问题
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:
- Reference to the original implementation
- 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