Asp.net web api 带有协议缓冲区的ASP.NET WebApi-错误处理
上下文: 我现在所拥有的:Asp.net web api 带有协议缓冲区的ASP.NET WebApi-错误处理,asp.net-web-api,error-handling,json.net,protocol-buffers,protobuf-net,Asp.net Web Api,Error Handling,Json.net,Protocol Buffers,Protobuf Net,上下文: 我现在所拥有的: 三层应用程序 客户机-服务器通信 服务器:ASP.NET WebApi v1 客户端:HttpClient 序列化-JSON.NET 但是, JSON.NET速度很慢 在第一次调用时,JSON.NET甚至更慢(我认为这是因为序列化程序集的动态生成)。这对我来说太慢了——根据需要,我需要尽可能优化第一次调用 我正在考虑使用JSON.NET而不是JSON.NET。在一个简单的PoC应用程序上,即使是第一次调用,它也显示了两倍多的快速结果,特别是当我为协议缓冲区序列化程
- 服务器:ASP.NET WebApi v1
- 客户端:HttpClient
public class ExceptionShielderAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, context.Exception);
}
}
在内部,CreateErrorResponse方法创建HttpError的实例(从Dictionary[string,object]继承)并将其写入内容
默认情况下,protobuf net对HttpError一无所知,所以我尝试将HttpError添加到protobuf运行时模型中,如下所示
typeModel.Add(typeof (HttpError), true);
但是,当我打电话时,这没有帮助
typeModel.Compile("ModelSerializer", "ModelSerializer.dll")
它抛出InvalidOperationException:没有为类型System.Object定义序列化程序。
可能是由于protobuf net不支持的字典类型[string,object]
问题:
你最好的选择是使用代理;比如:
typeModel.Add(typeof(HttpError), false)
.SetSurrogate(typeof(MyError));
其中MyError
是您的自定义类型,它:
- 有一个转换运算符(隐式或显式)到/从
HttpError
- 适用于protobuf网络
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
var completionSource = new TaskCompletionSource<object>();
try
{
if (type == typeof(HttpError))
{
value = CreateDto((HttpError) value);
}
model.Value.Serialize(stream, value);
completionSource.SetResult((object)null);
}
catch (Exception ex)
{
completionSource.SetException(ex);
}
return (Task)completionSource.Task;
}
private HttpErrorDto CreateDto(HttpError error)
{
if (error == null) return null;
return new HttpErrorDto
{
Message = error.GetValueOrDefault<string>("Message"),
ExceptionMessage = error.GetValueOrDefault<string>("ExceptionMessage"),
StackTrace = error.GetValueOrDefault<string>("StackTrace"),
ExceptionType = error.GetValueOrDefault<string>("ExceptionType"),
InnerException = CreateDto(error.GetValueOrDefault<HttpError>("InnerException"))
};
}
public override Task WriteToStreamAsync(类型、对象值、流、HttpContent内容、TransportContext)
{
var completionSource=new TaskCompletionSource();
尝试
{
if(type==typeof(HttpError))
{
值=CreateDto((HttpError)值);
}
model.Value.Serialize(流,值);
completionSource.SetResult((对象)null);
}
捕获(例外情况除外)
{
completionSource.SetException(ex);
}
返回(任务)completionSource.Task;
}
私有HttpErrordToCreatedTo(HttpError错误)
{
if(error==null)返回null;
返回新的HttpErrorDto
{
Message=错误。GetValueOrDefault(“消息”),
ExceptionMessage=error.GetValueOrDefault(“ExceptionMessage”),
StackTrace=error.GetValueOrDefault(“StackTrace”),
ExceptionType=错误。GetValueOrDefault(“ExceptionType”),
InnerException=CreateDto(error.GetValueOrDefault(“InnerException”))
};
}
下面是一个使用protobuf net实现System.Web.Http.HttpError序列化的代码片段
namespace WS
using System;
using System.Runtime.Serialization;
using System.Web.Http;
using WebApiContrib.Formatting;
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.Add(new ProtoBufFormatter());
ProtoBufFormatter.Model.Add(typeof(HttpErrorProto), true);
var model = ProtoBufFormatter.Model.Add(typeof(HttpError), false);
model.IgnoreListHandling = true;
model.SetSurrogate(typeof(HttpErrorProto));
}
}
[DataContract]
public class HttpErrorProto
{
[DataMember(Order = 1)]
public String ExceptionMessage { get; set; }
[DataMember(Order = 2)]
public String ExceptionType { get; set; }
[DataMember(Order = 3)]
public String InnerException { get; set; }
[DataMember(Order = 4)]
public String MessageDetail { get; set; }
[DataMember(Order = 5)]
public String Message { get; set; }
[DataMember(Order = 6)]
public String ModelState { get; set; }
[DataMember(Order = 7)]
public String StackTrace { get; set; }
public static implicit operator HttpErrorProto(HttpError error)
{
return error == null ? null : new HttpErrorProto
{
ExceptionMessage = error.ContainsKey("ExceptionMessage") ? error["ExceptionMessage"] as string : null,
ExceptionType = error.ContainsKey("ExceptionType") ? error["ExceptionType"] as string : null,
InnerException = error.ContainsKey("InnerException") ? error["InnerException"] as string : null,
MessageDetail = error.ContainsKey("MessageDetail") ? error["MessageDetail"] as string : null,
Message = error.Message,
ModelState = error.ContainsKey("ModelState") ? error["ModelState"] as string : null,
StackTrace = error.ContainsKey("StackTrace") ? error["StackTrace"] as string : null
};
}
public static implicit operator HttpError(HttpErrorProto error)
{
return error == null ? null : new HttpError
{
Message = error.Message
...
};
}
}
}
谢谢你的回答。但这并没有帮助。我按照你说的做了,但是typeModel.Compile()抛出了ArgumentException:重复数据(列表、集合等)具有内置行为,不能使用代理项。它是字典[字符串、对象]@olldman它是字典吗?还是有字典?但从根本上说:这个对象是行不通的。例如,如果您可以在从模型到DTO的转换过程中串值,例如它是一个字典-请在这里找到它的源代码,至于您的建议,我认为当调用CreateErrorResponse(此处-)时,不可能像WebApi故意这样做。看起来自定义错误处理是唯一的方法:(@olldman)这很尴尬。我可能可以编写代码来解决它,但它在今天不起作用。这是一个非常有用的解决方案。