c# - 从 Autofac 函数工厂获取每个请求的依赖性

标签 c# asp.net-core autofac

我正在使用 ASP.NET Core 和 Autofac。几乎所有内容都按照生命周期范围(“每个请求”)注册。所以我的数据库上下文 DbContext在整个请求中是相同的实例。

但是我有一个单例,它也依赖于 DbContext .为了避免俘虏依赖,它被注入(inject)为 Func<Owned<DbContext>> , 这意味着一个新的 DbContext每次实例。

问题是我需要同一个实例,就像请求期间的其他地方一样,而不是新实例。

我想避免捕获依赖错误,但我也想要相同的实例。这可以通过标记或自定义注册实现吗?

最佳答案

根据评论,最不“架构”痛苦的方法可能是创建您自己的 Scoped<T>将从当前 HttpContext 解析 DbContext 的类

// Use an interface, so we don't have infrastructure dependencies in our domain
public interface IScoped<T> where T : class
{
    T Instance { get; }
}

// Register as singleton too.
public sealed class Scoped<T> : IScoped<T> where T : class
{
    private readonly IHttpContextAccessor contextAccessor;
    private HttpContext HttpContext { get; } => contextAccessor.HttpContext;

    public T Instance { get; } => HttpContext.RequestServices.GetService<T>();

    public Scoped(IHttpContextAccessor contextAccessor)
    {
        this.contextAccessor = contextAccessor ?? throw new ArgumentNullException(nameof(contextAccessor));
    }
}

注册为

// Microsoft.Extensions.DependencyInjection
services.AddSingleton(typeof(IScoped<>), typeof(Scoped<>);
// Autofac
containerBuilder.RegisterType(typeof(Scoped<>))
            .As(typeof(IScoped<>));

然后将其注入(inject)您的验证器服务。

public class CustomerValidator: AbstractValidator<Customer>
{
    private readonly IScoped<AppDbContext> scopedContext;
    protected AppDbContext DbContext { get } => scopedContext.Instance;

    public CustomValidator(IScoped<AppDbContext> scopedContext)
    {
        this.scopedContext = scopedContext ?? throw new ArgumentNullException(nameof(scopedContext));

        // Access DbContext via this.DbContext
    }
}

通过这种方式,您可以注入(inject)任何作用域服务而无需进一步注册。

附加说明

Autofac 被认为是“符合者”(请参阅​​ docs)DI 并与 ASP.NET Core 和 Microsoft.Extensions.DependencyInjection 很好地集成。

来自文档

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Add services to the collection.
    services.AddMvc();

    // Create the container builder.
    var builder = new ContainerBuilder();

    // Register dependencies, populate the services from
    // the collection, and build the container. If you want
    // to dispose of the container at the end of the app,
    // be sure to keep a reference to it as a property or field.
    builder.RegisterType<MyType>().As<IMyType>();
    builder.Populate(services);
    this.ApplicationContainer = builder.Build();

    // Create the IServiceProvider based on the container.
    return new AutofacServiceProvider(this.ApplicationContainer);
}

Startup 的默认用法有一些细微差别。类和 Microsoft.Extensions.DependencyInjection容器。

  1. ConfigureServices不是 void不再,它返回 IServiceProvider .这将告诉 ASP.NET Core 使用返回的提供程序而不是 DefaultServiceProvider来自 Microsoft.Extensions.DependencyInjection .
  2. 我们返回 Autofac 容器适配器:new AutofacServiceProvider(this.ApplicationContainer)这是根容器。

这对于让 ASP.NET Core 在 ASP.NET Core 中的任何地方使用容器很重要,即使在通过 HttpContext.RequestedServices 解析每个请求依赖项的中间件内部也是如此。 .

因此您不能使用 .InstancePerRequest()在 Autofac 中的生命周期,因为 Autofac 无法控制创建作用域,只有 ASP.NET Core 可以做到这一点。所以没有简单的方法让 ASP.NET Core 使用 Autofac 自己的 Request 生命周期。

相反,ASP.NET Core 将创建一个新范围(使用 IServiceScopeFactory.CreateScope())并使用 Autofac 的范围容器来解析每个请求的依赖关系。

关于c# - 从 Autofac 函数工厂获取每个请求的依赖性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44596611/

相关文章:

c# - Thread、Task 和 async/await 关键字之间的区别

c# - unity hold touch水平移动

wcf - .Net Core ReportExecutionServiceSoapClient 设置凭据

visual-studio - 如何使用 Visual Studio 2019 在 Docker 容器中运行 ASP.NET Core 3.1 项目?

asp.net - Autofac 与 MVC4 : controller does not have a default constructor

c# - 为什么在与 null 比较时转换为对象?

c# - 是否可以创建扩展方法来格式化字符串?

entity-framework - 未找到与命令 "dotnet-ef"匹配的可执行文件

asp.net-web-api - Hangfire、Autofac 和 WebApi

autofac - 仅给出字符串键是否可以从 Autofac 解析实例?