I'm developing a little project to learn a few tools including ASP.NET MVC 2, NHibernate and Unity. The project is a simple web page to upload and search through documents of many different formats. One of the requirements I've made out for the system is having three different roles for users: “Uploader”, “Manager” and “Administrator”.
Now, ASP.NET MVC framework offers a very handy attribute called AuthorizeAttribute. Using it, you can allow some parts of the webpage to be viewable only for users in a specific role. All is well, but it uses ASP.NET role management under the hood. It requires a few additional tables in your database to be created and the actual data to be inserted to configure the roles. I was already using ASP.NET Membership to create secure logins for accounts, but it was only used to store passwords, nothing more. All the account information is stored in my own table called “Accounts
”. That’s where I wanted my role to be kept too. ASP.NET Roles require you to store the roles in a specific table though. To avoid needless complexity, I chose to create my own custom RoleProvider class, so I could modify the default behaviour to suit my needs.
RoleProvider
is an abstract
class, whose derivatives are used to manage roles in an application. Checking if a user is in a role belongs to that class also. I've considered implementing my own RoleProvider
a few times before, but I was overwhelmed by the number of methods we need to implement, so I went with the default behavior every time. That’s 11 methods and one property to implement.
Additionally, since I’m trying to use the best practices to develop this application and have been using Dependency Injection all over the place, implementing custom RoleProvider
brought in another problem: there’s no way I can pass dependencies to RoleProvider
implementation through a constructor, since that class is instantiated by ASP.NET implicitly, using settings in Web.Config.
Happily, both of these problems only seem tricky to solve. For the first one, implementing all the methods, it turned out that if I want to use AuthorizeAttribute
, I only need to implement one single method. That method is GetRolesForUser(..) and it does what its name tells. Now, to get the list of roles for an account in my system, I need that repository that can retrieve them from database. Since an account can be in one role at a time in my case, it simply needs to use an interface
I have, IAccountRepository
, to retrieve account by username
:
public override string[] GetRolesForUser(string username)
{
Account account = accountRepository.GetByUsername(username);
if(account != null)
return new string[]{ account.Role };
return new string[] { };
}
All is well, but we need to actually get an instance of some implementation of IAccountRepository interface
, since the project doesn’t reference any of them directly.
I’m using Unity IoC Container to create implementations of interface
s and fill any dependencies they might have in their constructors. Usually, the container is only used at the highest levels of your applications, like Global.asax in case of ASP.NET. But since there’s no way to inject anything into RoleProvider
classes, I decided to directly interfere with the container in my custom implementation’s Initialize
method. I created a UnityContainerFactory
class to get the container, so that no singletons are needed (I was convinced by some blogs that singleton should be considered an anti-pattern). The result looks like this:
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
IUnityContainer container = new UnityContainerFactory().Create();
accountRepository = container.Resolve<IAccountRepository>();
}
The UnityContainerFactory
class actually returns the same instance of IUnityContainer
that is being used by the custom IControllerFactory to create ASP.NET MVC controllers. It is effectively a Singleton, as in having one instance of a class per application, but not a singleton as in having a static
property that we use in every part of our application all over.
All in all, it turned out to be easier than I thought. All the other methods in my custom RoleProvider
implementation were left throwing NotImplementedExceptions
, but I don’t care about it yet, since these methods are not even used. The problem with inability to use the traditional Dependency Injection was solved quite easily too. Even though I don’t like the idea of directly calling the container, I had no other choice I believe. :)
CodeProject