简单注入器 - 如何注入一个 属性 类型为 Func<T>

Simple Injector - How to inject a property with type Func<T>

我使用的代码示例(使用 StructureMap 进行 DI)在 class 中有一个 属性,如下所示:

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
}

里面Global.asax

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

然后我继续将 属性 装饰为:

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

但是当调用 UnitOfWorkFactory() 时我仍然得到一个空异常。

依赖项和全局属性在 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());

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

编辑:

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

你的问题开始有道理了。您正在尝试将工厂注入 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. Basically the documentation says that you should either fall back to the Service Locator pattern (by calling DependencyResolver.Current.GetService) or make your attributes passive, as explained here.

中解释了备选方案