【问题标题】:How to Overcome Entity Framework Caching/Tracking Using MassTransit?如何使用 MassTransit 克服实体框架缓存/跟踪?
【发布时间】:2018-08-20 21:03:58
【问题描述】:

请原谅我的无知,但似乎 MassTransit 有效地对待单例和作用域依赖项相同。至少在实体框架 DbContext 的情况下,因此,UserManager 通过扩展方法 AddEntityFrameworkStores 注册。

这意味着任何加载了跟踪或以其他方式添加到上下文的实体都会在应用程序生命周期内缓存。反过来,这意味着在服务被回收之前,无法识别通过上下文之外的任何内容(例如临时脚本)对这些实体所做的更改。

是否有解决此限制的最佳做法?对于上下文,请考虑启动时的以下 sn-p:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddDbContextPool<SomeDbContext>(options =>
        options.UseSqlServer(configuration.GetConnectionString("SomeConnectionString")));

    services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<SomeDbContext>()
        .AddDefaultTokenProviders();

    // ...
}

还有以下消费者:

public class SomeConsumer : IConsumer<ISomeRequest>
{
    private readonly SomeDbContext _dbContext;
    private readonly UserManager<IdentityUser> _userManager;

    public SomeConsumer(SomeDbContext dbContext, UserManager<IdentityUser> userManager)
    {
        _dbContext = dbContext;
        _userManager = userManager;
    }

    public async Task Consume(ConsumeContext<ISomeRequest> context)
    {
        var identityUser1 = await _dbContext.Users.FindAsync(1);
        var identityUser2 = await _userManager.FindByIdAsync(1);

        var consumerHashCode = GetHashCode();
        var dbContextHashCode = _dbContext.GetHashCode();
        var userManagerHashCode = _userManager.GetHashCode();
        var identityUser1HashCode = identityUser1.GetHashCode();
        var identityUser2HashCode = identityUser2.GetHashCode();

        context.Respond(new SomeResponse());
    }
}

在上面的示例中,消费者(注册的瞬态)为每个请求提供不同的哈希码。尽管数据库上下文和用户管理器被注册为作用域,但所有其他人都提供相同的服务(建议相同的实例)。

万一重要的是,MassTransit 是从控制台应用程序而不是 Web 应用程序运行的。

【问题讨论】:

标签: dependency-injection .net-core rabbitmq entity-framework-core masstransit


【解决方案1】:

我被引导到 cmets 关于原始问题的答案,但我想我会为其他人发布详细信息。底线是我需要使用 MassTransit.Extensions.DependencyInjection 正确配置依赖注入(请参阅 http://masstransit-project.com/MassTransit/usage/containers/msdi.html)。

我已经开始走这条路,但在配置端点时错过了一个关键部分:e.LoadFrom(provider)。缺少那部分实际上将我的消费者变成了单身人士,无论他们实际上是如何配置的。

最后,我需要使用 AddDbContext 而不是 AddDbContextPool 来配置我的 DbContext。

这是实现这一点所需的最低限度的 sn-p:

    public void ConfigureServices(IServiceCollection services)
    {
        // ...

        services.AddDbContext<SomeDbContext>(options =>
            options.UseSqlServer(configuration.GetConnectionString("SomeConnectionString")));

        services.AddIdentity<IdentityUser, IdentityRole>()
            .AddEntityFrameworkStores<SomeDbContext>()
            .AddDefaultTokenProviders();

        // ...

        services.AddScoped<SomeConsumer>();

        services.AddMassTransit(x =>
        {
            x.AddConsumer<SomeConsumer>();
        });

        services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
        {
            var host = cfg.Host("localhost", "/", h => { });// However you want to get your host
            var queueName = "web-service-endpoint";
            cfg.ReceiveEndpoint(host, queueName, e => e.LoadFrom(provider));
        }));
    }

【讨论】:

  • 由于 LoadFrom 现已过时,您有没有它的工作示例吗?提前致谢!
  • 您需要验证这一点,但它似乎已更改为 e.Consumer&lt;SomeConsumer&gt;(provider);
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 2020-06-15
相关资源
最近更新 更多