根据标题,我希望能够在 Startup.cs 中添加开放的通用 InputFormatter 和 OutputFormatter 实例作为 ConfigureServices 的一部分,类似于如何添加开放的通用服务。
我想要的看起来像这样:
services.AddMvc(options =>
{
options.InputFormatters.Add(new ProtobufInputFormatter<>());
options.OutputFormatters.Add(new ProtobufOutputFormatter<>());
options.FormatterMappings.SetMediaTypeMappingForFormat("protobuf", MediaTypeHeaderValue.Parse("application/x-protobuf"));
});
这有可能吗?
编辑:
当前实现的 ProtobufOutputFormatter 示例
public class ProtobufInputFormatter : InputFormatter
{
static MediaTypeHeaderValue protoMediaType = MediaTypeHeaderValue.Parse("application/x-protobuf");
public override bool CanRead(InputFormatterContext context)
{
var request = context.HttpContext.Request;
MediaTypeHeaderValue requestContentType = null;
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
if (requestContentType == null)
{
return false;
}
return requestContentType.IsSubsetOf(protoMediaType);
}
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
try
{
var request = context.HttpContext.Request;
var obj = (IMessage)Activator.CreateInstance(context.ModelType);
obj.MergeFrom(request.Body);
return InputFormatterResult.SuccessAsync(obj);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex);
return InputFormatterResult.FailureAsync();
}
}
}
问题是使用反射不如我能够使用通用 Protobuf 反序列化器那样高效,例如:
public class ProtobufInputFormatter<T> : InputFormatter where T : IMessage<T>, new()
{
static MediaTypeHeaderValue protoMediaType = MediaTypeHeaderValue.Parse("application/x-protobuf");
public override bool CanRead(InputFormatterContext context)
{
var request = context.HttpContext.Request;
MediaTypeHeaderValue requestContentType = null;
MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType);
if (requestContentType == null)
{
return false;
}
return requestContentType.IsSubsetOf(protoMediaType);
}
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
{
try
{
var request = context.HttpContext.Request;
var serialiser = new ProtobufSerialiser<T>();
var obj = serialiser.Deserialise(request.Body);
return InputFormatterResult.SuccessAsync(obj);
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex);
return InputFormatterResult.FailureAsync();
}
}
ProtobufSerialiser 是我们拥有的 Google.Protobuf 的包装器(出于性能原因,它被实现为与缓冲池一起工作,这被对 Activator.CreateInstance 的需要所颠覆,如上面实际实现和工作的非通用示例所示。)
T 将来自端点。