我使用的代码示例(使用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();
}
}
}
答案 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所述。