diff --git a/CHANGELOG.md b/CHANGELOG.md index ff31284..edb9f86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changes in Medidata.MAuth +## v3.1.2 +- **[Core]** Fixed and enabled caching of the `ApplicationInfo` from the MAuth server. + ## v3.1.1 - **[Core]** Added `ConfigureAwait(false)` avoiding any possible deadlocks. diff --git a/README.md b/README.md index d626693..bdb53d7 100644 --- a/README.md +++ b/README.md @@ -303,14 +303,10 @@ is used as it wraps the original stream in a non-seekable version. ##### Does Medidata.MAuth support caching? -Yes, with the **.NET Framework** we support caching of the responses from the MAuth server in order to not overload it with client information -requests. The caching mechanism in Medidata.MAuth is based on the -[WebRequestHandler](https://msdn.microsoft.com/en-us/library/system.net.http.webrequesthandler(v=vs.110).aspx)'s -caching (with the request caching policy set to -[Default level](https://msdn.microsoft.com/en-us/library/system.net.cache.requestcachelevel(v=vs.110).aspx)), that -utilizes the -[Windows OS built-in WinINET caching](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383928(v=vs.85).aspx), -thus it respects all the HTTP-specific cache headers provided by the MAuth server. +Yes, all the **ASP.NET WebApi** handler and the **Owin** and **ASP.NET Core** middlewares support caching of the `ApplicationInfo` from the MAuth server in +order to not overload it with client information requests (and gradually improve the response times from the middlewares). +The cache expiration will be set according to the response cache header (max-age) from the MAuth server - or if this +information not provided, it will be **1 hour** by default for successful requests (i.e. valid application uuids). ##### The documentation for the `MAuthServiceRetryPolicy.Agressive` retry policy says that it is not recommended for production use. What is the reason for this? diff --git a/src/Medidata.MAuth.Core/MAuthAuthenticator.cs b/src/Medidata.MAuth.Core/MAuthAuthenticator.cs index c93ecc2..73c01f3 100644 --- a/src/Medidata.MAuth.Core/MAuthAuthenticator.cs +++ b/src/Medidata.MAuth.Core/MAuthAuthenticator.cs @@ -1,6 +1,7 @@ using System; using System.Net.Http; using System.Threading.Tasks; +using Microsoft.Extensions.Caching.Memory; using Org.BouncyCastle.Crypto; namespace Medidata.MAuth.Core @@ -8,7 +9,8 @@ namespace Medidata.MAuth.Core internal class MAuthAuthenticator { private readonly MAuthOptionsBase options; - private MAuthRequestRetrier retrier; + private readonly MAuthRequestRetrier retrier; + private readonly IMemoryCache cache = new MemoryCache(new MemoryCacheOptions()); public Guid ApplicationUuid => options.ApplicationUuid; @@ -60,11 +62,24 @@ public async Task AuthenticateRequest(HttpRequestMessage request) } } - private async Task GetApplicationInfo(Guid applicationUuid) => - await (await retrier.GetSuccessfulResponse(applicationUuid, CreateRequest, - requestAttempts: (int)options.MAuthServiceRetryPolicy + 1)) - .Content - .FromResponse(); + private Task GetApplicationInfo(Guid applicationUuid) => + cache.GetOrCreateAsync(applicationUuid, async entry => + { + var response = await retrier.GetSuccessfulResponse( + applicationUuid, + CreateRequest, + requestAttempts: (int)options.MAuthServiceRetryPolicy + 1 + ); + + var result = await response.Content.FromResponse(); + + entry.SetOptions( + new MemoryCacheEntryOptions() + .SetAbsoluteExpiration(response.Headers.CacheControl?.MaxAge ?? TimeSpan.FromHours(1)) + ); + + return result; + }); private HttpRequestMessage CreateRequest(Guid applicationUuid) => new HttpRequestMessage(HttpMethod.Get, new Uri(options.MAuthServiceUrl, diff --git a/src/Medidata.MAuth.Core/MAuthRequestRetrier.cs b/src/Medidata.MAuth.Core/MAuthRequestRetrier.cs index 13eb1d2..8db78e9 100644 --- a/src/Medidata.MAuth.Core/MAuthRequestRetrier.cs +++ b/src/Medidata.MAuth.Core/MAuthRequestRetrier.cs @@ -1,7 +1,4 @@ using System; -#if !NETSTANDARD1_4 -using System.Net.Cache; -#endif using System.Net.Http; using System.Threading.Tasks; @@ -18,19 +15,13 @@ public MAuthRequestRetrier(MAuthOptionsBase options) ApplicationUuid = options.ApplicationUuid, PrivateKey = options.PrivateKey }, - innerHandler: options.MAuthServerHandler ?? -#if NETSTANDARD1_4 - new HttpClientHandler() -#else - new WebRequestHandler() - { - CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default) - } -#endif + innerHandler: options.MAuthServerHandler ?? new HttpClientHandler() ); - client = new HttpClient(signingHandler); - client.Timeout = TimeSpan.FromSeconds(options.AuthenticateRequestTimeoutSeconds); + client = new HttpClient(signingHandler) + { + Timeout = TimeSpan.FromSeconds(options.AuthenticateRequestTimeoutSeconds) + }; } public async Task GetSuccessfulResponse(Guid applicationUuid, diff --git a/src/Medidata.MAuth.Core/Medidata.MAuth.Core.csproj b/src/Medidata.MAuth.Core/Medidata.MAuth.Core.csproj index e75610c..c71d0a1 100644 --- a/src/Medidata.MAuth.Core/Medidata.MAuth.Core.csproj +++ b/src/Medidata.MAuth.Core/Medidata.MAuth.Core.csproj @@ -13,6 +13,7 @@ + diff --git a/version.props b/version.props index 78afc83..c264a31 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 3.1.1 + 3.1.2