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();
}
}
}
您的问题开始有意义了。您正试图将工厂注入到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
),或者使您的属性变为被动属性,如下所述。