Optiize binder and api key retrieval caching
This commit is contained in:
parent
c5a9db661b
commit
bc4b04e378
|
|
@ -90,31 +90,27 @@ namespace NejCommon.Models
|
||||||
//get the binding parameter attributes
|
//get the binding parameter attributes
|
||||||
|
|
||||||
// Fetch the route values from the route data
|
// Fetch the route values from the route data
|
||||||
var capturedRouteData = new Dictionary<string, object>();
|
var values = new string[_routeValues.Length];
|
||||||
foreach (var routeValue in _routeValues)
|
for (var i = 0; i < _routeValues.Length; i++)
|
||||||
{
|
{
|
||||||
var name = routeValue.Name;
|
var routeValue = _routeValues[i];
|
||||||
if (routeValue.Primary && !string.IsNullOrWhiteSpace(bindingContext.ModelName))
|
|
||||||
{
|
|
||||||
name = bindingContext.ModelName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
var name =
|
||||||
Console.WriteLine("Route value: " + name);
|
routeValue.Primary && !string.IsNullOrWhiteSpace(bindingContext.ModelName)
|
||||||
Console.WriteLine();
|
? bindingContext.ModelName
|
||||||
Console.WriteLine(bindingContext.ActionContext.RouteData.Values[name]);
|
: routeValue.Name;
|
||||||
*/
|
|
||||||
|
|
||||||
var value = bindingContext.ValueProvider.GetValue(name).FirstOrDefault();//bindingContext.ActionContext.RouteData.Values[name];
|
// If these really are route values, don't go through the entire
|
||||||
|
// MVC ValueProvider infrastructure.
|
||||||
if (value is null)
|
if (!bindingContext.ActionContext.RouteData.Values.TryGetValue(name, out var rawValue) ||
|
||||||
|
rawValue is null)
|
||||||
{
|
{
|
||||||
bindingContext.ModelState.AddModelError(name, "Route value not found");
|
bindingContext.ModelState.AddModelError(name, "Route value not found");
|
||||||
|
bindingContext.Result = ModelBindingResult.Failed();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
values[i] = rawValue.ToString()!;
|
||||||
capturedRouteData[routeValue.Name] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if all the required route values are present
|
// Check if all the required route values are present
|
||||||
|
|
@ -124,21 +120,39 @@ namespace NejCommon.Models
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var entityParameter = Expression.Parameter(typeof(TEntity), "entity");
|
||||||
|
|
||||||
// Find the entity with the specified route values
|
// Find the entity with the specified route values
|
||||||
var query = _db.Set<TEntity>().AsQueryable();
|
Expression? predicateBody = null;
|
||||||
foreach (var routeValue in _routeValues)
|
for (var i = 0; i < _routeValues.Length; i++)
|
||||||
{
|
{
|
||||||
var value = capturedRouteData[routeValue.Name];
|
var routeValue = _routeValues[i];
|
||||||
|
|
||||||
var par = Expression.Parameter(typeof(TEntity));
|
// IMPORTANT:
|
||||||
var exp = Expression.Invoke(routeValue.Expression, par, Expression.Constant((string)value));
|
// captured variable -> EF parameter
|
||||||
var redExp = exp.Reduce();
|
// rather than Expression.Constant(value)
|
||||||
var compiledExp = Expression.Lambda<Func<TEntity, bool>>(redExp, par);
|
var value = values[i];
|
||||||
|
|
||||||
query = query.Where(compiledExp);
|
Expression<Func<string>> valueExpression = () => value;
|
||||||
|
|
||||||
|
var expression = Expression.Invoke(
|
||||||
|
routeValue.Expression,
|
||||||
|
entityParameter,
|
||||||
|
valueExpression.Body);
|
||||||
|
|
||||||
|
var body = expression.Reduce();
|
||||||
|
|
||||||
|
predicateBody = predicateBody is null
|
||||||
|
? body
|
||||||
|
: Expression.AndAlso(predicateBody, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
var model = await query.FirstOrDefaultAsync(cancellationToken);
|
var predicate =
|
||||||
|
Expression.Lambda<Func<TEntity, bool>>(
|
||||||
|
predicateBody!,
|
||||||
|
entityParameter);
|
||||||
|
|
||||||
|
var model = await _db.Set<TEntity>().AsQueryable().FirstOrDefaultAsync(predicate, cancellationToken);
|
||||||
|
|
||||||
if (model == null)
|
if (model == null)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,23 @@
|
||||||
using AspNetCore.Authentication.ApiKey;
|
using AspNetCore.Authentication.ApiKey;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NejCommon.Models;
|
using NejCommon.Models;
|
||||||
|
using NejCommon.Utils;
|
||||||
|
using ZiggyCreatures.Caching.Fusion;
|
||||||
|
|
||||||
namespace NejCommon.Services;
|
namespace NejCommon.Services;
|
||||||
|
|
||||||
public partial class ApiKeyProvider : IApiKeyProvider, IScopedService
|
public partial class ApiKeyProvider : IApiKeyProvider, IScopedService
|
||||||
{
|
{
|
||||||
private readonly ILogger<ApiKeyProvider> _logger;
|
private readonly ILogger<ApiKeyProvider> _logger;
|
||||||
|
private readonly IFusionCache _cache;
|
||||||
|
|
||||||
public async Task<IApiKey> ProvideAsync(string key)
|
public async Task<IApiKey?> ProvideAsync(string key)
|
||||||
{
|
{
|
||||||
try
|
using var activity = Telemetry.Start("ApiKeyProvider.ProvideAsync");
|
||||||
|
|
||||||
|
return await _cache.GetOrSetAsync($"ApiKeyProvider.ProvideAsync.{key}", async entry =>
|
||||||
{
|
{
|
||||||
|
// write your validation implementation here and return an instance of a valid ApiKey or retun null for an invalid key.
|
||||||
var lookup = ApiKey.ComputeLookupHash(key);
|
var lookup = ApiKey.ComputeLookupHash(key);
|
||||||
|
|
||||||
var apiKey = await GetApiKeySet().FirstOrDefaultAsync(x => x.LookupHash.SequenceEqual(lookup));
|
var apiKey = await GetApiKeySet().FirstOrDefaultAsync(x => x.LookupHash.SequenceEqual(lookup));
|
||||||
|
|
@ -25,17 +31,22 @@ public partial class ApiKeyProvider : IApiKeyProvider, IScopedService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (apiKey.Revoked)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
apiKey.Key = key;
|
apiKey.Key = key;
|
||||||
|
|
||||||
// write your validation implementation here and return an instance of a valid ApiKey or retun null for an invalid key.
|
|
||||||
// return await _apiKeyRepository.GetApiKeyAsync(key);
|
// return await _apiKeyRepository.GetApiKeyAsync(key);
|
||||||
return apiKey;
|
return apiKey;
|
||||||
}
|
}, new FusionCacheEntryOptions()
|
||||||
catch (System.Exception exception)
|
|
||||||
{
|
{
|
||||||
_logger.LogError(exception, exception.Message);
|
Duration = TimeSpan.FromMinutes(1),
|
||||||
throw;
|
IsFailSafeEnabled = true,
|
||||||
}
|
FailSafeMaxDuration = TimeSpan.FromMinutes(5),
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GenerateKey() => "nej-" + NanoidDotNet.Nanoid.Generate(size: 256);
|
public static string GenerateKey() => "nej-" + NanoidDotNet.Nanoid.Generate(size: 256);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user