I am developing a web app using MVC4 with Autofac. I have a global exception filter in which I'm injecting a logger service, so I'm initializing it in App_Start like this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(DependencyResolver.Current.GetService<IExceptionFilter>());
}
This is the general layout of the filter: public class ErrorHandlerAttribute : HandleErrorAttribute { private readonly ILoggerService logger;
public ErrorHandlerAttribute(ILoggerService logger)
{
this.logger = logger;
}
public override void OnException(ExceptionContext filterContext)
{
//dostuff
}
public void LogError(ExceptionContext context)
{
try
{
logger.Error(context.Exception.Message, context.Exception);
}
catch (Exception) { }
}
}
If I weren't using Autofac, I would've had something like this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new ErrorHandlerAttribute());
filters.Add(new ErrorHandlerAttribute
{
View = "UnauthorizedException",
ExceptionType = typeof(UnauthorizedAccessException)
});
filters.Add(new ErrorHandlerAttribute
{
View = "PageNotFound",
ExceptionType = typeof(NotImplementedException)
});
}
ErrorHandlerAttribute is my custom exception filter, derived from MVC's HandleErrorAttribute.
I would like to be able to keep the ability to redirect to custom error pages, while using Autofac's injection and a single filter (since I built it so it can handle any exception). Unfortunately, I can't seem to find any way to do this, despite scouring the web and other forums for possible solutions. I've tried a lot of configuration changes, different registrations, collection resolving etc.
The way I would like it to work would be similar to this:
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>().InstancePerHttpRequest();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
.WithProperties(new List<NamedParameter>() { new NamedParameter("ExceptionType", typeof(UnauthorizedAccessException)), new NamedParameter("View", "UnauthorizedAccess") })
.InstancePerHttpRequest();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
.WithProperties(new List<NamedParameter>() { new NamedParameter("ExceptionType", typeof(NotImplementedException)), new NamedParameter("View", "UnderConstruction") })
.InstancePerHttpRequest();
builder.RegisterFilterProvider();
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
DependencyResolver.Current.GetServices<IExceptionFilter>().ForEach(f => filters.Add(f));
}
Surprisingly, this compiles and runs, but all 3 IExceptionFilter instances are normal, defaulted ErrorHandlerAttribute (with View="Error" and ExceptionType=typeof(object)).
I am aware of the fact that Autofac takes the last registration of a service as default, and I have tried commenting two out of three registrations, as well as using PreserveExistingDefaults, still all my exception filters come with default values.
Have I misunderstood the WithProperties extension method or is there another similar way to implement what I want?
Edit 1:
Thanks for Alex's suggestion, I solved it by using NamedPropertyParameter and switching the order of the statements:
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
.WithProperties(new List<NamedPropertyParameter> { new NamedPropertyParameter("ExceptionType", typeof(UnauthorizedAccessException)), new NamedPropertyParameter("View", "UnauthorizedAccess") })
.InstancePerHttpRequest();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
.WithProperties(new List<NamedPropertyParameter> { new NamedPropertyParameter("ExceptionType", typeof(NotImplementedException)), new NamedPropertyParameter("View", "UnderConstruction") })
.InstancePerHttpRequest();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>().InstancePerHttpRequest();