6

I've read a number of articles that point out how to do this, namely:

Stack overflow solution

Brad Wilsons excellent tutorial

These do appear to work well, however when I follow some of the guidelines from here

Securing your ASP.NET MVC 3 Application

I seem to come a cropper. The issue for me is when I add my AuthorizationAttribute as a GlobalFilter rather than just decorating a controller/action. Although the dependancy resolvers seem to be called and set my Public exposed [Dependancy] property when it actually comes to the part of the code where I am overriding the OnAuthorization() method of AuthorizeAttribute, my public [Dependency] attribute is null.

When I remove it from global filter and decorate a controller it seems to work.

I can post code if more information is required.

EDIT: To further expand on this here is some of my code:

global.asax.cs

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {                        
        // If I have this here the my [Dependency] attribute does not keep it's value
        // If I remove it and decorate the controller the [Dependency] attribute keeps it value
        filters.Add(new BasicAuthenticationAttribute());
        filters.Add(new HandleErrorAttribute());
    }

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

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

        // injection of services and data contexts
        var container = new UnityContainer();

        // injections for services
        RegisterUnityServices(container);

        // Filter provides to allow injection into attribute filters
        RegisterUnityFilters(container);

    }

    private void RegisterUnityServices(UnityContainer container)
    {
        container.RegisterType<IDataContext, CDAXDataContext>();

        container.RegisterType<IUploadService, UploadService>();
        container.RegisterType<IAuthenticationService, AuthenticationService>();

        // add more services here ...            
        DependencyResolver.SetResolver(new Models.UnityDependencyResolver(container));            
    }

    private void RegisterUnityFilters(UnityContainer container)
    {
        var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
        FilterProviders.Providers.Remove(oldProvider);

        var provider = new UnityFilterAttributeFilterProvider(container);
        FilterProviders.Providers.Add(provider);            
    }

My Unity classes taken from brad wilsons examples:

    public class UnityDependencyResolver : IDependencyResolver
{
    readonly IUnityContainer _container;

    public UnityDependencyResolver(IUnityContainer container)
    {
        this._container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return _container.ResolveAll(serviceType);
        }
        catch
        {
            return new List<object>();
        }
    }
}

And

    public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider 
{
    private IUnityContainer _container;

    public UnityFilterAttributeFilterProvider(IUnityContainer container)
    {
        _container = container;
    }

    public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(controllerContext, actionDescriptor);

        foreach (var filter in filters)
        {
            _container.BuildUp(filter.Instance);
        }

        return filters;
    }

    protected override IEnumerable<FilterAttribute> GetControllerAttributes(
                ControllerContext controllerContext,
                ActionDescriptor actionDescriptor)
    {

        var attributes = base.GetControllerAttributes(controllerContext,
                                                      actionDescriptor);
        foreach (var attribute in attributes)
        {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerable<FilterAttribute> GetActionAttributes(
                ControllerContext controllerContext,
                ActionDescriptor actionDescriptor)
    {

        var attributes = base.GetActionAttributes(controllerContext,
                                                  actionDescriptor);
        foreach (var attribute in attributes)
        {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}

And the basis of My BasicAuthenticationAttribute where I have the [Dependency] property that is being set but not maintaining the value when the OnAuthorization method is fired.

    public class BasicAuthenticationAttribute : AuthorizeAttribute
{
    [Dependency]
    public IAuthenticationService Authentication { get; set; }

    private void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus)
    {
        validationStatus = OnCacheAuthorization(new HttpContextWrapper(context));
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
       // code here that uses the Authentication attribute but it's null
    }
Community
  • 1
  • 1
dreza
  • 3,605
  • 7
  • 44
  • 55

1 Answers1

3

I think you need to call the DependencyResolver in the attribute class...Not sure if the [Dependency] attribute works here...so in the OnAuthorization method call IAuthenticationService authentication = DependencyResolver.Current.GetService<IAuthenticationService>();

Dharman
  • 30,962
  • 25
  • 85
  • 135
w4ik
  • 1,276
  • 2
  • 19
  • 33
  • No I didn't. I find it strange that it works if I decorate the controller but doesn't work if I put it in the global.ascx. I'll give your method a go but I was really hoping to implement it via DIP using Unity. At the moment it's working but the method explained in that I decorate the controller and not include it in the global file. – dreza Apr 20 '12 at 19:52
  • I found the same behavior, worked fine in the controller, but not in the attribute/filter...it's just not there, so I needed to call the DependencyResolver. Pretty interesting comment from http://stackoverflow.com/users/759701/ethan-cabiac "it is not about whether they are registered, it is about how they are instantiated. Essentially, the framework is calling new Authenticate() which bypasses any DI-Container" in this question http://stackoverflow.com/questions/6121050/mvc-3-unity-2-inject-dependencies-into-a-filter – w4ik Apr 20 '12 at 20:36