I'm using WCF, REST and "pretty URI's" as shown in this blog post with the Online Template for VS 2010 .NET 4.0:
http://christopherdeweese.com/blog2/post/drop-the-soap-wcf-rest-and-pretty-uris-in-net-4
I have one problem though.
I want to return a a raw byte[] array but it automatically gets base64 encoded.
Unfortunately for my program base64 encoding is not acceptable because it will be too computationally intensive.
Is there a way for me to tell WCF NOT to base64 encode?
[WebGet(UriTemplate = "{id}")]
public byte[] Get(string id)
{
byte[] data = new byte[1024];
return data;
}
Appears to my web browser as:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
Use Stream as your return type.
Related
I'm using RestSharp, and using Json.NET for serialization (see here).
Json.NET supports BSON, and since some of my requests have huge blocks of binary data, I think this would speed up my application dramatically. However, as far as I can tell, RestSharp does not seem to have any in-built support for BSON.
The use of Json.NET is implemented as a custom serializer for RestSharp, and so at first glance it looks like it would be possible to modify that custom serializer to use BSON. But, the Serialize method of the RestSharp.Serializers.ISerializer interface returns a string - which is (I assume) unsuitable for BSON. So, I assume that it would take some more significant changes to RestSharp to implement this change.
Has anyone figured out a way to do this?
Update: I looked at the RestSharp source, and discovered that the RestRequest.AddBody method that takes my object and serializes it into the request body eventually calls Request.AddParameter (with the serialized object data, and the parameter type RequestBody).
I figured that I might be able to serialize my object to BSON and then call Request.AddParameter directly - and indeed I can. However, when RestSharp then executes the RestRequest, it fails to put the binary content into the request, because there are other embedded assumptions about the request content being UTF-8 encoded.
Thus it looks like this hack would not work - there would need to be some changes made to RestSharp itself, and I'm not the man for the job...
Update 2: I decided to have a go at using the debugger to figure out how much of RestSharp I'd have to change to overcome the body-encoding issue, so I swapped out my NuGet version of RestSharp and included the RestSharp project in my solution. And... it worked.
It turns out that there has been a change to RestSharp in the last few months that isn't yet in the NuGet version.
So, you can now use AddParameter and pass in an already-BSON-encoded object, and RestSharp will send it off to the server without complaint.
Per the updates in my question, it turns out that if you have the latest RestSharp source, then instead of this:
request.AddBody(myObject);
... you can do this instead whenever you have a payload that would benefit from using BSON:
using (var memoryStream = new System.IO.MemoryStream())
{
using (var bsonWriter = new Newtonsoft.Json.Bson.BsonWriter(memoryStream))
{
var serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Serialize(bsonWriter, myObject);
var bytes = memoryStream.ToArray();
request.AddParameter("application/bson", bytes, RestSharp.ParameterType.RequestBody);
}
}
Note that the first parameter to AddParameter is supposedly the parameter name, but in the case of ParameterType.RequestBody it's actually used as the content type. (Yuk).
Note that this relies on a change made to RestSharp on April 11 2013 by ewanmellor/ayoung, and this change is not in the current version on NuGet (104.1). Hence this will only work if you include the current RestSharp source in your project.
Gary's answer to his own question was incredibly useful for serializing restful calls. I wanted to answer how to deserialize restful calls using JSON.NET. I am using RestSharp version 104.4 for Silverlight. My server is using Web API 2.1 with BSON support turned on.
To accept a BSON response, create a BSON Deserializer for RestSharp like so
public class BsonDeserializer : IDeserializer
{
public string RootElement { get; set; }
public string Namespace { get; set; }
public string DateFormat { get; set; }
public T Deserialize<T>(IRestResponse response)
{
using (var memoryStream = new MemoryStream(response.RawBytes))
{
using (var bsonReader = new BsonReader(memoryStream))
{
var serializer = new JsonSerializer();
return serializer.Deserialize<T>(bsonReader);
}
}
}
}
Then, ensure your request accepts "application/bson"
var request = new RestRequest(apiUrl, verb);
request.AddHeader("Accept", "application/bson");
And add a handler for that media type
var client = new RestClient(url);
client.AddHandler("application/bson", new BsonDeserializer());
I've implemented a WCF Routing service; I would also like the service (or a similar WCF service) to transform the payload in a prescribed and uniform (content-agnostic) fashion. For example, the payload will always take the form Foo<T> and I would like to pass it on as Bar<T> in all cases. I'm happy for the transformation to be XSLT or programmatic. I don't care what happens to messages received that aren't of the type Foo<T>.
I wish to use WCF as it provides a lot of OOTB functionality (e.g. its support for numerous bindings). It's not practical to implement a WCF service with numerous boilerplate methods to transform each closed generic (Foo<Class1> -> Bar<Class1>; Foo<Class2> -> Bar<Class2>; etc), as this would require recompilation/redeployment every time a new message type was to be routed.
To the best of my knowledge, WCF doesn't handle open generics and WCF Routing doesn't facilitate content transformation OOTB. That said, System.ServiceModel.Routing.RoutingService obviously intercepts WCF calls in some non-specific form, so I was hoping to leverage the same pattern to achieve my goal. Can anyone please provide direction on how to do this (or indicate why it's not possible)?
As I suggested in my comments on the question, there is a solution to this using the IDispatchMessageInspector. Please find below an extremely dumbed-down version of what I ended up writing (easier than me posting the code for 20 classes). If anyone wants a full solution implementing this code in a significantly cleaner and more advanced manner, let me know and I'll put my demo up on CodeProject. For now, I'll presume you're happy with a snippet of the guts.
The Console commands can obvious be removed (they're just so you can debug if you're self-hosting).
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (request == null || request.IsEmpty)
return null;
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(request);
Console.ResetColor();
// Load the request into a document.
XPathDocument document;
MemoryStream stream;
using (stream = new MemoryStream())
{
using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream))
{
request.WriteMessage(writer);
writer.Flush();
stream.Position = 0L;
document = new XPathDocument(stream);
}
}
// Load the XSLT.
XslCompiledTransform transformer = new XslCompiledTransform();
transformer.Load("RequestTransformation.xslt");
// Transform the document.
byte[] transformedDocument;
using (stream = new MemoryStream())
{
transformer.Transform(document, null, stream);
transformedDocument = stream.ToArray();
}
// Construct new request from tranformed document.
stream = new MemoryStream(transformedDocument);
XmlReader reader = XmlReader.Create(stream);
Message modifiedMessage = Message.CreateMessage(reader, int.MaxValue, request.Version);
modifiedMessage.Properties.CopyProperties(request.Properties);
request = modifiedMessage;
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(new System.Text.UTF8Encoding(false).GetString(transformedDocument));
Console.ResetColor();
return null;
}
I want to send an image from java server (Restful Jax-rs).
My client is Android.
#GET
public Response getUserImage() {
byte[] image =new byte[1024];
return Response.ok(image, MediaType.APPLICATION_OCTET_STREAM).header("content-attachment; filename=image_from_server.png") .build();
But here one download box is coming.
So I want to download without download box, when I run the request URL on browser it should open automatically.
Thanks.
I believe that's because you specified application/octet-stream.
I think you should use image/jpeg or image/png.
#GET
#Produces({"image/png"})
public Response getUserImage() {
final byte[] image = ...;
// say your image is png?
return Response.ok().entity(new StreamingOutput(){
#Override
public void write(OutputStream output)
throws IOException, WebApplicationException {
output.write(image);
output.flush();
}
}).build();
}
You can encode the image with base 64 encoding, wrap the base 64 encoded string in xml or json and send that over rest. On the rest client extract the base 64 encoded string and decode it to get the final image. This preserves all the file meta data as well and but the only down side is 30% increase in image size.
I have tried the same with Restlet rest api, am pretty sure its possible over JAX-RS as well.
I'm working with a RESTful WCF service. One of the service methods returns byte[] (which contains a file).
On the client side, I have some code that uses the WebRequest class to invoke that particular service method. Using the WebRequest, I'm getting the response stream like:
Stream stream = webReq.GetResponse().GetResponseStream();
From this stream, I am then reconstructing a byte[] and then outputting the File locally. The problem is that the reconstructed file on the client-side doesn't resemble the file that was returned from the service side (I get a corrupt PDF file that is much larger in size than the one sent from the service side). Just before the service method returns the byte[], I outputted that byte[] to disk on the service side and it created the file fine... This points to something going wrong between that method returning the byte[] and my client side reconstructing the byte[] from a Stream on the client side... to reconstruct the byte[] from the Stream, I'm using the following method which someone posted in the past on stackoverflow:
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Any ideas what could be going wrong?
I guess that the response from the server contains some envelope in addition to the raw bytes. Like a XML envelope or something. Which would of course suppose that the bytes are base64 encoded string in the response because you cannot store binary data into XML. It would also explain why you are getting a bigger buffer on the client than the actual PDF that the server has sent.
This will of course depend on what binding your WCF service uses and how is it configured. When you dump the contents of the MemoryStream you are reading on the client what exactly do you see? This should give you further hints on how the actual PDF file is encoded in the HTTP response body.
I have created a WCF service for uploading images , which accepts System.IO.Stream as input parameter and am using streaming. When I added the service reference in Silverlight project then it automatically changed the parameter of my WCF method from System.IO.Stream to byte[]. Can anyone suggest if there is a way around this so that I can get System.IO.Stream type rather than byte[].
Thanks in advance
Silverlight does not support transfer mode streamed: http://forums.silverlight.net/forums/t/119340.aspx
So I think that you are stuck with getting a byte array.
Can you verify that you're not hitting one of the reader quotas in the service? You can try increasing all of them to see if this solves your problem.
I think you should set the transferMode property of your basicHttpBinding to the correct value, as described in this article. And then add the service reference to your Silverlight application again.
http://blogs.msdn.com/b/carlosfigueira/archive/2010/07/08/using-transfermode-streamedresponse-to-download-files-in-silverlight-4.aspx
Even I was struggling with the same issue. At last I got a solution by myself. All you can do is:
declare the accepting parameter as string array in the WCF Service.
convert the byte array into string array at client place.
After Sending the converted byte array as string array again convert back it into byte array.
eg. at the WCF side:
[DataContract]
Class FileInfo
{
[DataMember]
string filename;
[DataMember]
string[] StrArr;
}
the receiving function:
public void uploadFile(FileInfo fi)
{
int len=fi.StrArr.len;
byte[] myFileByte=new byte[len];
for(int i=0;i<len;i++)
{
myFileByte[i]=Convert.ToByte(fi.StrArr[i]);
}
//your uploaded File buffer is ready as myFileByte
//proceeding operations are most welcome here......
.........
}
At Client Side:
public void UploadMyFile()
{
//Take the InputStream from the selected File as iStream;
int len=(int)iStream.length;
byte[] buffer=new byte[len];
string[] MyStrArr=new string[len];
for(int i=0;i<len;i++)
{
MyStrArr[i]=Convert.ToString(buffer[i]);
}
//Here your string array is ready to send to the WCF Service....
//I m confident this code will work perfectly with some file limitation consideartions.
}