Context:
What i have now:
However,
I am considering using protobuf-net instead of JSON.NET. On a simple PoC app it has shown more than twice as fast result, even the first call, especially when i'd pre-generated the assembly for protocol buffers serializer.
So i've implemented MediaTypeFormatter using protobuf-net and everything works well except one thing - serializing errors.
This is how the exceptions are passed to the client:
public class ExceptionShielderAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
context.Response = context.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, context.Exception);
}
}
Internally, CreateErrorResponse method creates an instance of HttpError (which inherits from Dictionary[string, object]) and writes it to the content.
By default, protobuf-net knows nothing about HttpError so I've tried to add HttpError to protobuf runtime model as follows
typeModel.Add(typeof (HttpError), true);
but it did not help, when i call
typeModel.Compile("ModelSerializer", "ModelSerializer.dll")
it throws InvalidOperationException: No serializer defined for type: System.Object. Likely due to type of Dictionary[string, object] which is not supported by protobuf-net.
Questions:
Is there anything I can do to serialize errors properly or should i avoid using out-of-the-box errorhanding and implement my own error handling on the server that uses well-know types that protobuf is aware of?
Is protobuf a good choice for my problem at all?
Here is a snippet that enable serialization of System.Web.Http.HttpError using protobuf-net
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
...
};
}
}
}
Your best bet would be to use a surrogate; something like:
typeModel.Add(typeof(HttpError), false)
.SetSurrogate(typeof(MyError));
Where MyError
is a custom type of yours which:
HttpError
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With