HttpRequest.Files is empty when posting file through HttpClient - c#

Server-side:
public HttpResponseMessage Post([FromUri]string machineName)
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0 && !String.IsNullOrEmpty(machineName))
...
Client-side:
public static void PostFile(string url, string filePath)
{
if (String.IsNullOrWhiteSpace(url) || String.IsNullOrWhiteSpace(filePath))
throw new ArgumentNullException();
if (!File.Exists(filePath))
throw new FileNotFoundException();
using (var handler = new HttpClientHandler { Credentials= new NetworkCredential(AppData.UserName, AppData.Password, AppCore.Domain) })
using (var client = new HttpClient(handler))
using (var content = new MultipartFormDataContent())
using (var ms = new MemoryStream(File.ReadAllBytes(filePath)))
{
var fileContent = new StreamContent(ms);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = Path.GetFileName(filePath)
};
content.Add(fileContent);
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
var result = client.PostAsync(url, content).Result;
result.EnsureSuccessStatusCode();
}
}
At the server-side httpRequest.Files collection is always empty. But headers (content-length etc...) are right.

You shouldn't use HttpContext for getting the files in ASP.NET Web API. Take a look at this example written by Microsoft (http://code.msdn.microsoft.com/ASPNET-Web-API-File-Upload-a8c0fb0d/sourcecode?fileId=67087&pathId=565875642).
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
StringBuilder sb = new StringBuilder(); // Holds the response body
// Read the form data and return an async task.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the form data.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
sb.Append(string.Format("{0}: {1}\n", key, val));
}
}
// This illustrates how to get the file names for uploaded files.
foreach (var file in provider.FileData)
{
FileInfo fileInfo = new FileInfo(file.LocalFileName);
sb.Append(string.Format("Uploaded file: {0} ({1} bytes)\n", fileInfo.Name, fileInfo.Length));
}
return new HttpResponseMessage()
{
Content = new StringContent(sb.ToString())
};
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}

Everything looks good in your code except the content type which should be multipart/form-data. Please try changing your code to reflect the correct content type:
content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
You might want to refer to this post as to why setting the content type to application/octet-stream doesn't make sense from client side.

