Multipart Forms from C# Client

Multipart forms from C# client

This is cut and pasted from some sample code I wrote, hopefully it should give the basics. It only supports File data and form-data at the moment.

public class PostData
{

private List<PostDataParam> m_Params;

public List<PostDataParam> Params
{
get { return m_Params; }
set { m_Params = value; }
}

public PostData()
{
m_Params = new List<PostDataParam>();

// Add sample param
m_Params.Add(new PostDataParam("email", "MyEmail", PostDataParamType.Field));
}

/// <summary>
/// Returns the parameters array formatted for multi-part/form data
/// </summary>
/// <returns></returns>
public string GetPostData()
{
// Get boundary, default is --AaB03x
string boundary = ConfigurationManager.AppSettings["ContentBoundary"].ToString();

StringBuilder sb = new StringBuilder();
foreach (PostDataParam p in m_Params)
{
sb.AppendLine(boundary);

if (p.Type == PostDataParamType.File)
{
sb.AppendLine(string.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", p.Name, p.FileName));
sb.AppendLine("Content-Type: text/plain");
sb.AppendLine();
sb.AppendLine(p.Value);
}
else
{
sb.AppendLine(string.Format("Content-Disposition: form-data; name=\"{0}\"", p.Name));
sb.AppendLine();
sb.AppendLine(p.Value);
}
}

sb.AppendLine(boundary);

return sb.ToString();
}
}

public enum PostDataParamType
{
Field,
File
}

public class PostDataParam
{

public PostDataParam(string name, string value, PostDataParamType type)
{
Name = name;
Value = value;
Type = type;
}

public string Name;
public string FileName;
public string Value;
public PostDataParamType Type;
}

To send the data you then need to:

HttpWebRequest oRequest = null;
oRequest = (HttpWebRequest)HttpWebRequest.Create(oURL.URL);
oRequest.ContentType = "multipart/form-data";
oRequest.Method = "POST";
PostData pData = new PostData();

byte[] buffer = encoding.GetBytes(pData.GetPostData());

// Set content length of our data
oRequest.ContentLength = buffer.Length;

// Dump our buffered postdata to the stream, booyah
oStream = oRequest.GetRequestStream();
oStream.Write(buffer, 0, buffer.Length);
oStream.Close();

// get the response
oResponse = (HttpWebResponse)oRequest.GetResponse();

Hope thats clear, i've cut and pasted from a few sources to get that tidier.

Using C# HttpClient to POST File without multipart/form-data

I think it would look something like this

using var client = new HttpClient();

var file = File.ReadAllBytes(filePath);

var content = new ByteArrayContent(file);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

var result = await client.PostAsync(uploadURI.ToString(), content);
result.EnsureSuccessStatusCode();

var response = await result.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(response);

return doc.RootElement.GetProperty("documentId").ToString();

C# HttpClient 4.5 multipart/form-data upload

my result looks like this:

public static async Task<string> Upload(byte[] image)
{
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(new MemoryStream(image)), "bilddatei", "upload.jpg");

using (
var message =
await client.PostAsync("http://www.directupload.net/index.php?mode=upload", content))
{
var input = await message.Content.ReadAsStringAsync();

return !string.IsNullOrWhiteSpace(input) ? Regex.Match(input, @"http://\w*\.directupload\.net/images/\d*/\w*\.[a-z]{3}").Value : null;
}
}
}
}

How to upload file to server with HTTP POST multipart/form-data?

Here's my final working code. My web service needed one file (POST parameter name was "file") & a string value (POST parameter name was "userid").

/// <summary>
/// Occurs when upload backup application bar button is clicked. Author : Farhan Ghumra
/// </summary>
private async void btnUploadBackup_Click(object sender, EventArgs e)
{
var dbFile = await ApplicationData.Current.LocalFolder.GetFileAsync(Util.DBNAME);
var fileBytes = await GetBytesAsync(dbFile);
var Params = new Dictionary<string, string> { { "userid", "9" } };
UploadFilesToServer(new Uri(Util.UPLOAD_BACKUP), Params, Path.GetFileName(dbFile.Path), "application/octet-stream", fileBytes);
}

/// <summary>
/// Creates HTTP POST request & uploads database to server. Author : Farhan Ghumra
/// </summary>
private void UploadFilesToServer(Uri uri, Dictionary<string, string> data, string fileName, string fileContentType, byte[] fileData)
{
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest.Method = "POST";
httpWebRequest.BeginGetRequestStream((result) =>
{
try
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
using (Stream requestStream = request.EndGetRequestStream(result))
{
WriteMultipartForm(requestStream, boundary, data, fileName, fileContentType, fileData);
}
request.BeginGetResponse(a =>
{
try
{
var response = request.EndGetResponse(a);
var responseStream = response.GetResponseStream();
using (var sr = new StreamReader(responseStream))
{
using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
{
string responseString = streamReader.ReadToEnd();
//responseString is depend upon your web service.
if (responseString == "Success")
{
MessageBox.Show("Backup stored successfully on server.");
}
else
{
MessageBox.Show("Error occurred while uploading backup on server.");
}
}
}
}
catch (Exception)
{

}
}, null);
}
catch (Exception)
{

}
}, httpWebRequest);
}

