Skip to main content
 首页 » 编程设计

c#之我可以让 WebApi 与 IoC Aspects/Interceptor 一起工作吗

2024年08月12日48jpfss

我有 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(); 
    } 
}