tablesmit / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 1 forks source link

WebProtoBehavior #56

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago

I have not been able to get ProtoBehavior working with a WebGet 
OperationContract.  I want to do RESTful services with protocol buffers 
being the representation.  The System.ServiceModel.Web dll and namespace 
come with .NET 3.5.  

My guess, based on the docs here:
http://msdn.microsoft.com/en-us/library/bb412204.aspx

Is that something like this needs to be implemented:

using (var h = new WebServiceHost(typeof(TestService), uri))
{
    var b = new WebHttpBinding();
    var se = h.AddServiceEndpoint(typeof(ITestService), b, uri);
    //se.Behaviors.Add(new WebScriptEnablingBehavior()); // enables JSON
    se.Behaviors.Add(new WebProtoBehavior());

...

    public class WebProtoBehavior : IEndpointBehavior
    {

        public void AddBindingParameters(ServiceEndpoint endpoint, 
System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            throw new NotImplementedException();
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, 
System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            throw new NotImplementedException();
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            throw new NotImplementedException();
        }

        public void Validate(ServiceEndpoint endpoint)
        {
            throw new NotImplementedException();
        }
    }

Original issue reported on code.google.com by cameron.taggart on 5 May 2009 at 1:41

GoogleCodeExporter commented 8 years ago
This is an new feature request, not a defect.  Anyway, to quote that msdn 
document: 

http://msdn.microsoft.com/en-us/library/bb412204.aspx

"Extending WebHttpBehavior
WebHttpBehavior is extensible by using a number of virtual methods: 
GetOperationSelector, GetReplyClientFormatter, GetRequestClientFormatter, 
GetReplyDispatchFormatter, and GetRequestDispatchFormatter. Developers can 
derive a 
class from WebHttpBehavior and override these methods to customize the default 
behavior."

I'm not sure what the difference is between IClientMessageFormatter and 
IDispatchMessageFormatter yet, but I imagine a ProtoMessageFormatter could 
implement 
one of those, then a WebProtoBehavior could override a couple of the 
WebHttpBehavior 
methods and provide it.

Original comment by cameron.taggart on 5 May 2009 at 2:09

GoogleCodeExporter commented 8 years ago
OK, it was IDispatchMessageFormatter that did the trick.  Replies as Protocol 
Buffers 
are working with this code:

    public class WebProtoBehavior : WebHttpBehavior
    {
        protected override IDispatchMessageFormatter 
GetReplyDispatchFormatter(OperationDescription operationDescription, 
ServiceEndpoint 
endpoint)
        {
            return new ProtoDispatchMessageFormatter();
        }
    }

    public class ProtoDispatchMessageFormatter : IDispatchMessageFormatter
    {

        public void DeserializeRequest(Message message, object[] parameters)
        {
            throw new NotImplementedException();
        }

        public Message SerializeReply(MessageVersion messageVersion, object[] 
parameters, object result)
        {
            var contentType = "application/x-protobuf";
            var format = WebContentFormat.Raw;
            var type = result.GetType();

            // from ProtoOperationBehavior.cs
            var serializer = (XmlObjectSerializer)typeof(XmlProtoSerializer<>)
                .MakeGenericType(type)
                .GetConstructor(Type.EmptyTypes)
                .Invoke(null);

            WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
            OperationContext.Current.OutgoingMessageProperties.Add(
                WebBodyFormatMessageProperty.Name, new 
WebBodyFormatMessageProperty(format));
            return Message.CreateMessage(MessageVersion.None, null, result, 
serializer);
        }
    }

    // had to comment out WriteStartElement, so did the same for WriteEndElement
    class XmlProtoSerializer<T> : XmlObjectSerializer
    {
        public override void WriteEndObject(System.Xml.XmlDictionaryWriter writer)
        {
            //writer.WriteEndElement();
        }
        public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, 
object graph)
        {
            //writer.WriteStartElement(PROTO_ELEMENT); // Exception
        }
...

Original comment by cameron.taggart on 7 May 2009 at 2:27

GoogleCodeExporter commented 8 years ago
That looks really promising; any example usage? Is it just a case of decorating 
methods/the interface/? with the behaviour? And if so, at client? server?

(basically, I'd love to put a unit test together and commit it)

Your input is hugely appreciated,

Marc

Original comment by marc.gravell on 7 May 2009 at 7:03

GoogleCodeExporter commented 8 years ago

I was able to get a WCF REST Service reply with Protocol Buffers (PB).  I was 
*not* 
able to get a WCF REST client able to deserialze the reply.  I tried multiple 
ways 
and this is an en excpetion where I feel I was close, but haven't figured out 
how to 
resolve this:

System.Runtime.Serialization.SerializationException was unhandled
  Message="There was an error checking start element of object of type 
Company.License. The data at the root level is invalid. Line 1, position 1."
  Source="mscorlib"
  StackTrace:
    Server stack trace: 
       at 
System.Runtime.Serialization.XmlObjectSerializer.IsStartObjectHandleExceptions(X
mlRea
derDelegator reader)
       at 
System.Runtime.Serialization.DataContractSerializer.IsStartObject(XmlDictionaryR
eader 
reader)
       at 
System.ServiceModel.Dispatcher.SingleBodyParameterMessageFormatter.ReadObject(Me
ssage 
message)
       at 
System.ServiceModel.Dispatcher.SingleBodyParameterMessageFormatter.DeserializeRe
ply(M
essage message, Object[] parameters)
       at 
System.ServiceModel.Dispatcher.DemultiplexingClientMessageFormatter.DeserializeR
eply(
Message message, Object[] parameters)
       at 
System.ServiceModel.Dispatcher.CompositeClientFormatter.DeserializeReply(Message

message, Object[] parameters)
       at System.ServiceModel.Dispatcher.ProxyOperationRuntime.AfterReply(ProxyRpc& 
rpc)
       at 
System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime 
operation, ProxyRpc& rpc)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean 
oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan 
timeout)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean 
oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
       at 