/// <summary>
/// Writes multi part HTTP POST request. Author : Farhan Ghumra
/// </summary>
private void WriteMultipartForm(Stream s, string boundary, Dictionary<string, string> data, string fileName, string fileContentType, byte[] fileData)
{
/// The first boundary
byte[] boundarybytes = Encoding.UTF8.GetBytes("--" + boundary + "\r\n");
/// the last boundary.
byte[] trailer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
/// the form data, properly formatted
string formdataTemplate = "Content-Dis-data; name=\"{0}\"\r\n\r\n{1}";
/// the form-data file upload, properly formatted
string fileheaderTemplate = "Content-Dis-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n";

/// Added to track if we need a CRLF or not.
bool bNeedsCRLF = false;

if (data != null)
{
foreach (string key in data.Keys)
{
/// if we need to drop a CRLF, do that.
if (bNeedsCRLF)
WriteToStream(s, "\r\n");

/// Write the boundary.
WriteToStream(s, boundarybytes);

/// Write the key.
WriteToStream(s, string.Format(formdataTemplate, key, data[key]));
bNeedsCRLF = true;
}
}

/// If we don't have keys, we don't need a crlf.
if (bNeedsCRLF)
WriteToStream(s, "\r\n");

WriteToStream(s, boundarybytes);
WriteToStream(s, string.Format(fileheaderTemplate, "file", fileName, fileContentType));
/// Write the file data to the stream.
WriteToStream(s, fileData);
WriteToStream(s, trailer);
}

/// <summary>
/// Writes string to stream. Author : Farhan Ghumra
/// </summary>
private void WriteToStream(Stream s, string txt)
{
byte[] bytes = Encoding.UTF8.GetBytes(txt);
s.Write(bytes, 0, bytes.Length);
}

/// <summary>
/// Writes byte array to stream. Author : Farhan Ghumra
/// </summary>
private void WriteToStream(Stream s, byte[] bytes)
{
s.Write(bytes, 0, bytes.Length);
}

/// <summary>
/// Returns byte array from StorageFile. Author : Farhan Ghumra
/// </summary>
private async Task<byte[]> GetBytesAsync(StorageFile file)
{
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);
}
}

return fileBytes;
}

I am very much thankful to Darin Rousseau for helping me.

HttpClient Multipart Form Post in C#

So the problem I'm seeing is that the MultipartFormDataContent request message will always set the content type of the request to "multipart/form-data". Endcoding json and placing that into the request only "looks" like to the model binder as a string.

Your options are:

  • have your mvc action method receive a string and deserialize into your object
  • post each property of your model as a form part
  • create a custom model binder that will handle your request.
  • Breakup the operation into two posts, first sends the json metadata, the other sends the file. The response from the server should send some id or key to correlate the two requests.

Reading through the RFC document and the MSDN documentation you may be able to do this, if you replace MultipartFormDataContent with MultipartContent. But I have not tested this yet.

C# Multipart form-data in HttpClient Post REST API

All, Finally i am able to reproduce the Postman code in C# programmatically.

I able to add the "metadata" property in the multipart form-data.

Reference: Upload Files Using HttpClient

string Seshat_URL = "https://azr-stg.dev03.abs.ase.southcentralus.us.wc.net/files/v11";
using (var multiPartStream = new MultipartFormDataContent())
{

multiPartStream.Add(new StringContent("{}"), "metadata");
multiPartStream.Add(new ByteArrayContent(filecontent, 0, filecontent.Length), "file", docName);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Seshat_URL);
request.Content = multiPartStream;
//"application/json" - content type
request.Headers.Accept.Add(JSON_GENERIC_MEDIA_TYPE);
request.Headers.Add("X-Client-Id", ClientId);
request.Headers.Add("Tenant-Id", TenantId);

HttpCompletionOption option = HttpCompletionOption.ResponseContentRead;
System.Net.ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);

using (HttpResponseMessage response = _httpClient.SendAsync(request, option).Result)
{
if (response.IsSuccessStatusCode)
{
var deserializedObject = JsonConvert.DeserializeObject<Wc.MCM.UIMVC.Helpers1.BlobResponse>(response.Content.ReadAsStringAsync().Result);
return deserializedObject.fileId.ToString();
}
}

}//End Try

C# multipart form data httpclient upload csv service

I went the route of using Postman to create my request, then got the generated code for C# with the RestSharp NuGet Package.

public static void UploadFile(FileInfo file, Token token, DateTime lwt, DateTime nwt)
{
string status = "";
string reason = "";
try
{
var client = new RestClient(token.Url);
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddParameter("key", token.Key);
request.AddParameter("uuid", token.Uuid);
request.AddParameter("context", token.Context);
request.AddFile("file", file.FullName);
IRestResponse response = client.Execute(request);
status = response.StatusCode.ToString();
reason = response.ErrorMessage.ToString();
Library.RecordUploadSuccess(file, lwt, nwt);
}
catch (Exception ex)
{
Library.RecordUploadError(file, status, reason);
//Library.RecordUploadError(file, ex.Message, ex.StackTrace);
}
}

Highly recommend going that route for multipart form-data.



Related Topics



Leave a reply



Submit