Autofac - 如何从单例中解析 ISomething 的 Func,其中 ISomething 是 InstancePerHttpRequest [英] Autofac - how to resolve Func for ISomething from Singleton where ISomething is InstancePerHttpRequest

查看:21
本文介绍了Autofac - 如何从单例中解析 ISomething 的 Func,其中 ISomething 是 InstancePerHttpRequest的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Autofac 将依赖项注入 MVC 4 应用程序中的 FluentValidation.我想我已经制定了策略,但我一直在解决我的每个请求 ISomething 的问题.

I'm trying to use Autofac to inject dependencies into FluentValidation in an MVC 4 app. I think I've got the strategy worked out, but I'm getting stuck with resolving my per-request ISomething from a singleton.

场景如下:我有一个源自 FluentValidation 的 AbstractValidator 的验证器.我读过 FluentValidation 验证器作为单例执行得最好,所以我的构造函数需要一个 Func 并存储该工厂以供以后使用.当使用验证器时,它应该向存储工厂询问 IDataStore,获取为该请求创建的实例并使用它.这就是理论.我想感谢 https://github.com/robdmoore/UnobtrusiveMVCTechniques,它帮助我确定了这个解决方案.这是验证器...

Here's the scenario: I've got a validator that derives from FluentValidation's AbstractValidator. I've read that FluentValidation validators perform best as singletons, so my constructor expects a Func and stores that Factory for use later. When the validator is used, it should ask the stored factory for an IDataStore, get the instance created for that request and use it. That's the theory. I want to give credit to https://github.com/robdmoore/UnobtrusiveMVCTechniques, which helped me settle on this solution. Here's the validator...

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 技巧的方法.

If someone can point me to a working example of what I'm trying to accomplish, that would be great, but I'd also like to know the solution to this particular piece of Autofac tricksyness.

这是我的验证器注册...

Here's my validator registration...

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 工厂的注册...

Here's my registration for the IDataStore factory...

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.Register<Func<IDataStore>>(c => {
                                       var context = c.Resolve<IComponentContext>();
                                       return context.Resolve<IDataStore>;
                                   });

这是我的验证器在线请求 IDataStore 时遇到的错误 -var db = _dbFactory();

Here's the error I'm getting when my validator asks for an IDataStore on the line - var db = _dbFactory();

标签中没有与AutofacWebRequest"匹配的范围请求实例的范围.这通常表明正在请求注册为每个 HTTP 请求的组件一个 SingleInstance() 组件(或类似的场景.)在网络下集成总是从DependencyResolver.Current 或 ILifetimeScopeProvider.RequestLifetime,永远不会来自容器本身.

No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.

...这正是我在编写自己的 Factory 注册(Func 注册)之前尝试过的结果.通过阅读类似问题的各种答案,看起来我上面的内容应该可以工作,因为我认为我现在正在解析 Func 以获得当前的解析器.

...which is exactly what I got when I tried it prior to writing my own Factory registration - the Func registration. From reading various answers to similar questions, it looked like what I have above should work because I thought I was now resolving the Func to get the current resolver.

任何帮助将不胜感激.

推荐答案

我同意这应该可行 - Func 正在定义一个工厂,它将根据需要在每个方法中生成依赖项.

I agree that this should work - the Func<IDataStore> is defining a factory that will produce the dependency in each method as required.

我绕过这个方法的方法是使用 DependencyResolver.Current 就像错误消息所暗示的那样.主要原因是我已经使用 Autofac.Mvc4 nuget 包进行了设置...

The way that I got around this method is to use the DependencyResolver.Current like the error message suggests. The main reason is that I already had it set up using the Autofac.Mvc4 nuget package...

DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

所以要实际设置方法,我有以下功能

So to actually setup the method I have the following func

public Func<T> PerHttpSafeResolve<T>()
{
    return () => DependencyResolver.Current.GetService<T>();
} 

当构建容器时

builder.RegisterType<SuperDB>().As<IDataStore>().InstancePerHttpRequest();
builder.RegisterInstance(PerHttpSafeResolve<IDataStore>());

注册实例的第二行说 - 如果您需要 Func 然后使用传递给方法的值.PerHttpSafeResolve 的结果只是一个函数(工厂),因此它可以作为单个实例存在.

The second line that is registering the instance is saying - If you need a Func<IDataStore> then use the value passed into the method. The result of the PerHttpSafeResolve<IDataStore> is just a function (factory), so it can live as a single instance.

这篇关于Autofac - 如何从单例中解析 ISomething 的 Func,其中 ISomething 是 InstancePerHttpRequest的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