asp.net-coreasp.net-core-middlewareasp.net-core-8

Object as a Scoped Service, With Values being Set in Middleware, Sometimes Remains Null


I use the following to create an instance of a class for storing user information during the request:

services.AddScoped<IUserSettings, UserSettings>();

Then I use middleware to set the values of the userSettings.

public async Task InvokeAsync(HttpContext context, IUserSettings userSettings, IHttpClientFactory httpClientFactory)
{
    // Do some stuff here and set userSettings properties
}

The problem is when I send multiple requests in parallel, only one of them gets a non null userSettings.

Why does this happen and how can I fix it?

As of now I use httpContext.Items to store and use userSettings.


Solution

  • According to the document:

    To use scoped services in middleware, use one of the following approaches:

    So I suggest you could modify your middleware to use Factory-based middleware to see if we could solve this issue.

    More details, you could refer to below example:

    Usersettings:

    public interface IUserSettings
    {
        string UserId { get; set; }
        string UserName { get; set; }
      
    }
    
    // UserSettings.cs
    public class UserSettings : IUserSettings
    {
        public string UserId { get; set; }
        public string UserName { get; set; }
    }
    

    Usersettings middleware:

    public class UserSettingsMiddleware : IMiddleware
    {
        private readonly IUserSettings _userSettings;
    
        public UserSettingsMiddleware(IUserSettings userSettings)
        {
            _userSettings = userSettings;
        }
    
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            _userSettings.UserId = "123";
            _userSettings.UserName = "John Doe";
    
        
            await next(context);
        }
    }
    

    MiddlewareExtensions:

    public static class MiddlewareExtensions
    {
      
    
        public static IApplicationBuilder UseUserSettingsMiddleware(
            this IApplicationBuilder app)
            => app.UseMiddleware<UserSettingsMiddleware>();
    }
    

    Register inside the program.cs:

    ...
    builder.Services.AddScoped<IUserSettings, UserSettings>();
    builder.Services.AddTransient<UserSettingsMiddleware>();
    ...
    
    app.UseUserSettingsMiddleware();
    

    Result: enter image description here