Error 500 Server POST MultiPart Data WP8 - c#

I need some help for posting a MultipartFormDataContentto my web service.
I have an error 500 but I didn't know why.
There is a mean to see what kind of data i send with visual studio? Or there is a mistake in my code?
My c# code Client
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent())
{
MemoryStream s = new MemoryStream();
StreamWriter writer = new StreamWriter(s);
writer.Write(json);
writer.Flush();
s.Position = 0;
content.Add(new StreamContent(s), "JSON");
foreach (KeyValuePair<String, byte[]> pair in data)
{
Stream stream = new MemoryStream(pair.Value);
content.Add(new StreamContent(stream),"uploaded");
}
using (
var message =
await client.PostAsync(urlFinal, content))
{
var input = await message.Content.ReadAsStringAsync();
}
}
}
And the Web Service part in JAVA
public static Result Method() {
MultipartFormData data = request().body().asMultipartFormData();
return ok(toJson(MyObject.myMethode(data)));
}
public static int myMethode(MultipartFormData data) {
FilePart JSON = data.getFile("JSON");
FilePart picture = data.getFile("uploaded");
return 1;
}

Related

Unzip .zip File without Writing to Disc from Response c#

Let me preface by stating that I' somewhat new to dealing with zipping/unzipping/reading/reading files. That being said, I'm doing a PoC that will retrieve data via api and write the responses to a database. The response is a zip file and inside this zip is the json data I will be reading and writing to the database.
I'm having some trouble unzipping and reading the information. Please find the code below:
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(baseUrl),
Headers =
{
{ "X-API-TOKEN", apiKey },
},
};
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
// here is where I am stuck - not sure how I would unzip and read the contents
}
Thanks
Assuming you actually have a .zip file, you don't need a MemoryStream, you just need to pass the existing stream to ZipArchive
static HttpClient client = new HttpClient(); // always keep static client
async Task GetZip()
{
using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(baseUrl))
{
Headers = {
{ "X-API-TOKEN", apiKey },
},
};
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using var stream = await response.Content.ReadAsStreamAsync();
await ProcessZip(stream);
}
async Task ProcessZip(Stream zipStream)
{
using var zip = new ZipArchive(zipStream, ZipArchiveMode.Read);
foreach (var file in zip.Entries)
{
using var entryStream = file.Open();
await ....; // do stuff here
}
}
You can convert body to a byte array and then unzip it using MemoryStream.
byte[] bytes = Encoding.ASCII.GetBytes(body);
using (var mso = new MemoryStream(bytes)) {
using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}

Get the file postion of each file into a stream

