I am trying to post one or more files from my local machine to an API with HttpClient, MultipartFormContent and ContentType: "application/octet-stream" but when i do postSync and call an API from a local Winform application, the result of the task (var response = task.Result;) says that it is "Unsopported Type File" StatusCode: 415. I tried with ByteArrayContent but was still unsuccessful.
This is my code:
bool Upload(string url, string path, string localFilename, string fileName, string projectId, string folderId)
{
Boolean isFileUploaded = false;
string xapiKey = "-----";
try
{
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(url);
httpClient.DefaultRequestHeaders.Add("x-api-key", xapiKey);
var fileInfo = new FileInfo(localFilename);
FileUpload uploadResult = null;
bool _fileUploaded = false;
//Extract content file
FileStream fileStream = File.OpenRead(path);
var streamContent = new StreamContent(fileStream);
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
streamContent.Headers.ContentDisposition.FileName = "\"" + Path.GetFileName(path) + "\"";
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octetstream");
string boundary = Guid.NewGuid().ToString();
MultipartFormDataContent content = new MultipartFormDataContent(boundary);
content.Headers.Remove("Content-Type");
content.Headers.TryAddWithoutValidation("Content-Type", "mulitpart/form-data; boundary=" + boundary);
content.Add(streamContent);
//content.Add(new StreamContent(fileStream), "\"file\"", string.Format("\"{0}\"", fileName + fileInfo.Extension));
Task taskUpload = httpClient.PostAsync(url, content).ContinueWith(task =>
{
if (task.Status == TaskStatus.RanToCompletion)
{
var response = task.Result;
if (response.IsSuccessStatusCode)
{
uploadResult = response.Content.ReadAsAsync<FileUpload>().Result;
if (uploadResult != null)
_fileUploaded = true;
}
}
fileStream.Dispose();
});
taskUpload.Wait();
if (_fileUploaded)
isFileUploaded = true;
httpClient.Dispose();
}
catch (Exception ex)
{
isFileUploaded = false;
throw new Exception(ex.Message);
}
return isFileUploaded;
}
Related
The following code works:
string UploadWithHttpRequest(string url, string filePath, string fileName)
{
try
{
byte[] fileByteArray = File.ReadAllBytes(filePath);
string formDataBoundary = $"----------{Guid.NewGuid():N}";
string contentType = "multipart/form-data; boundary=" + formDataBoundary;
byte[] formData = GetMultipartFormDataForUpload(fileByteArray, fileName, contentType, formDataBoundary);
var request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = contentType;
request.UserAgent = Credentials.UserName;
request.CookieContainer = new CookieContainer();
request.ContentLength = formData.Length;
request.Credentials = Credentials;
using (Stream RequestStream = request.GetRequestStream())
{
RequestStream.Write(formData, 0, formData.Length);
RequestStream.Close();
}
var response = request.GetResponse() as HttpWebResponse;
var ResponseReader = new StreamReader(response.GetResponseStream());
string FullResponse = ResponseReader.ReadToEnd();
response.Close();
return FullResponse;
}
catch (Exception ex)
{
throw ex;
}
}
byte[] GetMultipartFormDataForUpload(byte[] byteArray, string fileName, string contentType, string Boundary)
{
Stream FormDataStream = new MemoryStream();
string Header = string.Format("--{0}" + Environment.NewLine + "Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\""
+ Environment.NewLine + Environment.NewLine, Boundary, "file", fileName);
FormDataStream.Write(Encoding.UTF8.GetBytes(Header), 0, Encoding.UTF8.GetByteCount(Header));
FormDataStream.Write(byteArray, 0, byteArray.Length);
string Footer = Environment.NewLine + "--" + Boundary + "--" + Environment.NewLine;
FormDataStream.Write(Encoding.UTF8.GetBytes(Footer), 0, Encoding.UTF8.GetByteCount(Footer));
FormDataStream.Position = 0L;
var FormData = new byte[(int)(FormDataStream.Length - 1L + 1)];
FormDataStream.Read(FormData, 0, FormData.Length);
FormDataStream.Close();
return FormData;
}
But instead of using HttpRequest I'd like to use HttpClient and instead of doing all the encoding manually (especially in GetMultipartFormDataForUpload) I'd like to use the class MultipartFormDataContent. When I try this, I always get a 500 from the server. This is what I have tried so far:
async Task<string> UploadWithHttpClient(string url, string filePath, string fileName)
{
try
{
byte[] fileByteArray = File.ReadAllBytes(filePath);
var content = new MultipartFormDataContent("------------" + Guid.NewGuid());
var byteArrayContent = new ByteArrayContent(fileByteArray, 0, fileByteArray.Length);
//Option 1
byteArrayContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = fileName
};
//Option 2
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "file",
FileName = fileName
};
content.Add(byteArrayContent, "file");
var client = new HttpClient();
var response = await client.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
return result;
}
catch (Exception ex)
{
throw ex;
}
}
What is the right way to replace the httprequest with the httpclient?
Where does the content-disposition header belong (is one of the options I have tried correct)? If yes what else is my problem?
the following code worked for me in the end:
async Task<string> UploadWithHttpClient(string url, string filePath, string fileName)
{
try
{
byte[] fileByteArray = File.ReadAllBytes(filePath);
var content = new MultipartFormDataContent("------------" + Guid.NewGuid());
var byteArrayContent = new ByteArrayContent(fileByteArray);
byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf");
content.Add(byteArrayContent, "\"file\"", $"\"{fileName}\"");
var client = new HttpClient();
var response = await client.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
return result;
}
catch (Exception ex)
{
throw ex;
}
}
```
Need to develop C# HttpClient PUT request for uploading image. Here is the curl request working well.
curl --location --request PUT 'https://somewheretest.com/abcd/efgh' \
--header 'Content-Type: application/octet-stream' \
--header 'Range: bytes=0-99999' \
--header 'Content-Length: 100000' \
--data-binary '#D:\image.jpg'
I've tried with HttpClient sending request PutAsync with MultipartFormDataContent, gets response Invalid Range. Any suggestion appreciated for the valid way to request uploading image to the server in C# UWP.
I've followed sort of ways. But only CURL is working perfectly. All other's code replies Invalid Range.
1st#
public static async Task<bool> fileUpload(string filePath, long fileSize)
{
string url = "";
try
{
string range = "bytes=0-" + (fileSize - 1).ToString();
using (var client = new System.Net.Http.HttpClient())
{
//client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36");
//client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/octet-stream");
//client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", fileSize.ToString());
//client.DefaultRequestHeaders.TryAddWithoutValidation("Range", range);
Uri uri = new Uri(url);
using (var content = new MultipartFormDataContent())
{
FileStream fs = File.OpenRead(filePath);
var streamContent = new StreamContent(fs);
//HttpContent contents = new StringContent(filePath);
//streamContent.Headers.TryAddWithoutValidation("Content-Type", "application/octet-stream");
//streamContent.Headers.TryAddWithoutValidation("Content-Length", fileSize.ToString());
//streamContent.Headers.TryAddWithoutValidation("Range", range);
//content.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
content.Add(new StringContent("Content-Type"), "application/octet-stream");
content.Add(new StringContent("Range"), range);
content.Add(new StringContent("Content-Length"), fileSize.ToString());
content.Add(streamContent, "file", Path.GetFileName(filePath));
using (var message = await client.PutAsync(uri, content))
{
var input = await message.Content.ReadAsStringAsync();
//var result = JsonSerializer.Deserialize<FileUploadResult>(input);
Debug.WriteLine($"Response File Upload: {input}");
return true;
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
2nd#
public static async Task<bool> UploadMultipart(byte[] file, string filename, string url)
{
string contentType = "application/octet-stream";
var webClient = new WebClient();
string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
webClient.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
var fileData = webClient.Encoding.GetString(file);
var package = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n{3}\r\n--{0}--\r\n", boundary, filename, contentType, fileData);
var nfile = webClient.Encoding.GetBytes(package);
byte[] resp = webClient.UploadData(url, "PUT", nfile);
return true;
}
3rd#
public static async Task<bool> fileUpload(ValueSet issueToken, string filePath, byte[] fileInByte)
{
int fileSize = fileInByte.Length;
//string range = "bytes=0-" + (fileSize - 1).ToString();
string url = "";
var httpClient = new System.Net.Http.HttpClient();
try
{
//StreamContent streamContent = new StreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
StreamContent streamContent = new StreamContent(new MemoryStream(fileInByte));
streamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
streamContent.Headers.ContentRange = new System.Net.Http.Headers.ContentRangeHeaderValue(0, fileSize - 1);
streamContent.Headers.ContentLength = fileSize;
using (var message = await httpClient.PutAsync(url, streamContent))
{
var input = await message.Content.ReadAsStringAsync();
//var result = JsonSerializer.Deserialize<FileUploadResult>(input);
Debug.WriteLine($"Response File Upload: {input}");
return true;
}
}
catch(Exception ex)
{
Debug.WriteLine(ex);
return false;
}
}
The only reason for not working, System.Net.Http.HttpClient behaves differently in UWP which I got from wireshark. And another reason server has very old configuration which does not support multipart in the request. Anyway here is my solution with Windows.Web.Http.HttpClient.
public static async Task<bool> fileUpload(ValueSet issueToken, string filePath, byte[] fileInByte)
{
int fileSize = fileInByte.Length;
string range = "bytes=0-" + (fileSize - 1).ToString();
string url = "https://somewheretest.com/abcd/efgh";
var httpClient = new Windows.Web.Http.HttpClient();
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Range", range);
try
{
HttpStreamContent streamContent = new HttpStreamContent(new FileStream(filePath, FileMode.Open, FileAccess.Read));
streamContent.Headers.ContentType = new HttpMediaTypeHeaderValue("application/octet-stream");
using (var message = await httpClient.PutAsync(new Uri(url), streamContent))
{
var output = await message.Content.ToString();
Debug.WriteLine($"Response File Upload: {output}");
return true;
}
}
catch(Exception ex)
{
Debug.WriteLine(ex);
return false;
}
}
The Json string has this structure:
{"CODIGO_AGENCIA":"HN001001","CODIGO_USUARIO":"some user","CODIGO_CATEGORIA":1}
This is the parameter asked by the WS:
public async Task SubirImagenCategoria(string JsonString, HttpPostedFileBase Archivo)
//This is what I got so far, the web service returns error that the json string is empty, I am completely lost on how to proceed.
public static async Task<CustomJsonResult> SubirImagenCategoría(int CodigoCategoria, HttpPostedFileBase Archivo)
{
usuario = UtilClass.GetUsuarioSesion();
var modelo = new SUBIR_IMAGEN_CAT();
modelo.CODIGO_AGENCIA = usuario.CodigoAgencia;
modelo.CODIGO_USUARIO = usuario.Nombre;
modelo.CODIGO_CATEGORIA = 1;
CustomJsonResult result = new CustomJsonResult();
try
{
var JsonString = JsonConvert.SerializeObject(modelo);
var formContent = new MultipartFormDataContent("form-data");
StringContent jsonPart = new StringContent(JsonString.ToString());
jsonPart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
jsonPart.Headers.ContentType = new MediaTypeHeaderValue("application/json");
formContent.Add(jsonPart);
/* byte[] Bytes = new byte[Archivo.InputStream.Length + 1];
Archivo.InputStream.Read(Bytes, 0, Bytes.Length);
var fileContent = new ByteArrayContent(Bytes);
fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data") { FileName = Archivo.FileName };
formContent.Add(fileContent);*/
StreamContent filePart = new StreamContent(Archivo.InputStream);
filePart.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
filePart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
filePart.Headers.ContentDisposition.FileName = Archivo.FileName;
formContent.Add(filePart);
var test = formContent;
/*HttpContent jsonParam = new StringContent(JsonString);
HttpContent fileStream = new StreamContent(Archivo.InputStream);
formData.Add(jsonParam, "JsonString", "JsonString");
formData.Add(fileStream, "Archivo", "Archivo");*/
/*var values = new Dictionary<string, string>
{
{ "JsonString", ("{\"CODIGO_AGENCIA\":"+usuario.CodigoAgencia+",\"CODIGO_USUARIO\":\""+usuario.Nombre+"\" ,\"CODIGO_CATEGORIA\":\""+CodigoCategoria+"\"}") },
};
HttpContent myBody = new FormUrlEncodedContent(values);*/
var formData = new MultipartFormDataContent();
String url = DataEntityLayer.Database.Environment.getFinalUrl(Util.UtilWS.subirImagenesCategorias);
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(url, formContent);
string stringContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<CustomJsonResult>(stringContent);
}
catch (Exception ex)
{
result.Error = ex.Message;
}
return result;
}
This is how I tested the WS from postman
After many attempts and almost having a mental & emotional breakdown, it finally worked.
Example 3 from this link worked for me.
public static UsuarioSesion usuario = new UsuarioSesion();
public static async Task<CustomJsonResult> SubirImagenCategoría(int CodigoCategoria, HttpPostedFileBase Archivo)
{
usuario = UtilClass.GetUsuarioSesion();
var modelo = new SUBIR_IMAGEN_CAT();
modelo.CODIGO_AGENCIA = usuario.CodigoAgencia;
modelo.CODIGO_USUARIO = usuario.Nombre;
modelo.CODIGO_CATEGORIA = CodigoCategoria;
CustomJsonResult result = new CustomJsonResult();
try
{
var JsonString = JsonConvert.SerializeObject(modelo);
var formContent = new MultipartFormDataContent();
HttpContent JsonParam = new StringContent(JsonString);
formContent.Add(JsonParam, "JsonString");
var fileContent = new StreamContent(Archivo.InputStream);
fileContent.Headers.Add("Content-Type", "application/octet-stream");
fileContent.Headers.Add("Content-Disposition", "form-data; name=\"Archivo\"; filename=\"" + Archivo.FileName.ToString() + "\"");
formContent.Add(fileContent, "file", Archivo.FileName.ToString());
String url = DataEntityLayer.Database.Environment.getFinalUrl(Util.UtilWS.subirImagenesCategorias);
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(url, formContent);
string stringContent = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<CustomJsonResult>(stringContent);
}
catch (Exception ex)
{
result.Error = ex.Message;
}
return result;
}
I am looking to upload a file with some associated data from a C# win app to a WebAPI 2.0 using HTTP POST, but the request does not seems to be created corectly, however when I try to send them seperately it works fine.
Below is Win App Code for Upload:
public bool Upload(string url, string filePath, string localFilename, string uploadFileName)
{
Boolean isFileUploaded = false;
HttpClient httpClient = new HttpClient();
var fileStream = File.Open(localFilename, FileMode.Open);
var fileInfo = new FileInfo(localFilename);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Headers.Add("filePath", filePath);
content.Add(new StreamContent(fileStream), "\"file\"", string.Format("\"{0}\"", uploadFileName + fileInfo.Extension));
TestDocument td = new TestDocument();
td.Field1 = "ABC";
td.Field2 = "PQR";
string json = JsonConvert.SerializeObject(td);
var httpContent = new StringContent(json, Encoding.UTF8, "multipart/form-data");
content.Add(httpContent);
var result = httpClient.PostAsync(url, content);
return true;
}
At Api end:
[HttpPost]
public HttpResponseMessage Post([FromBody] Testdocument document)
{
HttpResponseMessage result = null;
Testdocument otd = new Testdocument();
otd = document;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/App_Data/" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
Any suggestions on this?
I'm working on UWP apps, In that i need to upload the image for that i'm calling the web service to post the details. I'm using the below code to serialize the image.
byte[] fileBytes = null;
using (var stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
docs.Document = fileBytes;
docs.DocumentName = file.Name;
docs.DocumentTypeOtherDescription = "ProfilePicture";
var docsAsJson = JsonConvert.SerializeObject(docs);
StringContent stringContent = new StringContent(docsAsJson, System.Text.Encoding.UTF8);
ByteArrayContent byteContent = new ByteArrayContent(fileBytes);
MultipartFormDataContent httpContent = new MultipartFormDataContent();
httpContent.Add(byteContent, file.Name);
httpContent.Add(stringContent);
using (var httpClient = new HttpClient())
{
var request = new HttpRequestMessage {Method = HttpMethod.Post};
request.Headers.Add("authorization", App.TokenType + " " + App.AccessToken);
request.RequestUri = new Uri(App.BaseUrl + "api/User/UploadUserDocument");
request.Content = httpContent;
request.Content.Headers.Add(#"Content-Length", fileBytes.Length.ToString());
var response = httpClient.SendAsync(request).Result;
var data = response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
}
}
This is my side to serialize the image and in service side they deserialize the image and saved in database. But i'm getting StatusCode: 500, ReasonPhrase: 'Internal Server Error' this error, Any one please help me to solve this issue.
Here is my Service Code:
public IHttpActionResult UpdateUserWithProfilePic(FormData userviewmodel)
{
var error = string.Empty;
var userJson = new StringBuilder();
foreach (var items in userviewmodel.Fields)
{
if (items.Name == "}")
{
if (!userJson.ToString().EndsWith(",")) continue;
userJson.Remove(userJson.Length - 1, 1);
userJson.Append("}");
}
else
userJson.Append((items.Name.Replace("%22", "\"")) + ":" + items.Value);
}
var userView = JsonConvert.DeserializeObject<UserViewModel>(userJson.ToString());
var result = UpdateUser(userView, error);
if (result.ResultType != ResultType.Success) return daHttpActionResult(result.Result, result);
if (userviewmodel.Files != null && userviewmodel.Files.Count > 0)
{
userView.ProfileDocument = new UserDocument
{
DocumentName = userviewmodel.Files[0].Name,
Document = userviewmodel.Files[0].Value.Buffer,
UserID = UserId,
DocumentType = DocumentTypeEnum.ProfilePicture,
DocumentTypeOtherDescription = userviewmodel.Files[0].Value.MediaType,
};
}
return AdHttpActionResult(result.Result, result);
}
Thanks & Regards,
Cristina