I am sending a JSON message including filename, and a base64encoded image to a WCF service. I am not really sure on how to convert it back to the image, more specificallly deserializing the return stream.
WCF Interface
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "/UploadImage", ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
string UploadImage(Stream image);
And some part of the message(which I save to a file so I can view and try to understand)
--hr56lXG6Q_hKg5opmTx4xejr28dU17AC
Content-Disposition: form-data; name="entity"
{"filename":"mypicture.jpg","thebigfile":"\/9j\/4Re6RXhpZgAATU0AKgAAAAgACwEPAAIAAAAOAAAAkgEQAAIAAAAGAAAAoAESAAMAAAABAAYAAAEaAAUAAAABAAAApgEbAAUAAAABAAAArgEoAAMAAAABAAIAAAExAAIAAAATAAAAtgEyAAIAAAAUAAAAygITAAMAAAABAAEAAIdpAAQAAAABAAAA3oglAAQAAAABAAACegAAAoBTb255IEVyaWNzc29uAExUMjZpAAAAAEgAAAABAAAASAAAAAE2LjEuQS4yLjQ1XzUzX2YxMDAApDIwMTI6MTA6MDYgMDk6MzI6MTcAABiCmgAF
and lots more of the base64 encoded image....
--hr56lXG6Q_hKg5opmTx4xejr28dU17AC--
How do I deserialize this? Is Stream the way to go? I do not simply want to remove the top rows and then start deserializing the JSON array, I want to know WHY it looks like this.
To process the message you gave, the OperationContract needs to look something like:
[WebInvoke(Method="POST", UriTemplate="/UploadImage", BodyStyle=WebMessageBodyStyle.WrappedRequest, ResponseFormat=WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json)]
[OperationContract]
string UploadImage(string filename, string thebigfile);
See http://msdn.microsoft.com/en-us/library/bb885100.aspx for more information
You would then need to manually Base64-decode the "thebigfile" parameter using the decoder provided by the .NET Framework. There is no built-in support for Base64 inside JSON as far as I know, see http://msdn.microsoft.com/en-us/library/bb412170.aspx for details on how various data types are supported.
Related
I am building a couple of REST web services with WCF. I have some POST services to which I pass a list of objects in the wrapped HTTP body like this:
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "DoSomething/pages?term={term}",
BodyStyle = WebMessageBodyStyle.Wrapped)
]
MyResponseContainer DoSomethingFromPages(string term, List<Page> pages);
This works just fine. I can wrap the List<Page> into JSON or XML and put it into the body and it is deserialized automatically.
In a similar way I have another service where I read a binary stream (a file) from the HTTP body like this:
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "DoSomething/upload?term={term}",
BodyStyle = WebMessageBodyStyle.Bare)
]
MyResponseContainer DoSomethingUploadFile(Stream httpBody, string term);
Now my question is: Can I somehow combine both ways? So basically I want to pass a list of custom objects together with a (file)stream. And I would like to avoid using multi-part forms style.
Thanks a lot!
I have a WCF endpoint that is like such:
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, UriTemplate = "")]
Stream DoWork(Dictionary<string, string> items);
In order to pass anything to my service, I have to structure my JSON like such:
{"items":[{"Key":"random1","Value":"value1"}, {"Key":"random2","Value":"value2"}]}
What I actually want it to look like is this:
{"items":{"random1":"value1","random2":"value2"}}
Is there any way to accomplish this?
Is it an option for you to change the DoWork parameter to a string, then use a Json deserializer in the method to convert it to the appropriate format?
I have been searching for the same solution. I managed to get it working by using 'JavaScriptSerializer'. You have to set the function output to 'Stream' not 'String'.
Public Function hotel_availability(ByVal data1 As Stream) As Stream Implements IMyTestAPI.hotel_availability
....
Dim serializer As New JavaScriptSerializer()
Dim serializedResult = serializer.Serialize(a_response)
Dim json = Encoding.UTF8.GetBytes(serializedResult)
Dim a_result as New MemoryStream(json)
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8"
return a_result
You basically need a SerializableDynamic Object, so that your method will look like this:
[OperationContract]
[WebInvoke(...)]
Stream DoWork(SerializableDynamicObject items);
You can see a good guide on how to build the SerializableDynamic Object from a Dictionary here: (see Solution section). Hope this helps...
You may have better success using the Newtonsoft JSON serializer.
It is available here http://www.newtonsoft.com/json for free and is also available as a NuGet package.
I have found to be much more flexible than the stock JSON serializers.
Also, it looks like your URITemplate is empty. I haven't used the wrapped body style, but with bare body style you need the URITemplate to be populated.
Is there a way to dynamically change the WebResponseFormat on a method given a parameter passed by the client? I default my WebResponseFormat to XML, but I want to give the client the opportunity to specify a format as JSON or XML and if none is specified, default to XML.
Currently I am doing the following:
[WebGet(UriTemplate = "objects", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
List<SampleObject> GetObjects();
The user can call it via:
http://localhost/rest/myservice/objects
They then can specify a format by doing:
http://localhost/rest/myservice/objects?format=json
The problem is that when I try to set the response content type via:
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json";
That just returns the XML but the browser attempts to process it like a JSON object instead of serializing the response as JSON.
Is this even possible with .NET 3.5 outside of using a Stream as the return value and serializing the response myself? If not, is there a better solution?
I was able to resolve this by doing the following:
[WebGet(UriTemplate = "objects", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract]
List<SampleObject> GetObjects();
[WebGet(UriTemplate = "objects?format=json", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
List<SampleObject> GetObjectsInJson();
It isn't pretty, but if format=xml is defined or left off, it will default to my operation contract, but if format=json is defined, it defaults to the second operation contract. This successfully returns the result as JSON and XML as desired.
For .NET 3.5 and WCF REST 3.5, I don't know of any way to do this elegantly.
.NET 4 and WCF REST in .NET 4 will support the "content negotiation" strategy that you use - just setting the ContentType = "application/json" will cause the service to automagically return JSON instead of XML.
So if there's any chance for you, wait for .NET 4 (should be out mid April 2010) and use that - it should offer lots of improvements in WCF anyway, especially in the WCF REST area.
i am using the Plain old XML template from WCF REST Starter Kit Preview 2 to build a REST service and i would like to set the ResponseFormat inside the OperationContract, not outside(not with ResponseFormat = WebMessageFormat.Json) because i want to set it accordingly to the Accept Header in the Request. and ideally i would like to be able to set the RequestFormat from inside the OperationContract also, acording to the Content-Type header.
So, could anyone tell me how i can do it, or point me towards some examples.
chers,
Later Edit: so i don't want to have things like "format" in the UriTemplate, i just want one UriTemplate, no ResponseFormat (and no RequestFormat at some point) and the ResponseBody to be output according to the AcceptHeader
[WebHelp(Comment = "For Service testing purposes")]
[WebGet(UriTemplate = "Echo")]
[OperationContract]
public ResponseBody Echo()
You'll have to strip off most of the WCF REST code and rebuild it yourself. There is no support for content-type negotiation out of the box. I am lead to believe the starter kit has an example using their extensibility points, you may want to check with them.
http://damianblog.com/2008/10/31/wcf-rest-dynamic-response/ is a good place to start
In the following scenario I want to return just a string because that's what the spec says but to do that I have to return a stream and I just want to make sure than I don't keep too many streams around for too long. The method looks like:
[WebGet(BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml,
UriTemplate = "someuri/{parameter}")]
[OperationContract]
public Stream FooBar(string parameter)
{
byte[] bytes = Encoding.UTF8.GetBytes("some string");
return new MemoryStream(bytes);
}
Does anyone know when this resource is released?
I've been doing some research and found a few interesting articles on the topic:
Closing Returned Streams in WCF
WCF Streaming: Upload files over HTTP
Hope that might be helpful!
I would think by the GC, as for a normal object: when all references to it have gone.
And that is not bad, MemoryStream does implement IDisposable but doesn't really need it.