【问题标题】:Custom action filter unity dependency injection web api 2自定义操作过滤器统一依赖注入 web api 2
【发布时间】:2015-12-09 11:34:44
【问题描述】:

我遵循了这个article 并得到了除了依赖注入(部分)之外的一切工作。在我的项目中,我使用的是统一,我正在尝试创建一个自定义 Transaction 属性,其目的是在执行操作之前启动 NHibernate 事务并在方法执行之后提交/回滚事务。

这是我的属性的定义:-

public class TransactionAttribute : Attribute
{
}

下面是我的 TransactionFilter 的定义

public class TransactionFilter : IActionFilter 
{
   private readonly IUnitOfWork _unitOfWork;

   public TransactionFilter(IUnitOfWork uow) {
      _unitOfWork = uow;
   }

   public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation) {
      var transAttribute = actionContext.ActionDescriptor.GetCustomAttributes<TransactionAttribute>().SingleOrDefault();
      if (transAttribute == null) {
         return continuation();
      }

      var transaction = uow.BeginTransaction();
      return continuation().ContinueWith(t => 
      {
         try{
            transaction.Commit();
            return t.Result;
         }
         catch(Exception e)
         {
             transaction.Rollback();
             return new ExceptionResult(ex, actionContext.ControllerContext.Controller as ApiController).ExecuteAsync(cancellationToken).Result;
         }
      }
   }
}

我已经创建了一个自定义过滤器提供程序,它使用统一来构建这个过滤器。

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)
        {
            foreach (IActionFilter actionFilter in container.ResolveAll<IActionFilter>())
            {
                // TODO: Determine correct FilterScope
                yield return new FilterInfo(actionFilter, FilterScope.Global);
            }
        }
    }

我在UnityWebApiActivator中注册了UnityActionFilterProvider(我用的是Unity.AspNet.WebApi包)如下

public static void Start() 
        {
            var container = UnityConfig.GetConfiguredContainer();
            var resolver = new UnityDependencyResolver(container);
            var config = GlobalConfiguration.Configuration;
            config.DependencyResolver = resolver;

            var providers = config.Services.GetFilterProviders();
            var defaultProvider = providers.Single(i => i is ActionDescriptorFilterProvider);
            config.Services.Remove(typeof(IFilterProvider), defaultProvider);
            config.Services.Add(typeof(IFilterProvider), new UnityActionFilterProvider(container));
        }

问题是对于任何操作的第一次请求一切正常,但对同一操作的后续请求不会重新创建 TransactionFilter,这意味着它不会调用构造函数来分配新的 UOW。我不认为我可以禁用动作过滤器缓存。

我现在唯一的选择是使用服务定位器模式并使用 ExecuteActionFilterAsync 中的容器获取 UOW 实例,我认为这会扼杀这个目的,我最好实现自定义 ActionFilterAttribute。

有什么建议吗?

【问题讨论】:

  • repository 是什么? uow不使用为什么还要注入?
  • 抱歉,打错了。存储库应该是 uow。我已经在原始代码中更正了。谢谢

标签: nhibernate asp.net-web-api2 custom-action-filter


【解决方案1】:

据我多年来所知,Web 应用程序启动代码中发生的事情本质上具有 Singleton 生命周期。该代码只运行一次。

这意味着每个过滤器只有一个实例。这对性能有好处,但不适合您的场景。

该问题的最简单解决方案是注入一个抽象工厂而不是依赖项本身:

public class TransactionFilter : IActionFilter 
{
   private readonly IFactory<IUnitOfWork> _unitOfWorkFactory;

   public TransactionFilter(IFactory<IUnitOfWork> uowFactory) {
      _unitOfWorkFactory = uowFactory;
   }

   // etc...

然后在ExecuteActionFilterAsync方法中使用工厂:

var transaction = _unitOfWorkFactory.Create().BeginTransaction();

在我看来,更优雅的解决方案是使用适应 TransactionFilterDecoraptor,但上述答案可能更容易理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    相关资源
    最近更新 更多