Try this method :
public void UploadFilesToRemoteUrl()
{
string[] files = { #"your file path" };
string url = "Your url";
long length = 0;
string boundary = "----------------------------" +
DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest2.ContentType = "multipart/form-data; boundary=" +
boundary;
httpWebRequest2.Method = "POST";
httpWebRequest2.KeepAlive = true;
httpWebRequest2.Credentials =
System.Net.CredentialCache.DefaultCredentials;
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
memStream.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
for (int i = 0; i < files.Length; i++)
{
//string header = string.Format(headerTemplate, "file" + i, files[i]);
string header = string.Format(headerTemplate, "uplTheFile", files[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(files[i], FileMode.Open,
FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
memStream.Write(boundarybytes, 0, boundarybytes.Length);
fileStream.Close();
}
httpWebRequest2.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest2.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
WebResponse webResponse2 = httpWebRequest2.GetResponse();
Stream stream2 = webResponse2.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
webResponse2.Close();
httpWebRequest2 = null;
webResponse2 = null;
}

In case someone else has the same problem: make sure your boundary string is valid, e.g. don't do this:
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
...
}
This failed for me due to an invalid boundary character, maybe the "/" date separator. At least this solved my problem when accessing Context.Request.Files in a Nancy controller (which was always empty).
Better to use something like DateTime.Now.Ticks.ToString("x") instead.

Related

application/form-data in C# application?

I have using below code to upload file into url using C# console application.It doesn't upload file and not return error also.
string[] files = new string []{ "C:/test.csv" };
public static string UploadFilesToRemoteUrl(string url, string[] files, NameValueCollection formFields = null)
{
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=" +
boundary;
request.Method = "POST";
request.KeepAlive = true;
Stream memStream = new System.IO.MemoryStream();
var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "--");
string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
if (formFields != null)
{
foreach (string key in formFields.Keys)
{
string formitem = string.Format(formdataTemplate, key, formFields[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
memStream.Write(formitembytes, 0, formitembytes.Length);
}
}
string headerTemplate =
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
"Content-Type: application/octet-stream\r\n\r\n";
for (int i = 0; i < files.Length; i++)
{
memStream.Write(boundarybytes, 0, boundarybytes.Length);
var header = string.Format(headerTemplate, "uplTheFile", files[i]);
var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
using (var fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
{
var buffer = new byte[1024];
var bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
}
}
memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
request.ContentLength = memStream.Length;
using (Stream requestStream = request.GetRequestStream())
{
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
}
using (var response = request.GetResponse())
{
Stream stream2 = response.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
return reader2.ReadToEnd();
}
}
Upload files with HTTPWebrequest (multipart/form-data)
i have checked this code and it doesn't uploaded file in url i was given and also no error return.
This question has been answered already here:
Upload files with HTTPWebrequest (multipart/form-data)
Also, please note that in your code you are actually sending the string "C:/test.csv" and not the contents of the file! You will need to open a FileStream (https://msdn.microsoft.com/en-us/library/system.io.filestream.aspx) to stream out it's contents. (This is also covered in the answer linked above)

Can I post a file and data to a .net mvc web api controller

I have the following .net web api controller method that supports the posting of files to the server.
public Task<HttpResponseMessage> PostFile()
{
var request = Request;
if (!request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.UnsupportedMediaType));
}
var root = HttpContext.Current.Server.MapPath("~/App_Data/Uploads");
var provider = new MultipartFileStreamProvider(root);
var task = request.Content.ReadAsMultipartAsy
nc(provider).ContinueWith(o =>
{
var finfo = new FileInfo(provider.FileData.First().LocalFileName);
var guid = Guid.NewGuid().ToString();
File.Move(finfo.FullName,
Path.Combine(root,
guid + "_" + provider.FileData.First().Headers.ContentDisposition.FileName.Replace("\"", "")));
return new HttpResponseMessage
{
Content = new StringContent("File upload.")
};
});
return task;
}
This works well, however I would like to be able to include some metadata about the file as part of the post. At the moment I am have a different web api method for the metadata like
public HttpResponseMessage PostTAG(TAG tag)
Which takes the information in the tag object and saves it to a data base. It would be much easier for my api clients if they could post the file and metadata together in one request. Is this possible in .net web api.
It is possible, where your WEB API declare a parameter for the TAG data. The problems will be your client who post data to your WEB API. If your client using .NET to post data to your WEB API, .NET WebClient does not support posting file along with data
Hence you will need to use lower level HttpWebRequest such as this one
public string UploadFilesToRemoteUrl(string url, Dictionary<string, string> files, NameValueCollection nvc, string contenttype)
{
string boundary = "----------------------------" +
DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest2 = (HttpWebRequest)GetWebRequest(new Uri(url)); //(HttpWebRequest)WebRequest.Create(url);
SetProxy(httpWebRequest2);
SetUserAgent(httpWebRequest2);
httpWebRequest2.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest2.Timeout = WebRequestTimeout; // 60 second * miliseconds * 60 minutes = 1 hour
httpWebRequest2.Method = "POST";
httpWebRequest2.KeepAlive = true;
httpWebRequest2.Credentials =
System.Net.CredentialCache.DefaultCredentials;
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
if (nvc != null)
{
foreach (string key in nvc.Keys)
{
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
memStream.Write(formitembytes, 0, formitembytes.Length);
}
}
memStream.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n\r\n";
if (string.IsNullOrEmpty(contenttype) == false)
{
headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" + contenttype + "\r\n";
}
string[] keys = nvc.AllKeys;
foreach (KeyValuePair<string, string> key in files)
{
//string header = string.Format(headerTemplate, "file" + i, files[i]);
//string header = string.Format(headerTemplate, "uplTheFile", files[i]);
string header = string.Format(headerTemplate, key.Key, key.Value);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(key.Value, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[buffsize];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
int progress = Convert.ToInt32((memStream.Length * 100) / fileStream.Length);
ReportProgress(key.Value, progress);
}
memStream.Write(boundarybytes, 0, boundarybytes.Length);
fileStream.Close();
if (MonitoredDownload != null) MonitoredDownload.OnComplete(key.Value);
buffer = null;
headerbytes = null;
}
httpWebRequest2.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest2.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[buffsize];
int bytereads = 0;
while ((bytereads = memStream.Read(tempBuffer, 0, tempBuffer.Length)) != 0)
{
requestStream.Write(tempBuffer, 0, bytereads);
}
//memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
memStream.Dispose();
//requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
requestStream.Dispose();
WebResponse webResponse2 = httpWebRequest2.GetResponse();
//SaveCookie(webResponse2, new Uri(url).GetLeftPart(UriPartial.Authority));
Stream stream2 = webResponse2.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
string str = reader2.ReadToEnd();
reader2.Close();
reader2.Dispose();
stream2.Close();
stream2.Dispose();
webResponse2.Close();
httpWebRequest2 = null;
webResponse2 = null;
tempBuffer = null;
return str;
}
TO use it, simply call
Dictionary<string,string> dict = new Dictionary<string,string>();
dict.Add("file1","c:\\myfile1.jpg");
NamuValueCollection nvc = new NameValueCollection();
nvc.Add("GPSPosition","somegpsvalue");
nvc.Add("CameraModel","somecameramodel");
UploadFilesToRemoteUrl("http://www.remoteurl.com/upload", dict, metadata, "Content-Type: application/octet-stream\r\n");
The above code excerpt is gotten from WebScraper project at http://www.sorainnosia.com/Projects#WS

ASP.Net Handler Request.Files always empty

I'm writing a C# ASP.Net application for client to post files to other server. I'm using a generic handler to handle posted files from client to server. But in my handler, context.Request.Files always empty (0 count). I believe my post method is right, because when I tried to move the handler in the same domain as the client, I can accept the files and save them. But the problem is I need to save the files to the other server.
Here is the code to post files:
private void UploadFilesToRemoteUrl3(HttpFileCollection files)
{
string url = "http://localhost:19107/Catalog/api/dashboard/ImageHandler.ashx";
long length = 0;
string boundary = "----------------------------" +
DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest2.ContentType = "multipart/form-data; boundary=" + boundary;
httpWebRequest2.Method = "POST";
httpWebRequest2.KeepAlive = true;
httpWebRequest2.Credentials =
System.Net.CredentialCache.DefaultCredentials;
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
memStream.Write(boundarybytes,0,boundarybytes.Length);
length += boundarybytes.Length;
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
foreach (string s in files)
{
HttpPostedFile file = files[s];
string header = string.Format(headerTemplate, "file", file.FileName);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes,0,headerbytes.Length);
length += headerbytes.Length;
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ( (bytesRead = file.InputStream.Read(buffer, 0, buffer.Length)) != 0 )
{
memStream.Write(buffer, 0, bytesRead);
length += bytesRead;
}
memStream.Write(boundarybytes,0,boundarybytes.Length);
length += boundarybytes.Length;
file.InputStream.Close();
}
httpWebRequest2.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest2.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer,0,tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer,0,tempBuffer.Length );
requestStream.Close();
WebResponse webResponse2 = httpWebRequest2.GetResponse();
Stream stream2 = webResponse2.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
string a = reader2.ReadToEnd();
webResponse2.Close();
httpWebRequest2 = null;
webResponse2 = null;
}
And here is the code behind my handler to receive the files:
public void ProcessRequest(HttpContext context)
{
context.Request.ContentType = "multipart/form-data";
int count = context.Request.Files.Count; //always 0
foreach (string s in context.Request.Files)
{
string response = "";
HttpPostedFile file = context.Request.Files[s];
//code to save files
}
}
public Response<List<string>> UplaoadPostImage()
{
Response<List<string>> response = new Response<List<string>>();
ResponseImage objtemp = new ResponseImage();
List<string> objlist = new List<string>();
try
{
HttpContextWrapper objwrapper = GetHttpContext(this.Request);
HttpFileCollectionBase collection = objwrapper.Request.Files;
if (collection.Count > 0)
{
foreach (string file in collection)
{
HttpPostedFileBase file1 = collection.Get(file);
Stream requestStream = file1.InputStream;
Image img = System.Drawing.Image.FromStream(requestStream);
//Image UserImage = objcommon.ResizeImage(img, 600, 600);
string UniqueFileName = file1.FileName;
img.Save(HttpContext.Current.Request.PhysicalApplicationPath + "UploadImage\\" + UniqueFileName, System.Drawing.Imaging.ImageFormat.Png);
objlist.Add(ConfigurationManager.AppSettings["ImagePath"] + UniqueFileName);
requestStream.Close();
}
response.Create(true, 0, Messages.FormatMessage(Messages.UploadImage_Sucess, ""), objlist);
}
else
{
response.Create(false, 0, "File not found.", objlist);
}
}
catch (Exception ex)
{
response.Create(false, -1, Messages.FormatMessage(ex.Message), objlist);
}
return response;
}
private HttpContextWrapper GetHttpContext(HttpRequestMessage request = null)
{
request = request ?? Request;
if (request.Properties.ContainsKey("MS_HttpContext"))
{
return ((HttpContextWrapper)request.Properties["MS_HttpContext"]);
}
else if (HttpContext.Current != null)
{
return new HttpContextWrapper(HttpContext.Current);
}
else
{
return null;
}
}

c# ASP HttpWebRequest Multipart Upload XML and Images

I´ve (tried to) Customize a Method i found here on Stackoverflow to enable a Multipart Upload of one XML File and multiple Images, to process a HTTPWebRequest out a Sharepoint WebPart. For my shame i ve to say that I´m really not familar with that HttpRequest and StreamUpload thing, it`s the first time i seriously try to handle this.
Here`s my coding:
public XmlDocument DoHttpUploadFile(string url, string[] file, string[] paramName, string[] contentType, NameValueCollection nvc, NameValueCollection headerItems, string xmlFileName)
{
var xmlDox = new XmlDocument();
var totalLength = 0;
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
const string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
// First Loop is just need to get the Length of all Parts
for (int i = 0; i < file.Length; i++)
{
string header = "";
if (i == 0)
{
header = string.Format(headerTemplate, paramName[i], xmlFileName, contentType[i]);
}
else
{
var filename = Path.GetFileName(file[i]);
header = string.Format(headerTemplate, paramName[i], filename, contentType[i]);
}
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
var headerLength = headerbytes.Length;
var boundaryLength = boundarybytes.Length;
totalLength = totalLength + headerLength + boundaryLength;
if (file[i].StartsWith("<"))
{
byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(file[i]);
var xmlLength = xmlBytes.Length;
totalLength = totalLength + xmlLength;
}
else
{
var client = new WebClient();
var img = new Image { ImageUrl = file[i] };
client.UseDefaultCredentials = true;
// image as Byte into Stream
var fileData = client.DownloadData(img.ImageUrl);
var imgLength = fileData.Length;
totalLength = totalLength + imgLength;
}
}
var wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.ContentLength = totalLength;
Stream rs = wr.GetRequestStream();
var read = 0;
var finalLength = 0;
for (int i = 0; i < file.Length; i++)
{
string header = "";
if(i==0)
{
header = string.Format(headerTemplate, paramName[i], xmlFileName, contentType[i]);
}
else
{
var filename = Path.GetFileName(file[i]);
header = string.Format(headerTemplate, paramName[i], filename, contentType[i]);
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
var headerLength = headerbytes.Length;
var boundaryLength = boundarybytes.Length;
finalLength = finalLength + headerLength + boundaryLength;
rs.Write(headerbytes, 0, headerbytes.Length);
if(file[i].StartsWith("<"))
{
var writer = new StreamWriter(rs);
byte[] xmlBytes = System.Text.Encoding.UTF8.GetBytes(file[i]);
var xmlLength = xmlBytes.Length;
finalLength = finalLength + xmlLength;
writer.Write(file[i]);
}
else
{
var getitem = new GetItemFromList();
var client = new WebClient();
var img = new Image {ImageUrl = file[i]};
client.UseDefaultCredentials = true;
// image as Byte into Stream
var fileData = client.DownloadData(img.ImageUrl);
finalLength = finalLength + fileData.Length;
rs.Write(fileData, 0, fileData.Length);
}
}
finalLength.ToString();
rs.Close(); // Here it stops with Exception 'Bytes are not completely written
WebResponse wresp = null;
try
{
wresp = wr.GetResponse();
var wrlength = wr.ContentLength;
var stream2 = wresp.GetResponseStream();
if (stream2 != null)
{
var reader2 = new StreamReader(stream2);
var backstr = reader2.ReadToEnd();
xmlDox.LoadXml(backstr);
}
}
catch (Exception ex)
{
//log.Error("Error uploading file", ex);
if (wresp != null)
wresp.Close();
wresp = null;
}
finally
{
wr = null; }
return xmlDox;
}
It Stops at rs.Close with the Exception 'Cannot Close Stream bytes are not writen complete'.
I thought maybe this depends on wr.ContentLength and tried to set this manually, as you can see in the above section of the coding.
I cant find a solution i tried the last two Day`s and searched all around the web, especially stackeOverflow.
So, if anyone could tell me what going wrong, pleeeease tell me, thx.
"The Exception is thrown because you are writing less bytes than the WebRequest expects. For example if you have set say 75 bytes in the ContentLength property and you write 69 bytes on the ResquestStream and close it the exception will be thrown."
See this post: Cannot close stream until all bytes are written
Can you check the size of TotalLength making sure you are using the byte length and verify in a debugger?

How to post to a form which has type="file" [duplicate]

Is there any class, library or some piece of code which will help me to upload files with HTTPWebrequest?
Edit 2:
I do not want to upload to a WebDAV folder or something like that. I want to simulate a browser, so just like you upload your avatar to a forum or upload a file via form in a web application. Upload to a form which uses a multipart/form-data.
Edit:
WebClient is not cover my requirements, so I'm looking for a solution with HTTPWebrequest.
Took the code above and fixed because it throws Internal Server Error 500. There are some problems with \r\n badly positioned and spaces etc. Applied the refactoring with memory stream, writing directly to the request stream. Here is the result:
public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc) {
log.Debug(string.Format("Uploading {0} to {1}", file, url));
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
foreach (string key in nvc.Keys)
{
rs.Write(boundarybytes, 0, boundarybytes.Length);
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, paramName, file, contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) {
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
WebResponse wresp = null;
try {
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
log.Debug(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
} catch(Exception ex) {
log.Error("Error uploading file", ex);
if(wresp != null) {
wresp.Close();
wresp = null;
}
} finally {
wr = null;
}
}
and sample usage:
NameValueCollection nvc = new NameValueCollection();
nvc.Add("id", "TTR");
nvc.Add("btn-submit-photo", "Upload");
HttpUploadFile("http://your.server.com/upload",
#"C:\test\test.jpg", "file", "image/jpeg", nvc);
It could be extended to handle multiple files or just call it multiple times for each file. However it suits your needs.
I was looking for something like this, Found in :
http://bytes.com/groups/net-c/268661-how-upload-file-via-c-code (modified for correctness):
public static string UploadFilesToRemoteUrl(string url, string[] files, NameValueCollection formFields = null)
{
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=" +
boundary;
request.Method = "POST";
request.KeepAlive = true;
Stream memStream = new System.IO.MemoryStream();
var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "--");
string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
if (formFields != null)
{
foreach (string key in formFields.Keys)
{
string formitem = string.Format(formdataTemplate, key, formFields[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
memStream.Write(formitembytes, 0, formitembytes.Length);
}
}
string headerTemplate =
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
"Content-Type: application/octet-stream\r\n\r\n";
for (int i = 0; i < files.Length; i++)
{
memStream.Write(boundarybytes, 0, boundarybytes.Length);
var header = string.Format(headerTemplate, "uplTheFile", files[i]);
var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes, 0, headerbytes.Length);
using (var fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
{
var buffer = new byte[1024];
var bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
memStream.Write(buffer, 0, bytesRead);
}
}
}
memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
request.ContentLength = memStream.Length;
using (Stream requestStream = request.GetRequestStream())
{
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
}
using (var response = request.GetResponse())
{
Stream stream2 = response.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
return reader2.ReadToEnd();
}
}
This is possible without external code, extensions, and "low level" HTTP manipulation (just need Microsoft.Net.Http package from NuGet). Here is an example:
// Perform the equivalent of posting a form with a filename and two files, in HTML:
// <form action="{url}" method="post" enctype="multipart/form-data">
// <input type="text" name="filename" />
// <input type="file" name="file1" />
// <input type="file" name="file2" />
// </form>
private async Task<System.IO.Stream> UploadAsync(string url, string filename, Stream fileStream, byte [] fileBytes)
{
// Convert each of the three inputs into HttpContent objects
HttpContent stringContent = new StringContent(filename);
// examples of converting both Stream and byte [] to HttpContent objects
// representing input type file
HttpContent fileStreamContent = new StreamContent(fileStream);
HttpContent bytesContent = new ByteArrayContent(fileBytes);
// Submit the form using HttpClient and
// create form data as Multipart (enctype="multipart/form-data")
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
// Add the HttpContent objects to the form data
// <input type="text" name="filename" />
formData.Add(stringContent, "filename", "filename");
// <input type="file" name="file1" />
formData.Add(fileStreamContent, "file1", "file1");
// <input type="file" name="file2" />
formData.Add(bytesContent, "file2", "file2");
// Invoke the request to the server
// equivalent to pressing the submit button on
// a form with attributes (action="{url}" method="post")
var response = await client.PostAsync(url, formData);
// ensure the request was a success
if (!response.IsSuccessStatusCode)
{
return null;
}
return await response.Content.ReadAsStreamAsync();
}
}
Based on the code provided above I added support for multiple files and also uploading a stream directly without the need to have a local file.
To upload files to a specific url including some post params do the following:
RequestHelper.PostMultipart(
"http://www.myserver.com/upload.php",
new Dictionary<string, object>() {
{ "testparam", "my value" },
{ "file", new FormFile() { Name = "image.jpg", ContentType = "image/jpeg", FilePath = "c:\\temp\\myniceimage.jpg" } },
{ "other_file", new FormFile() { Name = "image2.jpg", ContentType = "image/jpeg", Stream = imageDataStream } },
});
To enhance this even more one could determine the name and mime type from the given file itself.
public class FormFile
{
public string Name { get; set; }
public string ContentType { get; set; }
public string FilePath { get; set; }
public Stream Stream { get; set; }
}
public class RequestHelper
{
public static string PostMultipart(string url, Dictionary<string, object> parameters) {
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Method = "POST";
request.KeepAlive = true;
request.Credentials = System.Net.CredentialCache.DefaultCredentials;
if(parameters != null && parameters.Count > 0) {
using(Stream requestStream = request.GetRequestStream()) {
foreach(KeyValuePair<string, object> pair in parameters) {
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
if(pair.Value is FormFile) {
FormFile file = pair.Value as FormFile;
string header = "Content-Disposition: form-data; name=\"" + pair.Key + "\"; filename=\"" + file.Name + "\"\r\nContent-Type: " + file.ContentType + "\r\n\r\n";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(header);
requestStream.Write(bytes, 0, bytes.Length);
byte[] buffer = new byte[32768];
int bytesRead;
if(file.Stream == null) {
// upload from file
using(FileStream fileStream = File.OpenRead(file.FilePath)) {
while((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);
fileStream.Close();
}
}
else {
// upload from given stream
while((bytesRead = file.Stream.Read(buffer, 0, buffer.Length)) != 0)
requestStream.Write(buffer, 0, bytesRead);
}
}
else {
string data = "Content-Disposition: form-data; name=\"" + pair.Key + "\"\r\n\r\n" + pair.Value;
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
requestStream.Write(bytes, 0, bytes.Length);
}
}
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
requestStream.Write(trailer, 0, trailer.Length);
requestStream.Close();
}
}
using(WebResponse response = request.GetResponse()) {
using(Stream responseStream = response.GetResponseStream())
using(StreamReader reader = new StreamReader(responseStream))
return reader.ReadToEnd();
}
}
}
My ASP.NET Upload FAQ has an article on this, with example code: Upload files using an RFC 1867 POST request with HttpWebRequest/WebClient. This code doesn't load files into memory (as opposed to the code above), supports multiple files, and supports form values, setting credentials and cookies, etc.
Edit: looks like Axosoft took down the page. Thanks guys.
It's still accessible via archive.org.
something like this is close: (untested code)
byte[] data; // data goes here.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = userNetworkCredentials;
request.Method = "PUT";
request.ContentType = "application/octet-stream";
request.ContentLength = data.Length;
Stream stream = request.GetRequestStream();
stream.Write(data,0,data.Length);
stream.Close();
response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
temp = reader.ReadToEnd();
reader.Close();
VB Example (converted from C# example on another post):
Private Sub HttpUploadFile( _
ByVal uri As String, _
ByVal filePath As String, _
ByVal fileParameterName As String, _
ByVal contentType As String, _
ByVal otherParameters As Specialized.NameValueCollection)
Dim boundary As String = "---------------------------" & DateTime.Now.Ticks.ToString("x")
Dim newLine As String = System.Environment.NewLine
Dim boundaryBytes As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" & boundary & newLine)
Dim request As Net.HttpWebRequest = Net.WebRequest.Create(uri)
request.ContentType = "multipart/form-data; boundary=" & boundary
request.Method = "POST"
request.KeepAlive = True
request.Credentials = Net.CredentialCache.DefaultCredentials
Using requestStream As IO.Stream = request.GetRequestStream()
Dim formDataTemplate As String = "Content-Disposition: form-data; name=""{0}""{1}{1}{2}"
For Each key As String In otherParameters.Keys
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
Dim formItem As String = String.Format(formDataTemplate, key, newLine, otherParameters(key))
Dim formItemBytes As Byte() = Text.Encoding.UTF8.GetBytes(formItem)
requestStream.Write(formItemBytes, 0, formItemBytes.Length)
Next key
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length)
Dim headerTemplate As String = "Content-Disposition: form-data; name=""{0}""; filename=""{1}""{2}Content-Type: {3}{2}{2}"
Dim header As String = String.Format(headerTemplate, fileParameterName, filePath, newLine, contentType)
Dim headerBytes As Byte() = Text.Encoding.UTF8.GetBytes(header)
requestStream.Write(headerBytes, 0, headerBytes.Length)
Using fileStream As New IO.FileStream(filePath, IO.FileMode.Open, IO.FileAccess.Read)
Dim buffer(4096) As Byte
Dim bytesRead As Int32 = fileStream.Read(buffer, 0, buffer.Length)
Do While (bytesRead > 0)
requestStream.Write(buffer, 0, bytesRead)
bytesRead = fileStream.Read(buffer, 0, buffer.Length)
Loop
End Using
Dim trailer As Byte() = Text.Encoding.ASCII.GetBytes(newLine & "--" + boundary + "--" & newLine)
requestStream.Write(trailer, 0, trailer.Length)
End Using
Dim response As Net.WebResponse = Nothing
Try
response = request.GetResponse()
Using responseStream As IO.Stream = response.GetResponseStream()
Using responseReader As New IO.StreamReader(responseStream)
Dim responseText = responseReader.ReadToEnd()
Diagnostics.Debug.Write(responseText)
End Using
End Using
Catch exception As Net.WebException
response = exception.Response
If (response IsNot Nothing) Then
Using reader As New IO.StreamReader(response.GetResponseStream())
Dim responseText = reader.ReadToEnd()
Diagnostics.Debug.Write(responseText)
End Using
response.Close()
End If
Finally
request = Nothing
End Try
End Sub
I think you're looking for something more like WebClient.
Specifically, UploadFile().
Took the above and modified it accept some header values, and multiple files
NameValueCollection headers = new NameValueCollection();
headers.Add("Cookie", "name=value;");
headers.Add("Referer", "http://google.com");
NameValueCollection nvc = new NameValueCollection();
nvc.Add("name", "value");
HttpUploadFile(url, new string[] { "c:\\file1.txt", "c:\\file2.jpg" }, new string[] { "file", "image" }, new string[] { "application/octet-stream", "image/jpeg" }, nvc, headers);
public static void HttpUploadFile(string url, string[] file, string[] paramName, string[] contentType, NameValueCollection nvc, NameValueCollection headerItems)
{
//log.Debug(string.Format("Uploading {0} to {1}", file, url));
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
foreach (string key in headerItems.Keys)
{
if (key == "Referer")
{
wr.Referer = headerItems[key];
}
else
{
wr.Headers.Add(key, headerItems[key]);
}
}
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
foreach (string key in nvc.Keys)
{
rs.Write(boundarybytes, 0, boundarybytes.Length);
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = "";
for(int i =0; i<file.Count();i++)
{
header = string.Format(headerTemplate, paramName[i], System.IO.Path.GetFileName(file[i]), contentType[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(file[i], FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();
rs.Write(boundarybytes, 0, boundarybytes.Length);
}
rs.Close();
WebResponse wresp = null;
try
{
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
//log.Debug(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
}
catch (Exception ex)
{
//log.Error("Error uploading file", ex);
wresp.Close();
wresp = null;
}
finally
{
wr = null;
}
}
I had to deal with this recently - another way to approach it is to use the fact that WebClient is inheritable, and change the underlying WebRequest from there:
http://msdn.microsoft.com/en-us/library/system.net.webclient.getwebrequest(VS.80).aspx
I prefer C#, but if you're stuck with VB the results will look something like this:
Public Class BigWebClient
Inherits WebClient
Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
Dim x As WebRequest = MyBase.GetWebRequest(address)
x.Timeout = 60 * 60 * 1000
Return x
End Function
End Class
'Use BigWebClient here instead of WebClient
There is another working example with some my comments :
List<MimePart> mimeParts = new List<MimePart>();
try
{
foreach (string key in form.AllKeys)
{
StringMimePart part = new StringMimePart();
part.Headers["Content-Disposition"] = "form-data; name=\"" + key + "\"";
part.StringData = form[key];
mimeParts.Add(part);
}
int nameIndex = 0;
foreach (UploadFile file in files)
{
StreamMimePart part = new StreamMimePart();
if (string.IsNullOrEmpty(file.FieldName))
file.FieldName = "file" + nameIndex++;
part.Headers["Content-Disposition"] = "form-data; name=\"" + file.FieldName + "\"; filename=\"" + file.FileName + "\"";
part.Headers["Content-Type"] = file.ContentType;
part.SetStream(file.Data);
mimeParts.Add(part);
}
string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
req.ContentType = "multipart/form-data; boundary=" + boundary;
req.Method = "POST";
long contentLength = 0;
byte[] _footer = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
foreach (MimePart part in mimeParts)
{
contentLength += part.GenerateHeaderFooterData(boundary);
}
req.ContentLength = contentLength + _footer.Length;
byte[] buffer = new byte[8192];
byte[] afterFile = Encoding.UTF8.GetBytes("\r\n");
int read;
using (Stream s = req.GetRequestStream())
{
foreach (MimePart part in mimeParts)
{
s.Write(part.Header, 0, part.Header.Length);
while ((read = part.Data.Read(buffer, 0, buffer.Length)) > 0)
s.Write(buffer, 0, read);
part.Data.Dispose();
s.Write(afterFile, 0, afterFile.Length);
}
s.Write(_footer, 0, _footer.Length);
}
return (HttpWebResponse)req.GetResponse();
}
catch
{
foreach (MimePart part in mimeParts)
if (part.Data != null)
part.Data.Dispose();
throw;
}
And there is example of using :
UploadFile[] files = new UploadFile[]
{
new UploadFile(#"C:\2.jpg","new_file","image/jpeg") //new_file is id of upload field
};
NameValueCollection form = new NameValueCollection();
form["id_hidden_input"] = "value_hidden_inpu"; //there is additional param (hidden fields on page)
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(full URL of action);
// set credentials/cookies etc.
req.CookieContainer = hrm.CookieContainer; //hrm is my class. i copied all cookies from last request to current (for auth)
HttpWebResponse resp = HttpUploadHelper.Upload(req, files, form);
using (Stream s = resp.GetResponseStream())
using (StreamReader sr = new StreamReader(s))
{
string response = sr.ReadToEnd();
}
//profit!
I was looking to do file upload and add some parameters to a multipart/form-data request in VB.NET and not through a regular forms post.
Thanks to #JoshCodes answer I got the direction I was looking for.
I am posting my solution to help others find a way to perform a post with both file and parameters
the html equivalent of what I try to achieve is :
html
<form action="your-api-endpoint" enctype="multipart/form-data" method="post">
<input type="hidden" name="action" value="api-method-name"/>
<input type="hidden" name="apiKey" value="gs1xxxxxxxxxxxxxex"/>
<input type="hidden" name="access" value="protected"/>
<input type="hidden" name="name" value="test"/>
<input type="hidden" name="title" value="test"/>
<input type="hidden" name="signature" value="cf1d4xxxxxxxxcd5"/>
<input type="file" name="file"/>
<input type="submit" name="_upload" value="Upload"/>
</form>
Due to the fact that I have to provide the apiKey and the signature (which is a calculated checksum of the request parameters and api key concatenated string), I needed to do it server side.
The other reason I needed to do it server side is the fact that the post of the file can be performed at any time by pointing to a file already on the server (providing the path), so there would be no manually selected file during form post thus form data file would not contain the file stream.Otherwise I could have calculated the checksum via an ajax callback and submitted the file through the html post using JQuery.
I am using .net version 4.0 and cannot upgrade to 4.5 in the actual solution. So I had to install the Microsoft.Net.Http using nuget cmd
PM> install-package Microsoft.Net.Http
Private Function UploadFile(req As ApiRequest, filePath As String, fileName As String) As String
Dim result = String.empty
Try
''//Get file stream
Dim paramFileStream As Stream = File.OpenRead(filePath)
Dim fileStreamContent As HttpContent = New StreamContent(paramFileStream)
Using client = New HttpClient()
Using formData = New MultipartFormDataContent()
''// This adds parameter name ("action")
''// parameter value (req.Action) to form data
formData.Add(New StringContent(req.Action), "action")
formData.Add(New StringContent(req.ApiKey), "apiKey")
For Each param In req.Parameters
formData.Add(New StringContent(param.Value), param.Key)
Next
formData.Add(New StringContent(req.getRequestSignature.Qualifier), "signature")
''//This adds the file stream and file info to form data
formData.Add(fileStreamContent, "file", fileName)
''//We are now sending the request
Dim response = client.PostAsync(GetAPIEndpoint(), formData).Result
''//We are here reading the response
Dim readR = New StreamReader(response.Content.ReadAsStreamAsync().Result, Encoding.UTF8)
Dim respContent = readR.ReadToEnd()
If Not response.IsSuccessStatusCode Then
result = "Request Failed : Code = " & response.StatusCode & "Reason = " & response.ReasonPhrase & "Message = " & respContent
End If
result.Value = respContent
End Using
End Using
Catch ex As Exception
result = "An error occurred : " & ex.Message
End Try
Return result
End Function
Modified #CristianRomanescu code to work with memory stream, accept file as a byte array, allow null nvc, return request response and work with Authorization-header. Tested the code with Web Api 2.
private string HttpUploadFile(string url, byte[] file, string fileName, string paramName, string contentType, NameValueCollection nvc, string authorizationHeader)
{
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.Headers.Add("Authorization", authorizationHeader);
wr.KeepAlive = true;
Stream rs = wr.GetRequestStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
if (nvc != null)
{
foreach (string key in nvc.Keys)
{
rs.Write(boundarybytes, 0, boundarybytes.Length);
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
rs.Write(formitembytes, 0, formitembytes.Length);
}
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, paramName, fileName, contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
rs.Write(file, 0, file.Length);
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
WebResponse wresp = null;
try
{
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
var response = reader2.ReadToEnd();
return response;
}
catch (Exception ex)
{
if (wresp != null)
{
wresp.Close();
wresp = null;
}
return null;
}
finally
{
wr = null;
}
}
Testcode:
[HttpPost]
[Route("postformdata")]
public IHttpActionResult PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var provider = new MultipartMemoryStreamProvider();
try
{
// Read the form data.
var result = Request.Content.ReadAsMultipartAsync(provider).Result;
string response = "";
// This illustrates how to get the file names.
foreach (var file in provider.Contents)
{
var fileName = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = file.ReadAsByteArrayAsync().Result;
response = HttpUploadFile("https://localhost/api/v1/createfromfile", buffer, fileName, "file", "application/pdf", null, "AuthorizationKey");
}
return Ok(response);
}
catch (System.Exception e)
{
return InternalServerError();
}
}
For me, the following works (mostly inspirated from all of the following answers), I started from Elad's answer and modify/simplify things to match my need (remove not file form inputs, only one file, ...).
Hope it can helps somebody :)
(PS: I know that exception handling is not implemented and it assumes that it was written inside a class, so I may need some integration effort...)
private void uploadFile()
{
Random rand = new Random();
string boundary = "----boundary" + rand.Next().ToString();
Stream data_stream;
byte[] header = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"file_path\"; filename=\"" + System.IO.Path.GetFileName(this.file) + "\"\r\nContent-Type: application/octet-stream\r\n\r\n");
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
// Do the request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(MBF_URL);
request.UserAgent = "My Toolbox";
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "multipart/form-data; boundary=" + boundary;
data_stream = request.GetRequestStream();
data_stream.Write(header, 0, header.Length);
byte[] file_bytes = System.IO.File.ReadAllBytes(this.file);
data_stream.Write(file_bytes, 0, file_bytes.Length);
data_stream.Write(trailer, 0, trailer.Length);
data_stream.Close();
// Read the response
WebResponse response = request.GetResponse();
data_stream = response.GetResponseStream();
StreamReader reader = new StreamReader(data_stream);
this.url = reader.ReadToEnd();
if (this.url == "") { this.url = "No response :("; }
reader.Close();
data_stream.Close();
response.Close();
}
Not sure if this was posted before but I got this working with WebClient. i read the documentation for the WebClient. A key point they make is
If the BaseAddress property is not an empty string ("") and address
does not contain an absolute URI, address must be a relative URI that
is combined with BaseAddress to form the absolute URI of the requested
data. If the QueryString property is not an empty string, it is
appended to address.
So all I did was wc.QueryString.Add("source", generatedImage) to add the different query parameters and somehow it matches the property name with the image I uploaded. Hope it helps
public void postImageToFacebook(string generatedImage, string fbGraphUrl)
{
WebClient wc = new WebClient();
byte[] bytes = System.IO.File.ReadAllBytes(generatedImage);
wc.QueryString.Add("source", generatedImage);
wc.QueryString.Add("message", "helloworld");
wc.UploadFile(fbGraphUrl, generatedImage);
wc.Dispose();
}
I wrote a class using WebClient way back when to do multipart form upload.
http://ferozedaud.blogspot.com/2010/03/multipart-form-upload-helper.html
///
/// MimePart
/// Abstract class for all MimeParts
///
abstract class MimePart
{
public string Name { get; set; }
public abstract string ContentDisposition { get; }
public abstract string ContentType { get; }
public abstract void CopyTo(Stream stream);
public String Boundary
{
get;
set;
}
}
class NameValuePart : MimePart
{
private NameValueCollection nameValues;
public NameValuePart(NameValueCollection nameValues)
{
this.nameValues = nameValues;
}
public override void CopyTo(Stream stream)
{
string boundary = this.Boundary;
StringBuilder sb = new StringBuilder();
foreach (object element in this.nameValues.Keys)
{
sb.AppendFormat("--{0}", boundary);
sb.Append("\r\n");
sb.AppendFormat("Content-Disposition: form-data; name=\"{0}\";", element);
sb.Append("\r\n");
sb.Append("\r\n");
sb.Append(this.nameValues[element.ToString()]);
sb.Append("\r\n");
}
sb.AppendFormat("--{0}", boundary);
sb.Append("\r\n");
//Trace.WriteLine(sb.ToString());
byte [] data = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(data, 0, data.Length);
}
public override string ContentDisposition
{
get { return "form-data"; }
}
public override string ContentType
{
get { return String.Empty; }
}
}
class FilePart : MimePart
{
private Stream input;
private String contentType;
public FilePart(Stream input, String name, String contentType)
{
this.input = input;
this.contentType = contentType;
this.Name = name;
}
public override void CopyTo(Stream stream)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Content-Disposition: {0}", this.ContentDisposition);
if (this.Name != null)
sb.Append("; ").AppendFormat("name=\"{0}\"", this.Name);
if (this.FileName != null)
sb.Append("; ").AppendFormat("filename=\"{0}\"", this.FileName);
sb.Append("\r\n");
sb.AppendFormat(this.ContentType);
sb.Append("\r\n");
sb.Append("\r\n");
// serialize the header data.
byte[] buffer = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(buffer, 0, buffer.Length);
// send the stream.
byte[] readBuffer = new byte[1024];
int read = input.Read(readBuffer, 0, readBuffer.Length);
while (read > 0)
{
stream.Write(readBuffer, 0, read);
read = input.Read(readBuffer, 0, readBuffer.Length);
}
// write the terminating boundary
sb.Length = 0;
sb.Append("\r\n");
sb.AppendFormat("--{0}", this.Boundary);
sb.Append("\r\n");
buffer = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(buffer, 0, buffer.Length);
}
public override string ContentDisposition
{
get { return "file"; }
}
public override string ContentType
{
get {
return String.Format("content-type: {0}", this.contentType);
}
}
public String FileName { get; set; }
}
///
/// Helper class that encapsulates all file uploads
/// in a mime part.
///
class FilesCollection : MimePart
{
private List files;
public FilesCollection()
{
this.files = new List();
this.Boundary = MultipartHelper.GetBoundary();
}
public int Count
{
get { return this.files.Count; }
}
public override string ContentDisposition
{
get
{
return String.Format("form-data; name=\"{0}\"", this.Name);
}
}
public override string ContentType
{
get { return String.Format("multipart/mixed; boundary={0}", this.Boundary); }
}
public override void CopyTo(Stream stream)
{
// serialize the headers
StringBuilder sb = new StringBuilder(128);
sb.Append("Content-Disposition: ").Append(this.ContentDisposition).Append("\r\n");
sb.Append("Content-Type: ").Append(this.ContentType).Append("\r\n");
sb.Append("\r\n");
sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
byte[] headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(headerBytes, 0, headerBytes.Length);
foreach (FilePart part in files)
{
part.Boundary = this.Boundary;
part.CopyTo(stream);
}
}
public void Add(FilePart part)
{
this.files.Add(part);
}
}
///
/// Helper class to aid in uploading multipart
/// entities to HTTP web endpoints.
///
class MultipartHelper
{
private static Random random = new Random(Environment.TickCount);
private List formData = new List();
private FilesCollection files = null;
private MemoryStream bufferStream = new MemoryStream();
private string boundary;
public String Boundary { get { return boundary; } }
public static String GetBoundary()
{
return Environment.TickCount.ToString("X");
}
public MultipartHelper()
{
this.boundary = MultipartHelper.GetBoundary();
}
public void Add(NameValuePart part)
{
this.formData.Add(part);
part.Boundary = boundary;
}
public void Add(FilePart part)
{
if (files == null)
{
files = new FilesCollection();
}
this.files.Add(part);
}
public void Upload(WebClient client, string address, string method)
{
// set header
client.Headers.Add(HttpRequestHeader.ContentType, "multipart/form-data; boundary=" + this.boundary);
Trace.WriteLine("Content-Type: multipart/form-data; boundary=" + this.boundary + "\r\n");
// first, serialize the form data
foreach (NameValuePart part in this.formData)
{
part.CopyTo(bufferStream);
}
// serialize the files.
this.files.CopyTo(bufferStream);
if (this.files.Count > 0)
{
// add the terminating boundary.
StringBuilder sb = new StringBuilder();
sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
byte [] buffer = Encoding.ASCII.GetBytes(sb.ToString());
bufferStream.Write(buffer, 0, buffer.Length);
}
bufferStream.Seek(0, SeekOrigin.Begin);
Trace.WriteLine(Encoding.ASCII.GetString(bufferStream.ToArray()));
byte [] response = client.UploadData(address, method, bufferStream.ToArray());
Trace.WriteLine("----- RESPONSE ------");
Trace.WriteLine(Encoding.ASCII.GetString(response));
}
///
/// Helper class that encapsulates all file uploads
/// in a mime part.
///
class FilesCollection : MimePart
{
private List files;
public FilesCollection()
{
this.files = new List();
this.Boundary = MultipartHelper.GetBoundary();
}
public int Count
{
get { return this.files.Count; }
}
public override string ContentDisposition
{
get
{
return String.Format("form-data; name=\"{0}\"", this.Name);
}
}
public override string ContentType
{
get { return String.Format("multipart/mixed; boundary={0}", this.Boundary); }
}
public override void CopyTo(Stream stream)
{
// serialize the headers
StringBuilder sb = new StringBuilder(128);
sb.Append("Content-Disposition: ").Append(this.ContentDisposition).Append("\r\n");
sb.Append("Content-Type: ").Append(this.ContentType).Append("\r\n");
sb.Append("\r\n");
sb.AppendFormat("--{0}", this.Boundary).Append("\r\n");
byte[] headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
stream.Write(headerBytes, 0, headerBytes.Length);
foreach (FilePart part in files)
{
part.Boundary = this.Boundary;
part.CopyTo(stream);
}
}
public void Add(FilePart part)
{
this.files.Add(part);
}
}
}
class Program
{
static void Main(string[] args)
{
Trace.Listeners.Add(new ConsoleTraceListener());
try
{
using (StreamWriter sw = new StreamWriter("testfile.txt", false))
{
sw.Write("Hello there!");
}
using (Stream iniStream = File.OpenRead(#"c:\platform.ini"))
using (Stream fileStream = File.OpenRead("testfile.txt"))
using (WebClient client = new WebClient())
{
MultipartHelper helper = new MultipartHelper();
NameValueCollection props = new NameValueCollection();
props.Add("fname", "john");
props.Add("id", "acme");
helper.Add(new NameValuePart(props));
FilePart filepart = new FilePart(fileStream, "pics1", "text/plain");
filepart.FileName = "1.jpg";
helper.Add(filepart);
FilePart ini = new FilePart(iniStream, "pics2", "text/plain");
ini.FileName = "inifile.ini";
helper.Add(ini);
helper.Upload(client, "http://localhost/form.aspx", "POST");
}
}
catch (Exception e)
{
Trace.WriteLine(e);
}
}
}
This will work with all versions of the .NET framework.
I can never get the examples to work properly, I always receive a 500 error when sending it to the server.
However I came across a very elegant method of doing it in this url
It is easily extendible and obviously works with binary files as well as XML.
You call it using something similar to this
class Program
{
public static string gsaFeedURL = "http://yourGSA.domain.com:19900/xmlfeed";
static void Main()
{
try
{
postWebData();
}
catch (Exception ex)
{
}
}
// new one I made from C# web service
public static void postWebData()
{
StringDictionary dictionary = new StringDictionary();
UploadSpec uploadSpecs = new UploadSpec();
UTF8Encoding encoding = new UTF8Encoding();
byte[] bytes;
Uri gsaURI = new Uri(gsaFeedURL); // Create new URI to GSA feeder gate
string sourceURL = #"C:\FeedFile.xml"; // Location of the XML feed file
// Two parameters to send
string feedtype = "full";
string datasource = "test";
try
{
// Add the parameter values to the dictionary
dictionary.Add("feedtype", feedtype);
dictionary.Add("datasource", datasource);
// Load the feed file created and get its bytes
XmlDocument xml = new XmlDocument();
xml.Load(sourceURL);
bytes = Encoding.UTF8.GetBytes(xml.OuterXml);
// Add data to upload specs
uploadSpecs.Contents = bytes;
uploadSpecs.FileName = sourceURL;
uploadSpecs.FieldName = "data";
// Post the data
if ((int)HttpUpload.Upload(gsaURI, dictionary, uploadSpecs).StatusCode == 200)
{
Console.WriteLine("Successful.");
}
else
{
// GSA POST not successful
Console.WriteLine("Failure.");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Check out the MyToolkit library:
var request = new HttpPostRequest("http://www.server.com");
request.Data.Add("name", "value"); // POST data
request.Files.Add(new HttpPostFile("name", "file.jpg", "path/to/file.jpg"));
await Http.PostAsync(request, OnRequestFinished);
http://mytoolkit.codeplex.com/wikipage?title=Http
Client use convert File to ToBase64String, after use Xml to promulgate
to Server call, this server use File.WriteAllBytes(path,Convert.FromBase64String(dataFile_Client_sent)).
Good lucky!
This method work for upload multiple image simultaneously
var flagResult = new viewModel();
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = method;
wr.KeepAlive = true;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream rs = wr.GetRequestStream();
string path = #filePath;
System.IO.DirectoryInfo folderInfo = new DirectoryInfo(path);
foreach (FileInfo file in folderInfo.GetFiles())
{
rs.Write(boundarybytes, 0, boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, paramName, file, contentType);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
rs.Write(headerbytes, 0, headerbytes.Length);
FileStream fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
rs.Write(buffer, 0, bytesRead);
}
fileStream.Close();
}
byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
rs.Write(trailer, 0, trailer.Length);
rs.Close();
WebResponse wresp = null;
try
{
wresp = wr.GetResponse();
Stream stream2 = wresp.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
var result = reader2.ReadToEnd();
var cList = JsonConvert.DeserializeObject<HttpViewModel>(result);
if (cList.message=="images uploaded!")
{
flagResult.success = true;
}
}
catch (Exception ex)
{
//log.Error("Error uploading file", ex);
if (wresp != null)
{
wresp.Close();
wresp = null;
}
}
finally
{
wr = null;
}
return flagResult;
}
I realize this is probably really late, but I was searching for the same solution. I found the following response from a Microsoft rep
private void UploadFilesToRemoteUrl(string url, string[] files, string logpath, NameValueCollection nvc)
{
long length = 0;
string boundary = "----------------------------" +
DateTime.Now.Ticks.ToString("x");
HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest2.ContentType = "multipart/form-data; boundary=" +
boundary;
httpWebRequest2.Method = "POST";
httpWebRequest2.KeepAlive = true;
httpWebRequest2.Credentials = System.Net.CredentialCache.DefaultCredentials;
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
foreach(string key in nvc.Keys)
{
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
memStream.Write(formitembytes, 0, formitembytes.Length);
}
memStream.Write(boundarybytes,0,boundarybytes.Length);
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";
for(int i=0;i<files.Length;i++)
{
string header = string.Format(headerTemplate,"file"+i,files[i]);
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
memStream.Write(headerbytes,0,headerbytes.Length);
FileStream fileStream = new FileStream(files[i], FileMode.Open,
FileAccess.Read);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ( (bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0 )
{
memStream.Write(buffer, 0, bytesRead);
}
memStream.Write(boundarybytes,0,boundarybytes.Length);
fileStream.Close();
}
httpWebRequest2.ContentLength = memStream.Length;
Stream requestStream = httpWebRequest2.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer,0,tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer,0,tempBuffer.Length );
requestStream.Close();
WebResponse webResponse2 = httpWebRequest2.GetResponse();
Stream stream2 = webResponse2.GetResponseStream();
StreamReader reader2 = new StreamReader(stream2);
webResponse2.Close();
httpWebRequest2 = null;
webResponse2 = null;
}

Categories