Web API 2 upload large json strings - c#

I'm after some advice on what the best strategy is for posting a large object from a client to a web api post method on the server? Is there a standard strategy that is followed? My class that I'm posting to the server is as follows:-
public class DataSetValidationRequest
{
public string DataSetName { get; set; }
public string JsonString { get; set; }
}
The JsonString property essentially holds a serialized DataTable which can contain ~200,000 rows (when this string is saved down to disk, it amounts to ~30mb)
I'm currently using the deflate algorithm to compress the DataSetValidationRequest object down before I send it to the server and then I decompress the compressed stream on the server back into the original stream. I then use JsonConvert to parse the stream back into the request object but I get OutOfMemoryExceptions. Is there a better way to do this in chunks somehow? I thought about splitting the data up into multiple chunks and making multiple requests to the server but then I would need to implement some form of transaction control to ensure that all the data is successfully transferred across the wire and it just doesn't seem like a great idea!
Any advice would be greatly appreciated.

Related

How to read data from WebClient.UploadData

First time posting! I've been breaking my head on this particular case. I've got a Web application that needs to upload a file towards a web-api and receive an SVG file (in a string) back.
The web-app uploads the file as follows:
using (var client = new WebClient())
{
var response = client.UploadFile(apiUrl, FileIGotEarlierInMyCode);
ViewBag.MessageTest = response.ToString();
}
Above works, but then we get to the API Part:
How do I access the uploaded file? Pseudocode:
public string Post([FromBody]File f)
{
File uploadedFile = f;
String svgString = ConvertDataToSVG(uploadedFile);
return s;
}
In other words: How do I upload/send an XML-file to my Web-api, use/manipulate it there and send other data back?
Thanks in advance!
Nick
PS: I tried this answer:
Accessing the exact data sent using WebClient.UploadData on the server
But my code did not compile on Request.InputStream.
The reason Request.InputStream didn't work for you is that the Request property can refer to different types of Request objects, depending on what kind of ASP.NET solution you are developing. There is:
HttpRequest, as available in Web Forms,
HttpRequestBase, as available in MVC Controllers
HttpRequestMessage, as available in Web API Controllers.
You are using Web API, so HttpRequestMessage it is. Here is how you read the raw request bytes using this class:
var data = Request.Content.ReadAsByteArrayAsync().Result;

Returning Images from WebApi

I am making a Web Api and I need to return multiple images to the client. I am currently using a Base64 string for each image but this results in each request taking far too long. Is there a better, more efficient way of returning images?
This is the code I am using:
Controller:
public LearningUnits GetLearningUnits([FromODataUri]Guid key)
{
var record = db.LearningUnits.SingleOrDefault(inst => inst.LearningUnitId == key);
record.ImageURLPath = ImageHandler.ImageToByteArrayFromFilePath(record.ImageURLPath);
return record;
}
ImageToByteArray Method:
public static string ImageToByteArrayFromFilePath(string imagefilePath)
{
byte[] imageArray = File.ReadAllBytes(imagefilePath);
string baseImage = Convert.ToBase64String(imageArray);
return baseImage;
}
If the endpoint returns json, then there is no other way, beyond base64, how to embed binaries within the response. But it is definitely a bad idea due to the performance issues. May be for some icons it would be ok, but for larger images its not suitable.
So the best solution here, is to return the url to the image. And the client will make further request to get raw bytes for the image.
Also worth to mention, the image url can not only be the path to the static file, but also a path to some webapi endpoint, which, for instance, gets the image bytes by the resource id and sends the client raw binary back, and not a json string.
The solution is to use media formatters, so that when the Web API is queried with a particular type, you'll then receive the actual binary stream of the particular type.
http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters
This is the standard RESTful pattern; you have the same URL, but when you want a JSON record for the data, you accept-type:application/json, but you change your MIME request type to image/png or something similar when you want that media type.
More can be found here:
How to provide custom mediatype formats for OData Api
Odata also implicitly supports it here: https://msdn.microsoft.com/en-us/library/system.web.http.odata.formatter.odatamediatypeformatter(v=vs.118).aspx