I am sending multiples files from my web api but I want to read each part of the stream to convert him into a byte array , then at the end I have a list of byte[], and I can save each files:
[Route("GetFiles")]
public HttpResponseMessage GetFile([FromUri] List<string> filesNames)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
if (filesNames.Count == 0)
return Request.CreateResponse(HttpStatusCode.BadRequest);
var content = new MultipartContent();
filesNames.ForEach(delegate (string fileName)
{
string filePath = System.Web.Hosting.HostingEnvironment.MapPath("~/Uploads/" + fileName);
byte[] pdf = File.ReadAllBytes(filePath);
content.Add(new ByteArrayContent(pdf));
response.Headers.Add(fileName, fileName);
});
var files = JsonConvert.SerializeObject(content);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response = Request.CreateResponse(HttpStatusCode.OK, content);
return response;
}
Here is how I get one file into a stream, then convert him into a byte array to report the process percentage :
public static async Task<byte[]> CreateDownloadTaskForFile(string urlToDownload, IProgress<DownloadBytesProgress> progessReporter)
{
int receivedBytes = 0;
int totalBytes = 0;
WebClient client = new WebClient();
using (var stream = await client.OpenReadTaskAsync(urlToDownload))
{
byte[] buffer = new byte[BufferSize];
totalBytes = Int32.Parse(client.ResponseHeaders[HttpResponseHeader.ContentLength]);
using (MemoryStream memoryStream = new MemoryStream())
{
for (; ; )
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
memoryStream.Write(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
await Task.Yield();
break;
}
receivedBytes += bytesRead;
if (progessReporter != null)
{
DownloadBytesProgress args = new DownloadBytesProgress(urlToDownload, receivedBytes, totalBytes);
progessReporter.Report(args);
}
}
return memoryStream.ToArray();
}
}
}
How do I get the position of a stream for each files send ?
Update :
I made a HttpResponseMessage like this :
[Route("GetFiles")]
public HttpResponseMessage GetFiles([FromUri] List<string> filesNames)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
if (filesNames.Count == 0)
return Request.CreateResponse(HttpStatusCode.BadRequest);
var content = new MultipartFormDataContent();
filesNames.ForEach(delegate (string fileName)
{
string filePath = System.Web.Hosting.HostingEnvironment.MapPath("~/Uploads/" + fileName);
byte[] pdf = File.ReadAllBytes(filePath);
content.Add(new ByteArrayContent(pdf), fileName);
});
response = Request.CreateResponse(HttpStatusCode.OK, content);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}
But from my device side : When I am trying to run the request But there is nothing on the response content :
using (var httpResponseMessage = await httpClient.GetAsync(urlToDownload + filesNamesArg))
{
var streamProvider = new MultipartMemoryStreamProvider();
streamProvider = httpResponseMessage.Content.ReadAsMultipartAsync().Result;
}
Could you show me some docs or advice ?
What?
This answer provides a 100% working example for:
Serving multiple files as a single response from a web API using multipart/mixed content type,
Reading the file contents on the client by parsing the response of the web API implemented in 1
I hope this helps.
Server:
The server application is a .Net 4.7.2 MVC project with web API support.
The following method is implemented in an ApiController and returns all the files under the ~/Uploads folder in a single response.
Please make note of the use of Request.RegisterForDispose extension to register the FileStreams for later disposal.
public async Task<HttpResponseMessage> GetFiles()
{
string filesPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Uploads");
List<string> fileNames = new List<string>(Directory.GetFiles(filesPath));
var content = new MultipartContent();
fileNames.ForEach(delegate(string fileName)
{
var fileContent = new StreamContent(File.OpenRead(fileName));
Request.RegisterForDispose(fileContent);
fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(fileContent);
});
var response = new HttpResponseMessage();
response.Content = content;
return response;
}
The response's Content-Type header shows as Content-Type: multipart/mixed; boundary="7aeff3b4-2e97-41b2-b06f-29a8c23a7aa7" and each file is packed in different blocks separated by the boundary.
Client:
The client application is a .Net Core 3.0.1 console application.
Please note the synchronous usage of the async methods. This can be easily changed to asynchronous using await, but implemented like this for simplicity:
using System;
using System.IO;
using System.Net.Http;
namespace console
{
class Program
{
static void Main(string[] args)
{
using (HttpClient httpClient = new HttpClient())
{
using (HttpResponseMessage httpResponseMessage = httpClient.GetAsync("http://localhost:60604/api/GetImage/GetFiles").Result)
{
var content = (HttpContent)new StreamContent(httpResponseMessage.Content.ReadAsStreamAsync().Result);
content.Headers.ContentType = httpResponseMessage.Content.Headers.ContentType;
MultipartMemoryStreamProvider multipartResponse = new MultipartMemoryStreamProvider();
content.ReadAsMultipartAsync(multipartResponse);
for(int i = 0; i< multipartResponse.Contents.Count;i++)
{
Stream contentStream = multipartResponse.Contents[i].ReadAsStreamAsync().Result;
Console.WriteLine("Content {0}, length {1}", i, contentStream.Length);
}
}
}
}
}
}

How to call API using MultiPartFormDataContetnt and get a response in C#

