.net 新作用域中的服务类似于 transient 服务

bwitn5fc  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(156)

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

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>();
ru9i0ody

ru9i0ody1#

我发现了问题:

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用他的工作片段帮助我寻找正确的方向。

相关问题