.NET Core中使用服务定位器时无法正确作用域化

4

我的代码的某些部分需要使用ServiceLocator,因为不支持构造函数注入。

我的启动类配置服务。我有一些是瞬态的,另一些是单例的,还有其他作用域。

例如:

services.AddScoped<IAppSession, AppSession>();
services.AddScoped<IAuthentication, Authentication>();
services.AddScoped<NotificationActionFilter>();

在我的服务定义结尾,我有以下一段代码块,用于设置服务定位器。
var serviceProvider = services.BuildServiceProvider();
DependencyResolver.Current = new DependencyResolver();
DependencyResolver.Current.ResolverFunc = (type) =>
{
    return serviceProvider.GetService(type);
};

我注意到在一个请求中,我从服务定位器中获取的实例与从构造函数注入中获取的实例不同。从服务定位器返回的实例似乎是单例的,并且不遵守作用域规则。 DependencyResolver 的代码如下:
public class DependencyResolver
{
    public static DependencyResolver Current { get; set; }

    public Func<Type, object> ResolverFunc { get; set; }

    public T GetService<T>()
    {
        return (T)ResolverFunc(typeof(T));
    }
}

我该怎么修复这个问题?

你不需要重新创建作用域,这就是为什么作用域服务不会遵守作用域的原因。此外,你有两个ServiceProvider - 这解释了为什么你会收到不同的实例。 - Alex Riabov
你能提供一个DependencyResolver的实现吗? - Alex Riabov
@AlexRiabov 我现在会添加完整的实现。 - Sam
1个回答

4

我建议创建一个中间件,将ServiceProvider设置为在其他地方使用的ServiceProvider:

public class DependencyResolverMiddleware
{
    private readonly RequestDelegate _next;

    public DependencyResolverMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        DependencyResolver.Current.ResolverFunc = (type) =>
        {
            return httpContext.RequestServices.GetService(type);
        };

        await _next(httpContext);
    }
}

此外,DependencyResolver 应该更新以支持这种行为:
public class DependencyResolver
{
    private static readonly AsyncLocal<Func<Type, object>> _resolverFunc = new AsyncLocal<Func<Type, object>>();

    public static DependencyResolver Current { get; set; }

    public Func<Type, object> ResolverFunc
    {
        get => _resolverFunc.Value;
        set => _resolverFunc.Value = value;
    }

    public T GetService<T>()
    {
        return (T)ResolverFunc(typeof(T));
    }
}

不要忘记在 Startup.cs 的 Configure 方法中进行注册:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    app.UseMiddleware<DependencyResolverMiddleware>();
}

这样做不行。在同时请求时设置解析器函数存在竞争条件。 - Sam
@Sam,你说得对,我已经更新了答案,所以这个问题不再是一个问题了。 - Alex Riabov
干得好,谢谢。另外,我之前没听说过AsyncLocal,很高兴学到了新东西。 - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接