中间件和 Blazor 组件的范围

MBi*_*irk 8 asp.net dependency-injection owin-middleware blazor blazor-server-side

我正在开发服务器端 Blazor 应用程序,并遇到了有关范围服务的一些问题。为了简单起见,我使用默认的 Blazor 模板(带有计数器的模板)重新创建了我的问题。

我有一个服务“CounterService”,它将计数器初始化为 1 并公开该计数器以及递增它的方法。非常基本:

public class CounterService
    {
        public int Counter { get; private set; }

        public CounterService()
        {
            Counter = 1;
        }

        public void IncrementCounter()
        {
            Counter++;
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后,我在 Startup.cs 中将此计数器注册为范围服务:`services.AddScoped()

然后我有一个自定义 ASP.NET 中间件,在本例中为“CounterInitializerMiddleware”。

public class CounterInitializerMiddleware
    {

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

        public RequestDelegate _next { get; }

        public async Task Invoke(HttpContext context, CounterService counterService)
        {
            Console.WriteLine($"CounterInitializer invoked from request path: {context.Request.Path.Value}");
            counterService.IncrementCounter();
            counterService.IncrementCounter();
            await _next(context);
        }
    }

    public static class MiddlewareExtensions
    {
        public static IApplicationBuilder UseCounterInitializer(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<CounterInitializerMiddleware>();
        }
    }
Run Code Online (Sandbox Code Playgroud)

基本上,它是一个中间层,用于增加计数器,以便当我将服务注入到我的组件中时,它从 3 而不是 1 开始。我在 Startup.cs 的配置方法中注册它:`app.UseCounterInitializer();

当我启动应用程序时,此中间件层被调用 4 次(请注意,它的 RenderMode 设置为 ServerPreRendered): 在页面加载请求和 _blazor 请求时:

CounterInitializer invoked from request path: /counter
CounterInitializer invoked from request path: /_blazor/disconnect
CounterInitializer invoked from request path: /_blazor/negotiate
CounterInitializer invoked from request path: /_blazor
Run Code Online (Sandbox Code Playgroud)

范围服务已注入,一切看起来都很好。

然后,如果我有一个注入了 CounterService 的组件,那么范围似乎会变得混乱。如果我查看 OnInitialized 方法,就会发现该方法被调用了两次。一次在预渲染期间,一次在正常渲染期间。在预渲染执行时,CounterService 将 Counter 按预期设置为 3,因为它是通过 CounterInitializerMiddleware 进行的。但是,在渲染执行期间,CounterService 会重新生成。因此,正常渲染的范围和通过中间件的请求的范围似乎是不同的。我认为组件的范围将绑定到由中间件处理的“_blazor”-signalR 连接。

谁能弄清楚发生了什么事并帮助我了解如何完成我想做的事情?

最好的,马蒂亚斯

编辑:只是为了澄清。我真正的用例是完全不同的,反例只是展示问题的简化案例,并且更容易重现(我希望)。

小智 1

我遇到了同样的问题,需要一个快速的解决方法。

解决方法是从 HttpContext 获取服务,这是一种反模式,但总比没有好。

class YourClass
{
     private readonly SomeMiddlewareScopedService _service;
     public YourClass(SomeMiddlewareScopedServiceservice)
     {
          _service = service;
     }
}
Run Code Online (Sandbox Code Playgroud)

解决方法:

class YourClass
{
     private readonly SomeMiddlewareScopedService _service;
     public YourClass(IHttpContextAccessor contextAccessor)
     {
          _service= (SomeMiddlewareScopedService)contextAccessor.HttpContext.RequestServices.GetService(typeof(SomeMiddlewareScopedService));
     }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记添加到您的构建器中:

builder.Services.AddHttpContextAccessor();
Run Code Online (Sandbox Code Playgroud)