Simple Injector - 如何注入类型为Func <t> </t>的属性

时间:2015-03-02 13:11:41

标签: c# asp.net-web-api2 simple-injector

我使用的代码示例(使用StructureMap for DI)在类中具有如下属性:

public Func<IUnitOfWork> UnitOfWorkFactory { get; set; }

在Simple Injector教程之后,我最终得到了以下代码,这些代码应该进行属性注入:

public class DependencyAttributeSelectionBehaviour : IPropertySelectionBehavior
{
    public bool SelectProperty(Type type, PropertyInfo prop)
    {
        return prop.GetCustomAttributes(typeof(Dependency)).Any();
    }
}

public class Dependency: Attribute
{
       // dummy class
}

Inside Global.asax

 var container = new Container();
 container.Options.PropertySelectionBehavior = new DependencyAttributeSelectionBehaviour();

然后我继续将该物业装饰为:

[Dependency]
public Func<IUnitOfWork> UnitOfWorkFactory { get; set; }

但是,在调用UnitOfWorkFactory()时,我仍然会得到一个null异常。

依赖关系和全局属性在Global.asax中初始化如下:

    // Create the container as usual.
    var container = new Container();
    container.Options.PropertySelectionBehavior = new DependencyAttributeSelectionBehaviour();

    // Register your types, for instance using the RegisterWebApiRequest
    // extension from the integration package:
    container.RegisterWebApiRequest<IUnitOfWork, NHibernateUnitOfWork>();
    container.RegisterSingle<ISessionSource, NHibernateSessionSource>();
    container.RegisterSingle<IAppSettings, AppSettings>();

    container.Register(() =>
    {
        var uow = (INHibernateUnitOfWork) (container.GetInstance<IUnitOfWork>());
        return uow.Session;
    });

    container.Register<IUserRepository, UserRepository>();

    // This is an extension method from the integration package.
    container.RegisterWebApiControllers(GlobalConfiguration.Configuration);

    container.Verify();

    GlobalConfiguration.Configuration.DependencyResolver =
        new SimpleInjectorWebApiDependencyResolver(container);

    GlobalConfiguration.Configuration.Filters.Add(new UnitOfWorkAttribute());

这是有道理的,因为属性注入不会神奇地定义我的函数属性的主体,但我不知道如何实现这一点。任何想法/提示都表示赞赏。

编辑:

    public class UnitOfWorkAttribute : ActionFilterAttribute
{
    [Dependency]
    private Func<IUnitOfWork> UnitOfWorkFactory { get; set; }

    public override void OnActionExecuting(HttpActionContext filterContext)
    {
        UnitOfWorkFactory().Begin();
    }

    // TODO: Fix this: We should also probably check if exception is handled
    public override void OnActionExecuted(HttpActionExecutedContext filterContext)
    {
        var uow = UnitOfWorkFactory();

        try
        {
            if (filterContext.Exception != null)
            {
                uow.Rollback();
            }
            else
            {
                uow.Commit();
            }
        }
        catch
        {
            uow.Rollback();
            throw;
        }
        finally
        {
            uow.Dispose();
        }
    }
}

1 个答案:

答案 0 :(得分:3)

你的问题开始变得有意义了。您正在尝试将工厂注入Web API过滤器属性的属性。属性总是由CLR创建;不是你的DI容器。这就是没有注入依赖性的原因。您可能已经知道Web API caches filter attributes indefinitely,使它们成为有效的单例,这意味着您不应该向它们注入除了单例之外的任何内容。这就解释了为什么要注射工厂;工厂可以是单身人士。

要实现这一点,您需要做两件事。首先,您需要将Func<IUnitOfWork>注册为单身,如下所示:

container.RegisterSingle<Func<IUnitOfWork>>(container.GetInstance<IUnitOfWork>);

您需要做的第二件事是创建一个允许将属性注入属性的自定义IFilterProvider

事实上,Simple Injector的Web API集成库包含一个扩展方法,该方法将自定义过滤器提供程序注册到执行此操作的Web API管道中。

虽然这种扩展方法可能听起来像答案;事实并非如此。这不是答案,因为这个扩展方法将在下一个次要版本(2.8)中标记为[Obsolete],它将在下一个主要版本(3.0)中从库中删除。这样做的原因是,很容易意外地将依赖项注入到不是单例的属性中,这会导致各种令人讨厌的并发问题。但由于容器无法创建属性,因此Simple Injector是盲目的,无法使用Diagnostic Services来解决此错误。

出于这个原因,我们决定在将来的版本中删除此功能。替代方案在Web API integration guide wiki page中解释。基本上,文档说您应该回退到服务定位器模式(通过调用DependencyResolver.Current.GetService)或使您的属性被动,如here所述。