Tuesday, December 16, 2008
Type Fidelity in WCF
Check out Evan's post on handling odd serialization problems in WCF. Old post, but well worth the read: Type fidelity across the wire in WCF.
Friday, December 12, 2008
SQL Session State, Response.Redirect() and HttpApplication.Dispose()
Our customer-facing ASP.NET web applications are load balanced, so of course we utilize SQL SessionState.
Thing is, SQL SessionState is much less forgiving than InProc session state. Everything you store must be marked with the Serializable attribute.
Problem is, the application has a funny way of telling you that you've forgotten that important attribute somewhere. Funny in that it doesn't throw an exception when it can't write the item to the session database.
See, the items you store in session during a Request are stored InProc until the ReleaseRequestState event is fired. At that time, the items you've stored in session are written to state. In the case of SQL Session State, this is when the stored procedure to write the data to the database is actually invoked.
In my case, I was storing a business entity in session, to be pulled right back out in the next request. Problem was, it was vanishing between the time it was written and the time the next Request came through, right after a Response.Redirect(). I was getting no exceptions, no indications at all as to what was happening.
After slamming my head against my desk for a couple of days, I found something that will now become a best practice. I call the Dispose() method on the ApplicationInstance of the current request. This manually calls the Dipose() method on each of the httpModules you have registered in your application - and somewhere in there the ReleaseRequestState event is raised. In doing this, I finally got the exception I was looking for - the entity that I was trying to store in session had a property of a type that was not marked Serializable. So I fixed it, and everything is working nicely.
Manually calling Dispose() right after a Response.Redirect() is a nice, clean way of freeing up resources and finishing the current Request in a tidy way. And it helps expose these little issues.
Thing is, SQL SessionState is much less forgiving than InProc session state. Everything you store must be marked with the Serializable attribute.
Problem is, the application has a funny way of telling you that you've forgotten that important attribute somewhere. Funny in that it doesn't throw an exception when it can't write the item to the session database.
See, the items you store in session during a Request are stored InProc until the ReleaseRequestState event is fired. At that time, the items you've stored in session are written to state. In the case of SQL Session State, this is when the stored procedure to write the data to the database is actually invoked.
In my case, I was storing a business entity in session, to be pulled right back out in the next request. Problem was, it was vanishing between the time it was written and the time the next Request came through, right after a Response.Redirect(). I was getting no exceptions, no indications at all as to what was happening.
After slamming my head against my desk for a couple of days, I found something that will now become a best practice. I call the Dispose() method on the ApplicationInstance of the current request. This manually calls the Dipose() method on each of the httpModules you have registered in your application - and somewhere in there the ReleaseRequestState event is raised. In doing this, I finally got the exception I was looking for - the entity that I was trying to store in session had a property of a type that was not marked Serializable. So I fixed it, and everything is working nicely.
Manually calling Dispose() right after a Response.Redirect() is a nice, clean way of freeing up resources and finishing the current Request in a tidy way. And it helps expose these little issues.
Tuesday, July 29, 2008
Authorization in Web Client Software Factory
This post details the default setup used by WCSF to authorize user requests. The reader is walked through a high-level description of how requests are authorized; additionally, customization points are described so that developers can be aware of where to correctly make modifications if a different authorization process is desired.
This post assumes that the reader has working knowledge of version 2.0 of the Web Client Software Factory.
1. Every request is run through the HandleAuthorization method in the WebClientAuthorizationModule. A delegate is specified that is hooked into the AuthorizeRequest event; this delegate calls the HandleAuthorization method.
2. The HandleAuthorization() method uses the AuthorizationRulesService to get all authorization rules associated with the request. That list is enumerated, and for each the AuthorizationService is used to check to make sure that the user is able to view the requested URL.
Question: Where do the concrete implementations of the IAuthorizationRulesService and IVirtualPathUtilityService get set?
Answer: in the AddRequiredServices() method of the WebClientApplication class.
If the developer wishes to change the specific implementations of these or any services defined in the AddRequiredServices() method, the developer may simply override the method and make the specified changes. Note however that this requires that the developer does one of the following:
A. Duplicate all of the code above and makes changes based on the specific implementations they want to use, OR
B. Call the base method and then use the RootContainer.Services.Remove() method to remove the ones to be replaced, and then use the AddServiceIfMissing(ICompositionContainer container) method to add the specific implementations needed.
3. The AuthorizationService calls the Authorize method on the AuthorizationProvider, passing the current principal and a string representing the URL of the request, to determine if the user is authorized.
Answer: a factory generates it based on configuration; the default configuration for WCSF applications is set for the AuthorizationRuleProvider.
CUSTOMIZATION POINT:
A different AuthorizationProvider can be specified in configuration. See the snippet from a typical WCSF web.config file. The highlighted section is where a different AuthorizationProvider can be specified. Be sure that the name specified in the “defaultAuthorizationInstance” is the same as the one that is specified under the “name” attribute for the new AuthorizationProvider configuration. While the specific rules do not have to be specified in configuration if another provider is used, all classes inheriting from AuthorizationProvider must provide for a constructor that takes a collection of rules as a parameter. In this case, the rules element can be simply left blank ().
4. The AuthorizationProvider compares the user and the rule, to see if the user has access.
For more on how WCSF showcases the ASP.NET security architecture, see this screencast. NOTE: screencast showcases ASP.NET version 2.0 architecture.
This post assumes that the reader has working knowledge of version 2.0 of the Web Client Software Factory.
1. Every request is run through the HandleAuthorization method in the WebClientAuthorizationModule. A delegate is specified that is hooked into the AuthorizeRequest event; this delegate calls the HandleAuthorization method.
public void Init(HttpApplication httpApplication)
{
EventHandler handler = null;
ICompositionContainer rootContainer = httpApplication.Application["__RootContainer__"] as ICompositionContainer;
if (rootContainer != null)
{
if (handler == null)
{
handler = delegate (object sender, EventArgs e) {
IHttpContext context = new HttpContext(httpApplication.Context);
this.HandleAuthorization(rootContainer, context);
};
}
httpApplication.AuthorizeRequest += handler;
}
}
2. The HandleAuthorization() method uses the AuthorizationRulesService to get all authorization rules associated with the request. That list is enumerated, and for each the AuthorizationService is used to check to make sure that the user is able to view the requested URL.
protected virtual void HandleAuthorization(ICompositionContainer rootContainer, IHttpContext context)Question: Where does the concrete implementation of the IAuthorizationService get set? Answer: in the ShellModuleInitializer. Developers are directed to set this to EnterpriseLibraryAuthorizationService.
{
if (!context.SkipAuthorization)
{
IAuthorizationRulesService service = rootContainer.Services.Get<IAuthorizationRulesService>();
IVirtualPathUtilityService service2 = rootContainer.Services.Get<IVirtualPathUtilityService>();
if (service != null)
{
string[] authorizationRules = service.GetAuthorizationRules(service2.ToAppRelative(context.Request.Path));
if ((authorizationRules != null) && (authorizationRules.Length != 0))
{
IAuthorizationService service3 = rootContainer.Services.Get<IAuthorizationService>(true);
foreach (string str in authorizationRules)
{
if (!service3.IsAuthorized(str))
{
throw new HttpException(0x193, Resources.UserDoesntHaveAccessToTheRequestedResource);
}
}
}
}
}
}
Question: Where do the concrete implementations of the IAuthorizationRulesService and IVirtualPathUtilityService get set?
Answer: in the AddRequiredServices() method of the WebClientApplication class.
protected virtual void AddRequiredServices()CUSTOMIZATION POINT:
{
AddServiceIfMissing<ModuleConfigurationLocatorService, IModuleConfigurationLocatorService>(this.RootContainer);
AddServiceIfMissing<VirtualPathUtilityService, IVirtualPathUtilityService>(this.RootContainer);
AddServiceIfMissing<AuthorizationRulesService, IAuthorizationRulesService>(this.RootContainer);
AddServiceIfMissing<SessionStateLocatorService, ISessionStateLocatorService>(this.RootContainer);
AddServiceIfMissing<HttpContextLocatorService, IHttpContextLocatorService>(this.RootContainer);
AddServiceIfMissing<ModuleLoaderService, IModuleLoaderService>(this.RootContainer);
AddServiceIfMissing<WebConfigModuleInfoStore, IModuleInfoStore>(this.RootContainer);
AddServiceIfMissing<WebModuleEnumerator, IModuleEnumerator>(this.RootContainer);
AddServiceIfMissing<ModuleContainerLocatorService, IModuleContainerLocatorService>(this.RootContainer);
}
If the developer wishes to change the specific implementations of these or any services defined in the AddRequiredServices() method, the developer may simply override the method and make the specified changes. Note however that this requires that the developer does one of the following:
A. Duplicate all of the code above and makes changes based on the specific implementations they want to use, OR
B. Call the base method and then use the RootContainer.Services.Remove() method to remove the ones to be replaced, and then use the AddServiceIfMissing(ICompositionContainer container) method to add the specific implementations needed.
3. The AuthorizationService calls the Authorize method on the AuthorizationProvider, passing the current principal and a string representing the URL of the request, to determine if the user is authorized.
public bool IsAuthorized(string context)Question: How does the concrete implementation of the authorizationProvider get set?
{
try
{
return this._authorizationProvider.Authorize(Thread.CurrentPrincipal, context);
}
catch (InvalidOperationException)
{
return true;
}
}
Answer: a factory generates it based on configuration; the default configuration for WCSF applications is set for the AuthorizationRuleProvider.
CUSTOMIZATION POINT:
A different AuthorizationProvider can be specified in configuration. See the snippet from a typical WCSF web.config file. The highlighted section is where a different AuthorizationProvider can be specified. Be sure that the name specified in the “defaultAuthorizationInstance” is the same as the one that is specified under the “name” attribute for the new AuthorizationProvider configuration. While the specific rules do not have to be specified in configuration if another provider is used, all classes inheriting from AuthorizationProvider must provide for a constructor that takes a collection of rules as a parameter. In this case, the rules element can be simply left blank ().
<securityConfiguration defaultAuthorizationInstance="RuleProvider" defaultSecurityCacheInstance="">
<authorizationProviders>
<add type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, Microsoft.Practices.EnterpriseLibrary.Security, Version=3.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" name="RuleProvider">
<rules>
<add expression="R:Approver" name="AllowApprovals"/>
<add expression="R:User" name="AllowAutocomplete"/>
<add expression="R:User" name="AllowCreateOrders"/>
<add expression="R:User" name="AllowBrowseOrders"/>
<add expression="R:User" name="AllowSearchCustomers"/>
</rules>
</add>
</authorizationProviders>
</securityConfiguration>
4. The AuthorizationProvider compares the user and the rule, to see if the user has access.
public override bool Authorize(IPrincipal principal, string ruleName)
{
if (principal == null)
{
throw new ArgumentNullException("principal");
}
if ((ruleName == null) (ruleName.Length == 0))
{
throw new ArgumentNullException("ruleName");
}
base.InstrumentationProvider.FireAuthorizationCheckPerformed(principal.Identity.Name, ruleName);
BooleanExpression parsedExpression = this.GetParsedExpression(ruleName);
if (parsedExpression == null)
{
throw new InvalidOperationException(string.Format(Resources.AuthorizationRuleNotFoundMsg, ruleName));
}
bool flag = parsedExpression.Evaluate(principal);
if (!flag)
{
base.InstrumentationProvider.FireAuthorizationCheckFailed(principal.Identity.Name, ruleName);
}
return flag;
}
For more on how WCSF showcases the ASP.NET security architecture, see this screencast. NOTE: screencast showcases ASP.NET version 2.0 architecture.
Monday, July 28, 2008
Career Advice: Keep a Journal
When I interviewed for my current job, it was incredibly difficult to remember everything I had done before. We all know how much we can potentially learn during the development process; if a project has been finished for months or years, it can be really hard to remember every obstacle bypassed, every challenge met.
About a year ago, I was walking through a Staples and found one of those grid-ruled college compositions books. I grabbed it and ever since I've been using it not only to keep notes on projects, but also keep copies (taped onto the pages) of important blog entries and articles I've found. It has been immensely helpful to remember vital solutions to recurring problems, and proved itself when I had to redo my resume for my latest job search.
Of course, then came Microsoft Office OneNote 2007. Same concept here, but in a convenient digital form.
If only I could afford that nifty Dell tablet...
Sunday, July 27, 2008
Simple Form Post Example
There's plenty of sites out there that offer services through form POST. Here's a really quick and dirty example of how to submit and receive:
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
namespace ClassLibrary1
{
public static class FormPostHelper
{
public static string FormPost()
{
string result = string.Empty;
//this sets up the request
Uri postUri = new Uri("http://www.domain.com/pagetopostto.htm");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUri);
//here you define the form fields
string xmlToPass = "FormField=Value";
byte[] bytes = Encoding.UTF8.GetBytes(xmlToPass);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = xmlToPass.Length;
//open a stream to the target URL
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
//submit the POST, get the response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
System.IO.StreamReader reader = new StreamReader(responseStream);
result = reader.ReadToEnd();
reader.Close();
}
return result;
}
}
}
Subscribe to:
Posts (Atom)