Wednesday, November 23, 2011

ASP.NET MVC3 Forms Authentication


The default ASP.NET MVC Internet Application comes with forms authentication. It has all layers and classes in a single project. This is good for a simple and small application, but for an enterprise application, I would like to have a better architecture. So, I changed the default Internet Application to have more layers and put the layers in separate projects.


In order to re-architecture this default application, I need to use the DDD (Domain Driven Design) concept to find the domain and services first. Because the core functionality in this application is authenticating users with forms authentication, the domain is membership management. The membership management is actually implemented inAspNetSqlMembershipProvider which is the realization of Microsoft’s Provider pattern, so the Domain is actually hiding behind the scenes. What are ChangePasswordModelLogOnModel, and RegisterModel, you may ask? First of all, they are Models, but they are View Models instead of Domain Models, from my perspective. Domain model is the core of your application and should contain both the data and behavior to reflect the specific domain.ChangePasswordModelLogOnModel, and RegisterModel really just help move data from the View to the Domain and vice versa. After identifying the domain, I am able to decide what should stay in the default project and what should be moved to a different project to have a better separation of concern, reusability, and testability.


The below steps are used to change the default application to a different architecture.
Step 1: Create View Models
Like I mentioned above, ChangePasswordModelLogOnModel, and RegisterModel are actually View Models from my perspective. So, I created a ViewModels folder in the default project and createdChangePasswordViewModelLogOnViewModel, and RegisterViewModel in it. All the places that usedChangePasswordModelLogOnModel, and RegisterModel originally are refactored to useChangePasswordViewModelLogOnViewModel, and RegisterViewModel.
Step 2: Create Utilities
There is an AccountValidation class in the default application that is used to convertMembershipCreateStatus to a description for displaying in the view. I created a Utilities folder to contain it. This folder will contain all the common classes and helper classes. Therefore, ValidatePasswordLengthAttributes is moved into it also.
Step 3: Create Server Interfaces
The default application already has a good decoupling for Membership and Forms Authentication functions to allow switching implementation in different environments, like in Tests project, MockMembershipService is used instead of AspNetSqlMembershipProvider to allow testing logon, register, etc., functions without connecting to the membership repository. However, I like to only keep the service interface in the web project. A ServiceInterfacesfolder is created and IFormAuthenticationService and IMembershipService are moved into it.
Step 4: Create Security Project
From step 3, you will know I like the implementation to stay in a separate project (assembly) to better decouple them from the contract and the caller. The Demo.Web.Secruity project is created and AccountMembershipService andFormAuthenticationService are moved into it. There is a problem. The AccountController createsAccountMembershipService and FormAuthenticationSerrvice instances directly to provide for using in the controller actions. I don’t want to let the Web project reference the Security project and seeing the concrete classes because this ruins the separation of concern. This problem will be fixed in the following steps with Dependency Injection.
Step 5: Create Library
Before I can have Dependency Injection in place, I need to have some cornerstone first. The IoC container I use in here is Unity. It’s not the best IoC container on the market, but it has all the features I need, like lifetime management, configuration file, etc. I created a Library folder in the folder of the solution file and copied all the Unity assembly files into it.
In order to let the solution manage all the Unity files, I also created a Library solution folder and made references to all files in the Library folder.
Step 6: Create Base Project
For an enterprise application, there are always some utility and helper classes that need to be used in all projects. The Demo.Base project is created to contain those classes. So far, I only have one interface IDependencyLocatorin it that is implemented in the project that has a dependency injection access point.
Step 7: Create Dependency Injection
ASP.NET MVC3 has built-in Dependency Injection support (DependencyResolver), but I prefer to manage Dependency Injection via a Registry class. A WebRegistry class is created in the Web project. It hasDependencyLocator to wrap up the IoC container. The FormsService property and MembershipServiceproperty will query the IoC container to get the instance object.
The UnityDependencyLocator binds with WebRegistry in Global.asax.cs.
protected void Application_Start()



private void RegisterUnityContainer()
    var container = new UnityContainer();
    UnityConfigurationSection section = (UnityConfigurationSection)
    WebRegistry.DependencyLocator = new UnityDependencyLocator(container);
The dependency configuration is in the web.config:
    <section name="unity" 
            Microsoft.Practices.Unity.Configuration" />

<unity xmlns="">
    <alias alias="IMembershipService" 
      type="Demo.Web.ServiceInterfaces.IMembershipService, Demo.Web" />
    <alias alias="MembershipService" 
      type="Demo.Web.Security.AccountMembershipService, Demo.Web.Security" />
    <alias alias="IFormsAuthenticationService" 
      type="Demo.Web.ServiceInterfaces.IFormsAuthenticationService, Demo.Web" />
    <alias alias="FormsAuthenticationService" 
      type="Demo.Web.Security.FormsAuthenticationService, Demo.Web.Security" />
      <register type="IMembershipService" mapTo="MembershipService">
        <constructor />
      <register type="IFormsAuthenticationService" mapTo="FormsAuthenticationService" />
The AccountController is changed to initialize the FormsService and MembershipService variables withWebRegistry.
protected override void Initialize(RequestContext requestContext)
    if (FormsService == null) { FormsService = WebRegistry.FormsService; }
    if (MembershipService == null) { MembershipService = WebRegistry.MembershipService; }

One more thing needs to be done here, which is to add:
xcopy /Y /F "$(SolutionDir)Demo.Web.Security\$(OutDir)\
            "Demo.Web.Security.dll "$(SolutionDir)Demo.Web\bin"
in the Security project “Build Events -> Post-build event command line” to copy Demo.Web.Security.dll into the Web application’s bin folder because there is no direct reference between the Web project and the Security project. The IoC container needs the assembly file to bind the implementation to the interface.
Step 8: Clean up
Finally, I have all the pieces here, I just need to remove the original Models folder from the Web project and refactor the entire solution to replace the old classes with the new classes and layers.


After the change, the View, ViewModel, Controller, and Service interface are still in the Web project. The Model layer is in AspNetSqlMembershipProvider. The Service implementation is in the Security project.
Before the change:
After the change:


What I did in this article is just to reflect my thoughts on how a web application with Forms Authentication should be organized. There is no big innovation. It’s just a different idea on developing an application with ASP.NET MVC that has Forms Authentication for entitlement management.

Using the Code

The code is developed in Visual Studio 2010. SQL Server database aspnetdb is needed for membership that can be created with aspnet_regsql.exe.

No comments:

Post a Comment