我有 WCF 背景,我成功地将 IoC 与方面/拦截器结合使用来抽象功能,例如身份验证和日志记录。我会简单地将所需的接口(interface)添加到方面构造函数,就像您使用任何典型的 IoC 设置一样。
我现在正尝试将相同类型的过程应用于 webapi,但由于 Controller 继承自 ApiController 并且不实现接口(interface)。我假设可能有不同的应用方面的方式?
public class MyController: ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
public LoginController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
// I WANT TO INTERCEPT THIS METHOD USING UserTokenAuthenticationInterceptor
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
看点
public class UserTokenAuthenticationInterceptor : IInterceptionBehavior
{
private readonly ILoginService _loginService;
private readonly ILog _log;
public UserTokenAuthenticationInterceptor(ILog log, ILoginService loginService)
{
this._log = log;
this._loginService = loginService;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
_log.Log(log entering authentication aspect);
// do some authentication here using this._loginService
_log.Log(log exiting authentication aspect);
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute { get { return true; }}
}
容器注册:
container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<ILoginService , LoginService>();
container.RegisterType<ILog, LogService>();
我在这个例子中使用了 unity。 谁能指出我正确的方向?
请您参考如下方法:
感谢大家的帮助,我终于弄明白了。
我从这篇文章中得到了大部分答案 https://unity.codeplex.com/discussions/446780
我使用了以下 nuget 包。
- Unity(我先加了这1个)
- Unity.WebApi(如果不先添加unity会有unity版本问题)
首先,我需要一个新的 IFilterProvider 实现。 它的工作是向容器注册所有 Action 过滤器。
public class UnityActionFilterProvider : ActionDescriptorFilterProvider, IFilterProvider
{
private readonly IUnityContainer container;
public UnityActionFilterProvider(IUnityContainer container)
{
this.container = container;
}
public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(configuration, actionDescriptor);
foreach (var filter in filters)
{
container.BuildUp(filter.Instance.GetType(), filter.Instance);
}
return filters;
}
}
然后需要一个注册方法,注册新的actionfilterprovider,去掉原来的webapi实现。 这需要在 Unity.WebApi nuget 包创建的 UnityConfig.cs 文件中的 RegisterComponents() 方法中执行。
public static void RegisterFilterProviders(IUnityContainer container)
{
var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();
GlobalConfiguration.Configuration.Services.Add(typeof(System.Web.Http.Filters.IFilterProvider),
new UnityActionFilterProvider(container));
var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);
GlobalConfiguration.Configuration.Services.Remove(typeof(System.Web.Http.Filters.IFilterProvider), defaultprovider);
}
在同一个 RegisterComponents() 方法中我注册了我的类型
container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<ILoginService , LoginService>();
container.RegisterType<ILog, LogService>();
接下来,我需要创建一个基于 AuthorizeAttribute 的类。
public class UserTokenAuthenticationAttribute : AuthorizeAttribute
{
private ILoginService _loginService;
// This is the magic part - Unity reads this attribute and sets injects the related property. This means no parameters are required in the constructor.
[Microsoft.Practices.Unity.Dependency]
public ILoginService LoginService
{
get
{
return this._loginService;
}
set
{
this._loginService = value;
}
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
// Authorise code goes here using injected this._loginService
}
}
还需要一个日志 Action 过滤器ActionFilterAttribute
public sealed class LogAttribute : ActionFilterAttribute
{
private ILog _log;
// This is the magic part - Unity reads this attribute and sets injects the related property. This means no parameters are required in the constructor.
[Microsoft.Practices.Unity.Dependency]
public ILog Log
{
get
{
return this._log;
}
set
{
this._log = value;
}
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
this._log.Info("Exited " + actionContext.Request.Method);
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
this._log.Info("Entering" + actionContext.Request.Method);
}
}
现在让我们配置 webapi Controller 。我们需要用我们的新属性来装饰这个类
[UserTokenAuthentication] // magic attribute in use
[Log] // magic attribute in use
public class MyController: ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
public MyController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
[System.Web.Http.AllowAnonymous] // doesnt require authentication as were not logged in yet
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
public HttpResponseMessage GetMyDetails(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