How to read Json data from Instagram RealTime API updates

I'm trying to use Instagram RealTime API to get updates whenever someone posts an image with an specific tag, I've followed all the steps, but I'm having problems to read the json data that is sent to my callback url. According to instagram's documentation :
When someone posts a new photo and it triggers an update of one of
your subscriptions, we make a POST request to the callback URL that
you defined in the subscription. The post body contains a raw text
JSON body with update objects.
I'm using C# and MVC 5, here's my code to read the "raw text JSON body", note that I'm saving the json string in a text file.
[HttpPost]
public HttpStatusCodeResult Receive()
{
string json;
using (var reader = new StreamReader(Request.InputStream))
{
json = reader.ReadToEnd();
}
File.WriteAllText(Path.Combine(Server.MapPath("~/"), "test.txt"), json);
return new HttpStatusCodeResult(200);
}
The problem is, when I receive the request, the file is create, but is always empty. There's something wrong with my code? Could it be some problem with Instagram's API? I'd appreciate some help with this.
Found it! Just set InputStream position to zero and it works!

Correct way to return a C# object to Android via RESTful JSON webservice

When returning data from a WCF RESTful webservice via JSON to an android app, currently I've designed the webservice to follow the Request/REsponse pattern, ie
public GetStorySeedsResponse GetStorySeeds(GetStorySeedsRequest request)
{
...
}
This is ok for the request, I create a JSONObject in Android and set that as the Post body, and WCF seems to receive it and decode it into a GetStorySeedsRequest object. The problem is when I return the above response object, this contains a List<StorySeed>() where the StorySeed class has a whole number of parameters, including image data. Currently when I try and decode this as a JSONObject in Android like so
String responseEntity = EntityUtils.toString(response.getEntity());
JSONObject seeds = new JSONObject(responseEntity);
It is timing out and the array length seems to blow out the IDE, so I'm assuming I'm handling the response to Android via JSON incorrectly.
What is the correct way to do this?

WCF Restful Service - Send File with Multiple fields in one requert

I am in the process of developing a WCF Restful Service. One of the requirements of the WCF is to allow a client to upload an image file and several input parameters that may contain multiple values.
I thought of several ways of sending a file with input parameters in one request. I am not sure what the best approach would be.
1) Accept a stream that contains a multipart form-data stream. A huge disadvantage with this approach is that I have to write a multipart parser. (aspNetCompatibilityEnabled="false")
[WebInvoke (UriTemplate = "Account",Method = "POST")]
public String Account(System.IO.Stream stream) {
MultiPartParser(stream);
}
2) Send the file as a stream and send other data in the QueryString. Only issue with this approach is that the values may be multi-line text data.
[WebInvoke (UriTemplate = "Account?input1={val1}&input2={val2}",Method = "POST")]
public String Account(System.IO.Stream stream) {
}
3) Convert the file as a Base64 string and encapsulate it in JSON or XML and send it with the other input parameters. Are there any limitations of this approach?
[WebInvoke (UriTemplate = "Account",Method = "POST")]
public String Account(String ImageFile, String input1, String input2) {
}
What is the best approach? Thank you for your time.
As always, the asnwer is "it depends". You mentioned the pros/cons of each approach, so it will really depend on your situation.
Pro: the file contents are not encoded (i.e., no size bloat). Con: you need to write the multipart parser on the server (and to package the request on the client), the multipart headers will add some (often non-significant) overhead to the requests
Pro: simple, operation is easy to write. Con: may need to URL-encode chars such as new line; size limitation of URIs may be an issue if additional data is large
Pro: No need for encoding, operation is easy to write. Con: size bloat due to base64-encoding (you can declare the parameter as byte[] so the decoding is done automatically for you), client will need to encode the file content, as well as wrap all the parameters from the request.
There's also a fourth option, which is to pass the additional parameters as HTTP headers.
Pro: no size limitation as in the URIs. Con: parameters are not explicitly declared, need to fetch them from the headers using the WebOperationContext, and still need to URI-encode chars outside the 0x20-0x7E range

Categories

Resources