How to inject dependencies into custom FilterAttributes?
I Have a custom HandleErrorAttribute
that extends FilterAttribute
.
How can I have Unity inject dependencies into this attribute at the same time that it injects the controller's dependencies itself?
Ok, figured it out.
Mostly I used Ben's solution above from the blog post he pointed to.
The problem is that Unity behaves a little differently.
You can't inject dependencies on the filters directly, because they are of type IActionFilter and IExceptionFilter respectively. This led me to believe they were readonly, which isn't so. It's just that Unity needs to know the explicit type in order to inject.
So, in the overridden method provided by the article, Unity users need to query the filters for the types in question, and then build them up.
public UnityActionInvoker(IUnityContainer container, IList<Type> typesToInject)
{
_container = container;
_typesToInject = typesToInject;
}
And then in the overridden method, do something like this:
var needsInjection = filters.Where(filter => typesToInject.Contains(filter.GetType()));
A bit messy, but it only needs to be done once, and keeps everything decoupled as Ben suggests.
The other gotcha is that you can't call _container.BuildUp(filter) inside a foreach loop, because the filter is readonly in that context.
You have two options
The first option is to write a custom ActionInvoker, which isn't nearly as hard as it sounds. Check out this blog post. It specifically deals with NInject, but Unity supports property injection so you can modify the example to use Unity.
This is the option that couples your IoC Container and isn't recommended.
public class MyFilter
{
IMyService MyService {get; set;}
MyFilter() : MyFilter(MyUnityContainer.Resolve<IMyService>())
{ }
MyFilter(IMyService service)
{
MyService = service;
}
}
I too came across this problem and now have a working solution. It is similar to the solution described above but with some slight differences and also with the full Unity code added.
First I will be using property injection for the reason described above and, as above, I will be using the BuildUp method on Unity to inject the properties into the already created Filters.
To do this I have all of my Controllers inherit from a new custom base class. On that base class I override the CreateActionInvoker method in order to set my own custom ActionInvoker.
Protected Overrides Function CreateActionInvoker() As System.Web.Mvc.IActionInvoker
Return CustomActionInvoker
End Function
Then in my CustomActionInvoker I override the GetFilters method.
Protected Overrides Function GetFilters(ByVal controllerContext As ControllerContext, ByVal actionDescriptor As ActionDescriptor) As FilterInfo
Dim info = MyBase.GetFilters(controllerContext, actionDescriptor)
For Each MyAuthorizationFilter In info.AuthorizationFilters
MvcApplication.Container.BuildUp(MyAuthorizationFilter.GetType, MyAuthorizationFilter)
Next
For Each MyActionFilter In info.ActionFilters
MvcApplication.Container.BuildUp(MyActionFilter.GetType, MyActionFilter)
Next
For Each MyResultFilter In info.ResultFilters
MvcApplication.Container.BuildUp(MyResultFilter.GetType, MyResultFilter)
Next
For Each MyExceptionFilter In info.ExceptionFilters
MvcApplication.Container.BuildUp(MyExceptionFilter.GetType, MyExceptionFilter)
Next
Return info
End Function
Contrary to what is said above I did not find that doing the buildup inside a For Each loop caused any problems. I also overcame the original problem of only having the object referenced via an interface by using one of the other overloads of the BuildUp method which takes a System.Type as well as the existing object.
With all of the above done I can now inject dependencies straight into my Filters.
Any comments and thoughts very much appreciated.
Cheers Mike
链接地址: http://www.djcxy.com/p/42738.html上一篇: 实施OpenID:识别用户