2

我关注了这篇文章,除了依赖注入(部分)之外,一切都正常了。在我的项目中,我正在使用统一,我正在尝试创建一个自定义事务属性,其目的是在执行操作之前启动 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。

有什么建议么 ?

4

1 回答 1

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();

在我看来,一个更优雅的解决方案是使用Adapts的Decoraptor TransactionFilter,但上面的答案可能更容易理解。

于 2015-12-09T13:57:47.690 回答