我试图使用autofacc注入依赖到一个MVC 4应用程序中的FluentValidation。我想我已经制定了策略,但我被卡在解决我的每请求issomething从一个单例。
场景如下:我有一个派生自FluentValidation的AbstractValidator的验证器。我读到过FluentValidation验证器作为单例执行得最好,所以我的构造函数需要一个Func并存储该Factory以供以后使用。当使用验证器时,它应该向存储工厂请求IDataStore,获取为该请求创建的实例并使用它。这就是理论。我要感谢https://github.com/robdmoore/UnobtrusiveMVCTechniques,它帮助我找到了这个解决方案。这是验证器…
public class SiteAdminViewModelValidator : AbstractValidator<SiteAdminViewModel> {
private readonly Func<IDataStore> _dbFactory;
public SiteAdminViewModelValidator(Func<IDataStore> dbFactory) {
_dbFactory = dbFactory;
RuleFor(model => model.SiteCode).Length(1, 40).Must(BeSpecial);
}
public bool BeSpecial(string siteCode) {
var db = _dbFactory();
List<Stuff> stuffs = db.All<Stuff>().ToList();
return true;
}
}
如果有人能给我指一个我正在努力完成的工作示例,那就太好了,但我也想知道解决autofacc这个特殊问题的方法。
这是我的验证器注册…
public class FluentValidatorModule : Module {
protected override void Load(ContainerBuilder builder) {
base.Load(builder);
builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();
var validators = AssemblyScanner.FindValidatorsInAssembly(System.Reflection.Assembly.GetExecutingAssembly());
validators.ToList().ForEach(v => builder.RegisterType(v.ValidatorType).As(v.InterfaceType).SingleInstance());
}
}
这是我注册的IDataStore工厂…
builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.Register<Func<IDataStore>>(c => {
var context = c.Resolve<IComponentContext>();
return context.Resolve<IDataStore>;
});
这是我得到的错误,当我的验证器要求一个IDataStore在线-var db = _dbFactory();
标签匹配'AutofacWebRequest'的作用域在请求实例所在的范围。这通常表明一个按http请求注册的组件正在被请求SingleInstance()组件(或类似的场景)。在网上集成总是从DependencyResolver。当前或ILifetimeScopeProvider。RequestLifetime,
…这正是我在编写自己的工厂注册- Func注册之前尝试时得到的结果。从阅读对类似问题的各种答案来看,看起来我上面的内容应该可以工作,因为我认为我现在正在解析Func以获得当前解析器。
我同意这应该工作- Func<IDataStore>
定义了一个工厂,将根据需要在每个方法中产生依赖项。
我绕过这个方法的方法是使用DependencyResolver.Current
,如错误消息所建议的。主要原因是我已经用Autofac设置好了。Mvc4 nuget包…
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
要设置这个方法,我输入下面的func
public Func<T> PerHttpSafeResolve<T>()
{
return () => DependencyResolver.Current.GetService<T>();
}
构造容器
时builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.RegisterInstance(PerHttpSafeResolve<IDataStore>());
编辑:注册实例的第二行是说-如果你需要一个Func<IDataStore>
,然后使用传递到方法的值。PerHttpSafeResolve<IDataStore>
的结果只是一个函数(工厂),因此它可以作为单个实例存在。
问题在于验证器的作用域。autofacc总是从应用程序容器中解析SingleInstance
依赖项,这意味着验证器的依赖项也来自应用程序容器。
Func<IDataStore>
实例,而不是从请求容器。当您解析IComponentContext
时,您将获得验证器被解析的容器:应用程序容器。由于Func<IDataStore>
的作用域是一个请求,autofacc无法在应用程序级别提供它,因此出现了错误。
正确的方法是将验证器注册为InstancePerHttpRequest
。组件的生命周期由其最长的依赖项决定;当验证器没有依赖关系时,它们作为单例器工作得最好。但是,在这种情况下,依赖于IDataStore
的验证器被限制最多只能存活IDataStore
实例的生命周期。(好的一面是,你可以摆脱Func
。)
把它想象成去参加一个聚会:如果你搭了主人的车,你必须呆在那里直到聚会结束。如果你想早点离开,你就不能和主人一起坐车。