I Have an API that takes an IFormFile and returns an IActionsresult with some values. When i call the API with postman it works fine I get a nice 200 Ok response with the data I am looking for. But when I trie to call the API from within another program I get nothing in response. I get no errors, it's just that the program seems to wait for a response that never shows. I am simply wondering if anyone can see the problem with this code any help would be greately apriciated.
Both my API and my program is on the same computer and here is the code i use to call the API.
public static async Task<string> Calculate()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var content = new MultipartFormDataContent())
{
var img = Image.FromFile("path");
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.jpeg);
content.Add(new StreamContent(new MemoryStream(ms.ToArray())), "image", "myImage.jpg");
using (var response = await client.PostAsync($"http://localhost:####/api/1.0/###", content))
{
var responseAsString = await response.Content.ReadAsStringAsync();
return responseAsString;
}
}
}
}
Successful request using postman:
Post Request using Postman
Try this-
using (var client = new HttpClient())
{
client.BaseAddress = new Uri($"http://localhost/###");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var content = new MultipartFormDataContent())
{
content.Add(new StreamContent(new MemoryStream(image)), "image", "myImage.jpg");
using (var response = await client.PostAsync($"http://localhost:#####/###/###/###", content).ConfigureAwait(false))
{
if (response.StatusCode == HttpStatusCode.OK)
{
var responseAsString = response.Content.ReadAsStringAsync().Result;
var receiptFromApi = JsonConvert.DeserializeObject<Receipt>(responseAsString);
var metadata = new metadata(bilaga)
{
Value1 = fromApi.Value1.Value,
Value2 = fromApi.Value2.Value,
Value3 = fromApi.Value3.Value,
Value4 = fromApi.Value4.Value
};
return metadata;
}
else
{
throw new InvalidProgramException();
}
}
}
}
reference- https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

uploading large file c# http post

I have a requirement to upload large files (upto 2GB) from my .NET web application to a java web service which in turn consumes a .jar file.
The java webservice API accepts MultipartFormDataContent as its parameter.
Problem I am facing is, I am unable to load the entire 2GB into a byte array as it throws "SystemOutOfMemoryException" when I attempt to upload a file anything larger that 300MB.
I also tried BufferedReader, StreamWriter but in vain.
Provided my code below for your reference:
public bool SendMessage(Dictionary<string, byte[]> files, string fromAddress, string toAddresses, string ccAddresses, string subject, string body)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
Dictionary<string, long> fileSizes = new Dictionary<string, long>();
Dictionary<string, ByteArrayContent> fileContent = new Dictionary<string, ByteArrayContent>();
HttpContent fileSizesContent = null;
try
{
HttpContent messageContent = new StringContent(jss.Serialize(new
{
to = toAddress,
cc = ccAddresses,
subject = subject,
body = "Test"
}));
if (files != null)
{
foreach (var entry in files)
{
fileSizes.Add(entry.Key, entry.Value.Length);
fileContent.Add(entry.Key, new ByteArrayContent(entry.Value));
}
fileSizesContent = new StringContent(jss.Serialize(fileSizes));
}
using (var client = new HttpClient())
{
using (var formData = new MultipartFormDataContent())
{
if (fileContent.Count > 0)
{
foreach (var entry in fileContent)
{
formData.Add(entry.Value, "attachments", entry.Key);
}
formData.Add(fileSizesContent, "fileSizes");
}
formData.Add(messageContent, "message");
var response = client.PostAsync(<java web service url>, formData).Result;
if (!response.IsSuccessStatusCode)
{
return false;
}
return true;
}
}
}
catch (Exception ex)
{
return false;
}
}
Issue is: I am unable to opulate the parameter ByteArrayContent as it throws SystemOutOfMemoeyException for files >300MB.
Please help me out.
Thanks.

Transfer data withou buffer from MultipartMemoryStreamProvider to an output stream

I am doing kind of a proxy. A client uploads file to Web API method, this web API method sends file to some other HTTP location. I have this code:
[HttpPost]
public async Task mPost(string id)
{
var provider = new MultipartMemoryStreamProvider();
var r = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(async t =>
{
var file = provider.Contents.First();
var buffer = await file.ReadAsByteArrayAsync();
var stream = new MemoryStream(buffer);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.ExpectContinue = false;
using (var content = new StreamContent(stream))
{
using (var req = new HttpRequestMessage(HttpMethod.Put, "target_url"))
{
req.Content = content;
using (HttpResponseMessage resp = client.SendAsync(req).Result)
{
resp.EnsureSuccessStatusCode();
}
}
}
}
});
It works, but what i don't like is that at some point (var buffer = await file.ReadAsByteArrayAsync();) I have all file data in server's memory.
How to transfer data directly from input stream to output without keeping it in memory buffer?

Categories

Resources