Reputation: 17915
Is there any canonical straight way of enabling protobuf-net serialization on .NET 4 WCF? I tried to simplify code to the point where it can be easy to build on:
Here is my service code:
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MobileServiceV2
{
[WebGet(UriTemplate = "/some-data")]
[Description("returns test data")]
public MyResponse GetSomeData()
{
return new MyResponse { SomeData = "Test string here" };
}
}
[DataContract]
public class MyResponse
{
[DataMember(Order = 1)]
public string SomeData { get; set; }
}
I'm activating this service route in Application_OnStart
(Global.asax) like so:
RouteTable.Routes.Add(new ServiceRoute("mobile", new MyServiceHostFactory(), typeof(MobileServiceV2)));
I use MyServiceHostFactory
to manage services with MEF, but that's irrelevant.
Configuration of my service is all default, the only additional stuff in Web.Config is here:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint helpEnabled="true" maxReceivedMessageSize="5242880" defaultOutgoingResponseFormat="Json" automaticFormatSelectionEnabled="true">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</standardEndpoint>
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
Ok, service alive and running. There is mobile/help, I can issue GET on mobile/some-data and getting response in both XML and JSON
application/xml returns XML, application/json returns JSON
What do I need to do so clients can set application/x-protobufs and get their response encoded using protobuf-net?
I'm reading whole day and getting more and more confused...
Here is what I found so far and nothing seems to give straight solution:
Second link is kind of what I need, but it doesnt work for me. Don't know why but I can't figure out which namespace MediaTypeProcessor
lives in and just can't make it work in .NET4 ?
Various scattered info about configuring protobuf-net via web.config give me different errors and I'm just not sure I need to go that way. I'd rather have code-only solution.
EDIT:
From what I researched - my bad, MediaFormatter
seem to NOT be in current version of WCF. I wonder if creating separate URL for all protobuf clients will be best? This way I can receive Stream and return Stream. Handler all serializing logic manually. Little more work but I will have better control over actual data.
Upvotes: 5
Views: 1733
Reputation: 1063338
The first thing to do is to add Microsoft.AspNet.WebApi
("Microsoft ASP.NET Web API Core Libraries (RC)") and Microsoft.AspNet.WebApi.Client
("Microsoft ASP.NET Web API Client Libraries (RC)") via NuGet.
This looks like the most promising walk-through: http://byterot.blogspot.co.uk/2012/04/aspnet-web-api-series-part-5.html
MediaTypeFormatter
is in System.Net.Http.Formatting
I haven't got time right now to try and get it working, but you can PRESUMABLY add the formatter via:
GlobalConfiguration.Configuration.Formatters.Add(
new ProtobufMediaTypeFormatter(RuntimeTypeModel.Default));
With an example COMPLETELY UNTESTED implementation of something like:
public class ProtobufMediaTypeFormatter : MediaTypeFormatter
{
private readonly TypeModel model;
public override bool CanReadType(Type type)
{
return model.IsDefined(type);
}
public override bool CanWriteType(Type type)
{
return model.IsDefined(type);
}
public ProtobufMediaTypeFormatter() : this(null) {}
public ProtobufMediaTypeFormatter(TypeModel model) : base()
{
this.model = model ?? RuntimeTypeModel.Default;
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/protobuf"));
}
public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type, System.IO.Stream stream, HttpContentHeaders contentHeaders, IFormatterLogger formatterLogger)
{
// write as sync for now
var taskSource = new TaskCompletionSource<object>();
try
{
taskSource.SetResult(model.Deserialize(stream, null, type));
} catch (Exception ex)
{
taskSource.SetException(ex);
}
return taskSource.Task;
}
public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, System.IO.Stream stream, HttpContentHeaders contentHeaders, System.Net.TransportContext transportContext)
{
// write as sync for now
var taskSource = new TaskCompletionSource<object>();
try
{
model.Serialize(stream, value);
taskSource.SetResult(null);
}
catch (Exception ex)
{
taskSource.SetException(ex);
}
return taskSource.Task;
}
}
I know virtually nothing about Web API, so please let me know if you manage to get it working for you. I will quite happily add a supported wrapper as a downloadable binary, but I can't do that until it works ;p
Upvotes: 3