新范围内的服务就像瞬态服务

Services in new scope act like transient services

我有一个方法,我需要一个新的范围(必须是一个新的范围,这里的场景不需要它,但是当这个工作时,我会在其他需要单独范围的地方使用逻辑),为此我使用 IServiceScopeFactory(我认为这是正确的)。然后我从新的范围中获得我需要的服务,我希望它们仍然以范围内的方式工作。但是这些服务中的依赖关系就像瞬态服务一样。我总是在构造函数中得到一个新的。

示例:


public class EntryController : IEntryController
{
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly IRequestContext _requestContext;
    
    public EntryController(IServiceScopeFactory scopeFactory, IRequestContext requestContext)
    {
        _scopeFactory = scopeFactory;
        _requestContext = requestContext;
    }

    public async Task GetEntries(int userId)
    {
        using var scope = _scopeFactory.CreateScope();
        var requestContext = scope.ServiceProvider.GetRequiredService<IRequestContext>();
        var manager = scope.ServiceProvider.GetRequiredService<IEntryManager>();

        var test = requestContext // Completely new IRequestContext
        requestContext = _requestContext;
        var test1 = requestContext // test1 is the same as _requestContext, which is good

        return await manager.GetAll();
    }
}
public class EntryManager : IEntryManager
{
    private readonly IEntryResource _entryResource;
    private readonly IRequestContext _requestContext;

    public EntryManager (IEntryResource entryResource, IRequestContext requestContext)
    {
        _entryResource = entryResource;
        _requestContext = requestContext;
    }

    public async Task GetAll()
    {
        var test = _requestContext; // Completely new IRequestContext, which is bad
        return await _entryResource.GetAll();
    }
}
public class EntryResource : IEntryResource
{
    private readonly IRequestContext _requestContext;

    public EntryManager (IRequestContext requestContext)
    {
        _requestContext = requestContext;
    }

    public async Task GetAll()
    {
        var test = _requestContext; // Completely new IRequestContext, which is bad
        // here is some code for the db query where I need info stored in the IRequestContext
        return _dbContext.Entries.ToListAsync();
    }
}

我理解为什么我在新范围内获得一个新的 requestContext,但是当我更新值时,我希望这些值通过依赖注入在整个范围内可用。当我 运行 没有新范围的代码时,一切正常。所有服务都在启动时作为作用域服务添加。

services.AddScoped<IRequestContext, RequestContext>();
services.AddScoped<IEntryManager,EntryManager>();
services.AddScoped<IEntryResource, EntryResource>();

我发现了问题:

requestContext = _requestContext;

这没有用,因为 requestContext 不再是该行之前的同一个对象,并且它将不再与注入到范围内其他服务的对象相同。

如果我只是为其属性分配新值,它就可以工作。 这就是它起作用的原因:

requestContext.Id = _requestContext.Id

这样它仍然是同一个对象,Id 的新值可以在 requestContext.

的新范围内的任何地方检索到

使用自定义扩展我可以分配所有属性。

public static IRequestContext CopyRC(this IRequestContext dest, IRequestContext source)
{
    var props = typeof(RequestContext).GetProperties();
            
    foreach(var prop in props)
    {
        var value = prop.GetValue(source);
        prop.SetValue(dest, value);
    }
    return dest;
}

有了这个

requestContext = _requestContext;

现在变成了

requestContext.CopyRC(_requestContext);

感谢 Stephen Cleary 通过他的工作片段帮助我寻找正确的方向。