Best/"cleanest" implementation for resolving in MVC authorize attribute and role provider?

Oct 16, 2012 at 9:49 AM

Hi,

in a previous discussion (https://simpleinjector.codeplex.com/discussions/399509) I said that I am relying on a singleton providing access to the SimpleInjector container.

This is because I am using custom MVC authorize attributes and a custom role provider which need to resolve certain dependencies: a logging-interface in the authorize-attribute and infrastructure-access for db-lookup in the role provider.

These types are registered on Application_Start.

Does anyone see a better way of implementing this than relying on a singleton?

Coordinator
Oct 16, 2012 at 10:11 AM

Since these attributes are specific to MVC, the least you can do is take a dependency on System.Web.Mvc.DependencyResolver.Current.GetService(), instead of taking a dependency on your own container or abstraction directly. The code in the attribute should do as little as possible, and direct the execution to the service that is returned from the DependencyResolver.

Using attributes that contain logic (especially attributes that have dependencies) is always sub-optimal. Attributes are created by the runtime and constructor injection doesn't work. Because of this many containers (including Simple Injector) allow you to do implicit property injection, but implicit property injection is suboptimal, because it doesn't allow the container to verify whether all dependencies are correctly registered.

Instead you could take a different approach. As I see it, most of the filter attributes you place on controllers and actions are business logic, and they don't belong to the controller. Instead, make the MVC layer as thin as possible and run these cross-cutting concerns between the controller and the business layer.

Take a look at this article. It describes a model where you give every use case in the system its own class and place a generic interface on them. This allows you to extend the behavior of these use cases with cross-cutting concerns such as logging, authorization, monitoring, validation, transactions etc. You can easily decorate them with a decorator that is application specific (such as a decorator that translates a business layer exception to an mvc authorization exception). Not only results this model in a very flexible and maintainable system, based on the SOLID principles; it is a model that works very well with the Simple Injector. Please take a look at the article and think about whether this model works in your situation.

Marked as answer by dot_NET_Junkie on 11/4/2013 at 2:03 AM
Oct 16, 2012 at 10:45 AM

The attribute is an AuthorizeAttribute, which is something I'd rather not move that implementation out of the context of the controller. The only thing I need to resolve is a custom logging-interface to allow logging of failed authorization attempts. (Effectively, the implementation of that interface writes to a TraceSource)

So I'm able to resolve this interface using System.Web.Mvc.DependencyResolver.Current.GetService().

But what about the custom role provider (inherited from System.Web.Security.RoleProvider) which I need to resolve custom user groups and authorization for them?

Coordinator
Oct 16, 2012 at 11:14 AM

For your custom role provider, you can as well call DependencyResolver.Current from within the role provider. However, this smells an awfully lot of the service locator anti-pattern. Instead, you can create an RoleProvider class that redirects all its calls to DependencyResolver.Current.GetService(typeof(RoleProvider)). When you do that, you can register your own RoleProvider and allow to usee constructor injection in it.

Another option is to use a framework such as Griffin.MvcContrib. which defines SOLID abstraction that you can implement easily instead of defining your own custom provider (or take an approach as this one).

Oct 16, 2012 at 1:31 PM

I'm not sure if relying on the DependencyResolver from the MVC namespace would work, when the role provider is independent of MVC (and used for web api as well).

Coordinator
Oct 16, 2012 at 1:49 PM

For Web Api you will need a different role provider, but the only thing that will do is forward the calls to System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver. If you find that this gives too much duplicated code, you could even create an abstract implementation where all methods forward calls to an protected abstract GetRoleProvider() method. In that case you will have an MvcRoleProvider, WebApiRoleProvider, WebFormsRoleProvider, that all each have just that method to implement.

Oct 16, 2012 at 2:30 PM

Seeing how both MVC and API controllers are part of the same web project, I don't really see how I could define a role provider for mvc and api separately (since the role provider is defined in the web.config).

Coordinator
Oct 16, 2012 at 3:22 PM
Edited Oct 16, 2012 at 3:24 PM

You should definately not mix MVC and Web API in the same project. A Web API is a web service. Neither would you mix MVC with a WCF project. If you do this, you'll find quickly that you will have a hard time configuring your DI container to make it work with the mix of MCV and Web API, since they almost certainly need different configurations. This problem is not Simple Injector specific; it is a container agnostic problem.

This doesn't mean that you can't define a simple HomeController on your Web API project that visualizes the API. This could work fine. However, separate your concerns and place an user driven web site in a different project than machine driven web service.

I experienced this myself a couple of weeks ago.

Oct 19, 2012 at 6:39 AM

I'm using  MVC Controllers to generate razor views which then access the data via RESTful Web API. I see nothing wrong with that :)

A few select special cases also require the use of a MVC controller. Both Web API and MVC share the same infrastructure and container configuration.

Coordinator
Oct 19, 2012 at 7:26 AM

I see. You use MVC controllers as a code generation mechanism. Just be warned :-)