- Notifications
You must be signed in to change notification settings - Fork 586
Enable using a Cookie Session Store from DI #1719
Conversation
Tratcher left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to need tests.
| ? _diSessionStore ?? Options.SessionStore | ||
| : Options.SessionStore; | ||
| | ||
| public CookieAuthenticationHandler(IOptionsMonitor<CookieAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, ITicketStore diSessionStore = default) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No API signature changes are allowed in 2.1. You'll have to add a new constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pakrym does DI support optional parameters like this? We don't usually use them. We tend to use IEnumerable<T> for optional services.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does, usually, we use multiple constructors to achieve optional args. Usage of IEnumerable optional services is generally discouraged.
| public MemoryCacheTicketStore(IMemoryCache cache) | ||
| { | ||
| _cache = new MemoryCache(new MemoryCacheOptions()); | ||
| _cache = cache ?? new MemoryCache(new MemoryCacheOptions()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this ctor gets injected into cache would never be null.
| Did we ever put |
| We never did put it in DI though users might have. There's also the issue of having multiple cookie middleware, they don't all necessarily want the same store. The option may still be redundant though, it may be sufficient to prefer the instance on Options over the instance from DI. |
| Do we really need this functionality at all? You can already use a custom IConfigureNamedOptions that gets ITicketStore from DI and use that to set the instance... public class CookieConfig : IConfigureNamedOptions<CookieAuthenticationOptions> { public CookieConfig(ITicketStore store) => _store = store; public void Configure(string name, CookieAuthenticationOptions o) { o.TicketStore = store; } } services.AddTransient<IConfigureOptions<CookieAuthenticationOptions>, CookieConfig>(); |
| That seems good enough to me |
| Defining your own class and registering that in DI is more work and less discoverable than just registering the ITokenStore in DI. Though if you also have to set an option then the discoverability suffers there too. |
| File a doc bug to add that example to https://docs.microsoft.com/en-us/aspnet/core/security/authentication/cookie?tabs=aspnetcore2x ? |
| That's just the general pattern of how to get things from DI onto options, its not particularly specific to cookies, @scottaddie @Rick-Anderson I think @Tratcher has a good point that we should have an explicit section recommending this pattern of how to configure options instances with things from DI in this doc maybe? https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options public class UseSomethingFromDI : IConfigureNamedOptions/IConfigureOptions<YourOptions> { public CookieConfig(ISomethingFromDI thing) => _thing = thing; public void Configure([string name,] YourOptions o) { o.Thing = thing; } } services.AddTransient<IConfigureOptions<YourOptions>, UseSomethingFromDI>(); |
| Also Its certainly more work in the long run if we adopted something like this everywhere (useXyzFromDI flags on all services?), instead of just always using the options instance, and relying on configuring the options instance appropriately. |
| dotnet/AspNetCore.Docs#5922 Add doc section - Enable using a Cookie Session Store from DI |
| Instead of a |
| I still say we should do nothing special here, since this already can be done via options already |
| EventsType was added before named options was fully baked, I don't think we'd have added that either since you can accomplish that via a custom named IConfigureOptions as well |
| So this is actually even easier in 2.1:
|
No, it was added because there was a need for scoped "services as options", that you can't do with options, where everything is a singleton. |
| Ah right events are recreated per request, but that's not what ticket store needs here |
| If the ticket stored uses EF Core, it needs to be scoped, since |
| You probably can make a particular options type transient for an IOptionsMonitor by plugging in a no-op cache: https://github.com/aspnet/Options/blob/dev/src/Microsoft.Extensions.Options/IOptionsMonitorCache.cs |
Heh, that means the entire options and all the "services" attached are re-created per request, including the The real question is: is using scoped ticket stores common enough to introduce DI support? |
| Closing because we are not planning to add direct support for this feature. To work around this, you can use the service located pattern to get the required services imperatively instead of through typical DI. |
A
CookieAuthenticationHandlerwill use aITicketStorefrom DI if and only if the following conditions are met:UseSessionStoreFromDIproperty of the handler'sCookieAuthenticationOptionsistrue.ITicketStoreinterface, and the returned instance is non-null.Since
UseSessionStoreFromDIis a new property and new behaviour only is applied when its value istrue, these changes remain fully backwards compatible.Code Changes:
UseSessionStoreFromDItoMicrosoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions.Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandlerrequests anITicketStorein its constructor with an optional argument.Because the argument is optional, DI can provide the argument as
nullif noITicketStoreservice is registered. This will ensure backwards-compatability.CookieAuthenticationHandlerpreviously got theITicketStorefrom itsOptions.SessionStore, it now first checks the newOptions.UseSessionStoreFromDIproperty and uses the non-null DI-injectedITicketStoreinstance ifUseSessionStoreFromDIistrue.fixes #581