System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessag
e 
methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage 
reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& 
msgData, Int32 type)

Original comment by cameron.taggart on 13 May 2009 at 8:29

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago

I took a completely different approach and implemented a MessageEncoder that 
begins 
like this:

namespace ProtoBuf.ServiceModel.Web
{
    public class ProtoMessageEncoder : MessageEncoder
    {

I just got it working on the server side and the client side looks possible.  
Another 
approach may be to implement a custom DataContractSerializer, then wire it up 
like 
so:

http://tinyurl.com/rbwzl3

Original comment by cameron.taggart on 16 May 2009 at 3:16

GoogleCodeExporter commented 8 years ago
Interesting; anything concrete?

Original comment by marc.gravell on 16 May 2009 at 8:46

GoogleCodeExporter commented 8 years ago
I am probably going to give up for now on getting the WCF client working.  I'm 
getting quite frustrated with the WCF API, even with 3 books on hand.  I posted 
a 
message here where I got stuck:

http://tinyurl.com/p22wvc

I got the WCF services serving protocol buffers with two different 
implementations.  
They work, but both must create MemoryStream buffers, which doesn't feel right. 
 WCF 
is extremely XML centric.

Original comment by cameron.taggart on 19 May 2009 at 2:05

GoogleCodeExporter commented 8 years ago
I feel for your frustration. I hugely appreciate all the time you've spent 
trying to 
crack this; it must be painful that it (WCF) refuses to play the game...

It sounds like you've done a lot more digging in this area than I have, so I 
can't 
offer any sensible input - but really: thanks again for trying.

Regards,

Marc

Original comment by marc.gravell on 19 May 2009 at 7:28

GoogleCodeExporter commented 8 years ago
Marc, Cameron
Have you made any progress on this front.
I am currently using Damian Mehers approach to send back XML and JSON.
I need to add protobuf to that mix.
http://damianblog.com/2008/10/31/wcf-rest-dynamic-response/

if a working version of public 
class WebProtoBehavior : WebHttpBehavior exist I think I can take it the rest 
of the 
way.

Herb

Original comment by ghst...@gmail.com on 26 Aug 2009 at 9:48

GoogleCodeExporter commented 8 years ago
Ok, so I don't know where Cameron got stuck, but I followed his lead and got it 
all 
to work end to end.
1) sync down r269
2) add the 3 files I have attached here 
(ProtoDispatchMessageFormatter.cs,WebProtoBehavior.cs, 
XmlProtoSerializerForRest.cs).  This is all from camerons stuff.
3) I was enhanced Damian Mehers to also return protobuf stuff
http://damianblog.com/2008/10/31/wcf-rest-dynamic-response/
4) I wrote a test forms application that requests a protobuf response and 
deserializes it correctly.

Original comment by ghst...@gmail.com on 28 Aug 2009 at 5:46

Attachments:

GoogleCodeExporter commented 8 years ago
Cool - interesting progress. This simply isn't something I've had chance to 
progress, 
so thanks.

Original comment by marc.gravell on 28 Aug 2009 at 9:42