Search code examples
c#asp.net-mvc-4autofacactionfilterattribute

Autofac attribute injection failing on attributes


I've found a few questions on this, but they tend to point to the exact documentation I'm following... but it's still not working.

I'm building a fairly simple ASP.NET MVC 4 site, and the plan is to use ActionFilterAttribute-based logging. I have a DataAccessProvider class which opens transactions with the database and provides unit-of-work instances, and I'm trying to inject it into the filter attribute.

The documentation says that it's enough to just call RegisterFilterProvider(), and ensure that the relevant types are registered. It specifically says that there is no need to register the attribute, but I've tried both with and without. My code currently looks something like this:

var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());

builder.Register(x => new EntityAccessProvider())
    .As<IDataAccessProvider>()
    .InstancePerHttpRequest();

builder.RegisterType<DebugLogAttribute>().PropertiesAutowired();
// ^ I've tried it with and without this line

builder.RegisterFilterProvider();
var container = builder.Build();

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

The example in the docs then just places a property on the filter, so I've done the same:

public class DebugLogAttribute : ActionFilterAttribute
{
    private IDataAccessProvider DataAccess { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext) { ... }
    public override void OnActionExecuted(ActionExecutedContext filterContext) { ... }
}

The docs say that's all is required - not even a constructor to inject into; it's done by property injection. When I run this code, however, The DataAccess property is always null; Autofac seems to ignore it. I know the registration works properly because it's correctly injecting EntityAccessProvider into my controllers, but it's not working for attributes. What am I missing?


Solution

  • Your property of type IDataAccessProvider has to be public for injection to work. You can still mark DebugLogAttribute, IDataAccessProvider and it's implementation as internal if you prefer.

    [DebugLogAttribute]
    public class HOmeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }
    
    internal class DebugLogAttribute : ActionFilterAttribute
    {
        public IDataAccessProvider DataAccess { get; set; }
    
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            Debugger.Break();
        }
    
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            Debugger.Break();
        }
    }
    
    internal interface IDataAccessProvider {}
    
    internal class DataAccessProvider:IDataAccessProvider {}