Simple Injector-如何注入类型为Func<;T>;

本文关键字:Func gt lt 类型 Injector- 何注入 注入 Simple | 更新日期: 2024-09-22 09:31:37

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

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

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

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

Simple Injector-如何注入类型为Func<;T>;

您的问题开始有意义了。您正试图将工厂注入到Web API筛选器属性的属性中。属性始终由CLR创建;而不是通过DI容器。这就是为什么没有注入依赖项。您可能已经知道Web API无限期地缓存过滤器属性,使它们成为有效的单例,这意味着除了单例之外,您不应该向它们注入任何内容。这就解释了你为什么要给工厂注射;工厂可以是一个单独的工厂。

要让它发挥作用,你需要做两件事。首先,您需要将Func<IUnitOfWork>注册为singleton,如下所示:

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

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

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

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

出于这个原因,我们决定在未来的版本中删除此功能。替代方案在Web API集成指南维基页面中进行了说明。基本上,文档中说,您应该返回到ServiceLocator模式(通过调用DependencyResolver.Current.GetService),或者使您的属性变为被动属性,如下所述。