ASP.NET Core MVC Loading Session Asynchronously

痞子三分冷 提交于 2020-01-13 19:41:11

问题


I have been reading the official Session and application state documentation and have stumbled upon the following paragraph:

Loading Session asynchronously

The default session provider in ASP.NET Core loads the session record from the underlying IDistributedCache store asynchronously only if the ISession.LoadAsync method is explicitly called before the TryGetValue, Set, or Remove methods. If LoadAsync is not called first, the underlying session record is loaded synchronously, which could potentially impact the ability of the app to scale.

To have applications enforce this pattern, wrap the DistributedSessionStore and DistributedSession implementations with versions that throw an exception if the LoadAsync method is not called before TryGetValue, Set, or Remove. Register the wrapped versions in the services container.

The wrapping itself is not an issue for me, but in order to implement it, I need:

  1. Reference to the original implementation
  2. Registering the wrapped version

Currently, I have created the following wrapper class:

public class WrappedDistributedSession : ISession
  {
    private DistributedSession _service;
    private bool loaded = false;

    public WrappedDistributedSession(DistributedSession service)
    {
      _service = service;
    }

    public bool IsAvailable => _service.IsAvailable;

    public string Id => _service.Id;

    public IEnumerable<string> Keys => _service.Keys;

    public void Clear() => _service.Clear();

    public Task CommitAsync() => _service.CommitAsync();

    public Task LoadAsync()
    {
      loaded = true;
      return _service.LoadAsync();
    }

    public void Remove(string key)
    {
      if(loaded)
      {
        _service.Remove(key);
      } else
      {
        throw new Exception();
      }
    }

    public void Set(string key, byte[] value)
    {
      if (loaded)
      {
        _service.Set(key, value);
      }
      else
      {
        throw new Exception();
      }
    }

    public bool TryGetValue(string key, out byte[] value)
    {
      if (loaded)
      {
        return _service.TryGetValue(key, out value);
      }
      else
      {
        throw new Exception();
      }
    }
  }

And I have registered it in the Startup.ConfigureServices

services.AddScoped<ISession, WrappedDistributedSession>();

Obviously, since I am writing this question, my solution does not work. Where did I go wrong and how does one "Register the wrapped versions in the services container"?


回答1:


It seems you need to implement ISessonStore too (which is actually mentioned in the documentation you quoted), as it's the only one registered in AddSession extension method.

public static IServiceCollection AddSession(this IServiceCollection services)
{
    if (services == null)
    {
        throw new ArgumentNullException(nameof(services));
    }

    services.AddTransient<ISessionStore, DistributedSessionStore>();
    services.AddDataProtection();
    return services;
}

ISessionStore (and hence DistributedSessionStore) has a Create (see source) method which returns ISession. Here you need to return your custom implementation.

https://github.com/aspnet/Session/blob/rel/1.1.0/src/Microsoft.AspNetCore.Session/SessionServiceCollectionExtensions.cs#L27-L29

Then you can add before AddSession with

services.AddTransient<ISessionStore, AsyncDistributedSessionStore>();


来源:https://stackoverflow.com/questions/43201763/asp-net-core-mvc-loading-session-asynchronously

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!