我正在尝试使用Autofac将依赖项注入MVC 4应用程序中的FluentValidation。我想我的策略已经解决了,但是我已经陷入了从单身人士处理我的请求ISomething的问题。
以下是该方案: 我有一个派生自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;
}
}
如果有人可以指出我正在努力完成的工作示例,那就太棒了,但我也想知道这一特定Autofac诡计的解决方案。
这是我的验证员注册......
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.Current或ILifetimeScopeProvider.RequestLifetime, 从来没有从容器本身。
...这正是我在编写自己的工厂注册 - Func注册之前尝试的时候得到的。从阅读各种答案到类似的问题,看起来我上面应该工作,因为我以为我现在正在解决Func以获得当前的解析器。
非常感谢任何帮助。
答案 0 :(得分:18)
我同意这应该有效 - Func<IDataStore>
正在定义一个工厂,它将根据需要在每个方法中产生依赖关系。
我使用此方法的方法是使用DependencyResolver.Current
,如错误消息所示。主要原因是我已经使用Autofac.Mvc4 nuget包设置了它......
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
因此,为了实际设置方法,我有以下函数
public Func<T> PerHttpSafeResolve<T>()
{
return () => DependencyResolver.Current.GetService<T>();
}
构建容器时
builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.RegisterInstance(PerHttpSafeResolve<IDataStore>());
编辑:注册实例的第二行是 - 如果需要Func<IDataStore>
,则使用传递给方法的值。 PerHttpSafeResolve<IDataStore>
的结果只是一个函数(工厂),因此它可以作为单个实例存在。
答案 1 :(得分:9)
问题在于验证者的范围。 Autofac始终从应用程序容器中解析SingleInstance
依赖项,这意味着验证程序的依赖项也来自应用程序容器。
Autofac从那里请求Func<IDataStore>
实例,而不是请求容器。解析IComponentContext
时,您将获得正在解析验证程序的容器:应用程序容器。由于Func<IDataStore>
的范围是一个请求,因此Autofac无法在应用程序级别提供它,因此会出错。
正确的方法是将验证器注册为InstancePerHttpRequest
。组件的生命周期取决于其最长寿命的依赖性;验证者在没有依赖关系时最适合作为单身人士。但是,在这种情况下,依赖于IDataStore
的验证器被限制为最多只能存活IDataStore
实例的生命周期。 (好的一面是,你可以摆脱Func
。)
想想参加派对:如果你和主人搭车,你必须留在那里直到派对结束。如果你想早点离开,你不能和主人一起骑车。