Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET MVC3 Forms Authentication

0.00/5 (No votes)
28 Aug 2011 3  
In this article, I want to change the default ASP.NET MVC Forms Authentication code to reflect my thoughts on how the code should be organized.

Motivation

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.

Analysis

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 in AspNetSqlMembershipProvider which is the realization of Microsoft’s Provider pattern, so the Domain is actually hiding behind the scenes. What are ChangePasswordModel, LogOnModel, 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. ChangePasswordModel, LogOnModel, 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.

Change

The below steps are used to change the default application to a different architecture.

Step 1: Create View Models

Like I mentioned above, ChangePasswordModel, LogOnModel, and RegisterModel are actually View Models from my perspective. So, I created a ViewModels folder in the default project and created ChangePasswordViewModel, LogOnViewModel, and RegisterViewModel in it. All the places that used ChangePasswordModel, LogOnModel, and RegisterModel originally are refactored to use ChangePasswordViewModel, LogOnViewModel, and RegisterViewModel.

Step 2: Create Utilities

There is an AccountValidation class in the default application that is used to convert MembershipCreateStatus 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 ServiceInterfaces folder 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 and FormAuthenticationService are moved into it. There is a problem. The AccountController creates AccountMembershipService 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.

LibraryFolder.gif

LibraryFolderContent.gif

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.

LibrarySolutionFolder.gif

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 IDependencyLocator in 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 has DependencyLocator to wrap up the IoC container. The FormsService property and MembershipService property will query the IoC container to get the instance object.

WebRegistryClass.gif

UnityDependencyLocatorClass.gif

The UnityDependencyLocator binds with WebRegistry in Global.asax.cs.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    RegisterUnityContainer();
}

private void RegisterUnityContainer()
{
    var container = new UnityContainer();
    UnityConfigurationSection section = (UnityConfigurationSection)
           ConfigurationManager.GetSection("unity");
    section.Configure(container);
    WebRegistry.DependencyLocator = new UnityDependencyLocator(container);
}

The dependency configuration is in the web.config:

<configSections>
    <section name="unity" 
      type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
            Microsoft.Practices.Unity.Configuration" />
</configSections>

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <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" />
    <container>
      <register type="IMembershipService" mapTo="MembershipService">
        <constructor />
      </register>
      <register type="IFormsAuthenticationService" mapTo="FormsAuthenticationService" />
    </container>
</unity>

The AccountController is changed to initialize the FormsService and MembershipService variables with WebRegistry.

protected override void Initialize(RequestContext requestContext)
{
    if (FormsService == null) { FormsService = WebRegistry.FormsService; }
    if (MembershipService == null) { MembershipService = WebRegistry.MembershipService; }

    base.Initialize(requestContext);
}

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.

Comparison

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:

SolutionBeforeChange.gif

After the change:

SolutionAfterChange.gif

Conclusion

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here