我正在使用 .net 8 和 Kestrel。我正在尝试获取任何 Post 或 Put 请求的类类型。
我的端点代码看起来像这样:
endpoints.MapPost($"{_basePath}/registerMyObject", [AllowAnonymous] async ([FromBody] MyOject myObject) =>
{
// my code
}
我的中间件看起来像:
public class ValidateModelMiddleware : IMiddleware
{
private ITokenService _tokenService;
private IServiceProvider _serviceProvider;
public ValidateModelMiddleware([FromServices] ITokenService tokenService, [FromServices] IServiceProvider serviceProvider)
{
_tokenService = tokenService;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (context.Request.Method == "POST" || context.Request.Method == "PUT")
{
// I need to figure out the type that was passed in. For instance
}
}
因此,当收到 registerMyObject 请求时,我想获取 Type MyOject,以便我可以将该 json 文本直接反序列化到该类中。如果使用不同的 Post / Put 请求并且它具有不同的类类型,那么我想获取相应的类型。有办法做到这一点吗?
您可以根据 jsonstring“keys”是否与哪个类类型字段匹配来选择要反序列化的类型。例如:
如果有
ClassA
和 ClassB
都实现 MyObject
。
public class ClassA :MyObject
{
public string Name { get; set; }
public string Address { get; set; }
}
public class ClassB : MyObject
{
public string Name { get; set; }
public string Age { get; set; }
}
您可以使用以下代码来获取与 jsonstring 匹配的“classResult”字符串。
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var classResult = "";
//Get JsonString
var bodyStr = "";
using (StreamReader reader
= new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true))
{
bodyStr = await reader.ReadToEndAsync();
}
//Parse to JObject and get the keys
var jobject = (JObject)JsonConvert.DeserializeObject(bodyStr);
var keys = jobject.Properties().Select(p => p.Name);
//Get all types implement "MyObject"
var parenttype = typeof(MyObject);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => parenttype.IsAssignableFrom(p));
//Compare which type matches keys
foreach (var type in types)
{
if (Match(keys, type))
{
classResult=type.Name;
}
}
await next(context);
}
//Method to compare if keys matches all the fields of a Class type
private bool Match(IEnumerable<string>? keys,Type type)
{
var fieldNames =type .GetProperties().Select(field => field.Name);
if (!keys.Except(fieldNames).Any() && !fieldNames.Except(keys).Any())
{
return true;
}
else
{
return false;
}
}
如果您使用的是最小 API,那么您可以利用 端点过滤器(例如此处):
app.MapPost("/reports", (ReportDTO activityReport) => ...)
.AddEndpointFilter(async (context, next) =>
{
// collection will contain ReportDTO activityReport itself:
IList<object?> mappedArguments = context.Arguments;
return await next(context);
});
如果您希望这是一个中间件,那么对于端点路由,您可以使用
IEndpointFeature
(中间件应在适当的位置注册,另请注意,对于控制器的处理可能会有所不同):
// lambda is analog for you InvokeAsync method
app.Use(async (context, next) =>
{
var endpointFeature = context.Features.Get<IEndpointFeature>();
var endpointMetadataCollection = endpointFeature.Endpoint.Metadata;
var acceptsMetadata = endpointMetadataCollection.GetMetadata<AcceptsMetadata>();
var requestType = acceptsMetadata.RequestType; // typeof(ReportDTO)
// ...
await next();
});
显然第一种方法在性能方面应该更好,因为您不需要多次绑定数据