Upload a File to WebDAV using HttpClient PUT in Windows Universal App? - c#

I used WebClient for uploading a file with few headers and it worked perfectly. But now I am creating a universal app using HttpClient. I don't understanding how to add file path to request header. Please see the following code:
public async void testUploadFile()
{
string url = "http://localhost/webdav/";
string filepath = #"C:\mydata\file-1.txt";
string resource_name = Path.GetFileName(filepath);
url += resource_name;
HttpMultipartFormDataContent multipart = new HttpMultipartFormDataContent();
multipart.Headers.Add("RequestId", "abc");
multipart.Headers.Add("UserId", "apple");
multipart.Headers.Add("SessionId", "ssdfsd22");
Stream stream = new System.IO.MemoryStream();
HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
multipart.Add(streamContent);
httpClient = new HttpClient();
HttpResponseMessage respMesg =await httpClient.PutAsync(new Uri(url), multipart);
Debug.WriteLine(respMesg.Content);
}
Can anyone sort out this issue? Thank you in advance!

The following code works for one time upload:
public async void testFileUploadWebDAV()
{
string url = "http://localhost/webdav/";
string userId = "xxx";
string sessionId = "yyy";
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);
var filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add("*");
filePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
StorageFile file = await filePicker.PickSingleFileAsync();
url += file.Name;
httpClient = new HttpClient(filter);
msg = new HttpRequestMessage(new HttpMethod("PUT"), new Uri(url));
httpClient.DefaultRequestHeaders.Add("RequestId", file.DisplayName);
httpClient.DefaultRequestHeaders.Add("UserId", userId);
httpClient.DefaultRequestHeaders.Add("SessionId", sessionId);
httpClient.DefaultRequestHeaders.Add("ContentType", file.ContentType);
Certificate cert = msg.TransportInformation.ServerCertificate;
//-----------------ADD FILE CONTENT TO BODY-----------
HttpStreamContent content = new HttpStreamContent(await file.OpenReadAsync());
try
{
HttpResponseMessage httpResponseContent = await httpClient.PutAsync(new Uri(url), content);
Debug.WriteLine(httpResponseContent.ToString());
if (httpResponseContent.IsSuccessStatusCode)
{
msg.Dispose();
httpClient.Dispose();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}

#Brajesh's answer was super helpful for me, but I needed a .NET Core solution. In particular, I found there to be some issues with encoding support in .NET Core, so I couldn't just pass an StreamContent into the httpClient.PutAsync method. Please see below for the .NET Core equivalent:
public static async void writeToWebDAV(string sourceFilename, Stream httpStream)
{
//As described above, decoding must be forced as UTF8 default returns some strange results
var content = Encoding.GetEncoding("iso-8859-1").GetString(readToEnd(httpStream));
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("RequestId", sourceFilename);
//Be sure user:pass is in Base64 encoding, can use this resource https://www.base64encode.org/
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic dXNlcjpwYXNzd29yZA==");
StringContent c = new StringContent(content, Encoding.UTF8);
try
{
HttpResponseMessage httpResponseContent = await httpClient.PutAsync(
new Uri(Path.Combine(#"https://randomhost.com:5009/shareFolder", sourceFilename)), c);
if (httpResponseContent.IsSuccessStatusCode)
httpClient.Dispose();
else
{
try
{
//occasionally the server will respond with the WWW-Authenticate header in which case you need to re-PUT the file
//described here: https://stackoverflow.com/questions/32393846/webdav-return-401-how-to-authenticate
HttpResponseMessage httpResponseContent = await httpClient.PutAsync(
new Uri(Path.Combine(#"https://randomhost.com:5009/shareFolder", sourceFilename)), c);
if (httpResponseContent.IsSuccessStatusCode)
httpClient.Dispose();
else if (httpResponseContent.StatusCode.ToString() == "401")
Console.WriteLine("WebDAV Authentication Error...");
}
catch (Exception ex)
{ Console.WriteLine(ex.Message); }
}
}
catch (Exception ex)
{ Console.WriteLine(ex.Message); }
}
}
//Taken from StackOverflow: https://stackoverflow.com/questions/1080442/how-to-convert-an-stream-into-a-byte-in-c
public static byte[] readToEnd(Stream stream)
{
long originalPosition = 0;
if (stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if (stream.CanSeek)
stream.Position = originalPosition;
}
}

Related

Get the file postion of each file into a stream

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

How to resolve 400 error with bad request in update api when it is deployed

I am getting 400 error code with bad request while request to file upload API.
I built the back-end and front-end for file uploading in asp.net core and it works in localhost when I run it with IIS in my PC (using visual studio 2017).
Both of saving and updating API are working in my local but update API is not working if I deploy the code
front-end code like below:
public static async Task<HttpResponseMessage> UploadFile(string uploadUrl, string filePath, FFFileInfo fileInfo)
{
string fileName = fileInfo.Name + "." + fileInfo.Extension;
string contentType = MimeTypes.GetMimeType(filePath);
using (var hc = new HttpClient())
{
hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(TokenType, AccessToken);
hc.DefaultRequestHeaders.Accept.Clear();
hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
StreamContent streamContent = CreateFileContent(fileStream, fileName, contentType);
// StreamContent streamContent = CreateFileContent(fileStream, "image.jpg", "image/jpeg"); // Multiple file upload
var requestContent = new MultipartFormDataContent("Upload Id" + DateTime.Now.ToString(CultureInfo.InvariantCulture));
requestContent.Add(streamContent, fileInfo.Name, fileName);
var progressContent = new ProgressableStreamContent(
requestContent,
4096,
(sent, total) =>
{
//Console.WriteLine("Uploading {0}/{1}", sent, total);
int percentage = (int) Math.Round((double)(100 * sent) / total);
Console.Write("\r{0}\t{1}%", fileInfo.Path, percentage);
if (sent == total)
{
Console.WriteLine();
}
});
var response = await hc.PostAsync(new Uri(uploadUrl), progressContent);
return response;
}
}
backend code like below:
[HttpPost]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadFiles([FromQuery] FFFileInfo fileinfo)
{
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
}
authUser = User.ToAuthUser();
userId = authUser.UserId();
customerId = authUser.CustomerId();
Server.Model.File new_file = new Server.Model.File();
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
MemoryStream writeStream = new MemoryStream();
byte[] content = null;
while (section != null)
{
ContentDispositionHeaderValue contentDisposition;
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
int chunkSize = 1024;
byte[] byte_file = new byte[chunkSize];
int bytesRead = 0;
new_file.File_Content = byte_file;
if (hasContentDispositionHeader)
{
if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
{
//await section.Body.CopyToAsync(targetStream);
using (var byte_reader = new BinaryReader(section.Body))
{
do
{
bytesRead = byte_reader.Read(byte_file, 0, byte_file.Length);
if(bytesRead <= 0)
{
content = writeStream.ToArray();
}
writeStream.Write(byte_file, 0, bytesRead);
} while (bytesRead > 0);
content = writeStream.ToArray();
}
}
}
// Drains any remaining section body that has not been consumed and
// reads the headers for the next section.
section = await reader.ReadNextSectionAsync();
}
try
{
new_file = new Server.Model.File
{
File_Name = fileinfo.Name,
File_Path = fileinfo.Path,
File_Ext = fileinfo.Extension,
Check_Sum = fileinfo.Checksum,
ToolSerialNumber = fileinfo.ToolSerialNumber,
FileSize = fileinfo.Length,
File_Content = content,
UserId = userId,
CustomerId = customerId
};
}
catch (Exception ex)
{
return BadRequest(ex);
}
try
{
if (!fileService.isExist(new_file.File_Path, userId))
{
fileService.SaveFile(new_file);
}
else
{
Server.Model.File existing = fileService.GetFileByPath(new_file.File_Path, userId);
fileService.UpdateFile(existing, new_file);
}
//set file content to null to response with small data
new_file.File_Content = null;
return Ok(new_file);
}
catch (Exception ex)
{
logger.LogError("DB action error {0}", ex.ToString());
return BadRequest(ex);
}
}
As you can see the above code, saving and updating are using same code but only updating is not working when it is deployed.
It is very strange for me.
I found the solution.
This code was deployed by my client I couldn't check the database that he deployed.
Based on researching and testing, I got an idea that might be related with permission issue.
So, we check it for db.
At the end, we found that current user has insert, delete, select permission but have not update permission.
After granting the update permission, it is working perfectly

Problems with streaming video for IOS Client (Server developed on ASP.NET WEB API 2)

I have a problem with streaming video. I developed the server on ASP.NET Web API 2 and implemented 2 methods:
The first method:
if (Request.Headers.Range != null)
{
try
{
var httpResponce = Request.CreateResponse();
httpResponce.Content =
new PushStreamContent((Action<Stream, HttpContent, TransportContext>) WriteContentToStream);
return httpResponce;
}
catch (Exception ex)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
else
{
return new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable);
}
/*method for streaming*/
private async void WriteContentToStream(Stream outputStream, HttpContent content, TransportContext transportContext)
{
string relativeFilePath = "~/App_Data/Videos/4.mp4";
try
{
var filePath = System.Web.Hosting.HostingEnvironment.MapPath(relativeFilePath);
int bufferSize = 1000;
byte[] buffer = new byte[bufferSize];
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
int totalSize = (int)fileStream.Length;
while (totalSize > 0)
{
int count = totalSize > bufferSize ? bufferSize : totalSize;
int sizeOfReadedBuffer = fileStream.Read(buffer, 0, count);
await outputStream.WriteAsync(buffer, 0, sizeOfReadedBuffer);
totalSize -= sizeOfReadedBuffer;
}
}
}
catch (HttpException ex)
{
if (ex.ErrorCode == -2147023667)
{
return;
}
}
finally
{
outputStream.Close();
}
}
2) The second method:
public HttpResponseMessage Test()
{
if (Request.Headers.Range != null)
{
try
{
string relativeFilePath = "~/App_Data/Videos/4.mp4";
var filePath = System.Web.Hosting.HostingEnvironment.MapPath(relativeFilePath);
HttpResponseMessage partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
partialResponse.Headers.AcceptRanges.Add("bytes");
var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
partialResponse.Content = new ByteRangeStreamContent(stream, Request.Headers.Range, new MediaTypeHeaderValue("video/mp4"));
return partialResponse;
}
catch (Exception)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
else
{
return new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable);
}
}
Both of these methods worked on Web-client and Android-client, but iOS-client doesn't show video.
I think, that problem may be with codec of video (but I used codecs, which recommend Apple) or http-headers.
I just solved this one, and it was because the Content-Length header had (what iOS considered to be) an invalid value.
My solution was based on method #2 above...
Here's the important part of my code that actually worked.
if (!file.Exists) {
response.StatusCode = HttpStatusCode.NotFound;
response.ReasonPhrase = "Deleted";
} else {
var range = Request.Headers.Range?.Ranges?.FirstOrDefault();
if (range == null) {
using (var stream = new MemoryStream()) {
using (var video = file.OpenRead()) await video.CopyToAsync(stream);
response.Content = new ByteArrayContent(stream.ToArray());
}
response.Content.Headers.ContentType = new MediaTypeHeaderValue("video/mp4");
response.Content.Headers.ContentLength = file.Length;
} else {
var stream = new MemoryStream();
using (var video = file.OpenRead()) await video.CopyToAsync(stream);
response.Content = new ByteRangeStreamContent(
stream,
new RangeHeaderValue(range.From, range.To),
new MediaTypeHeaderValue("video/mp4")
);
// response.Content.Headers.ContentLength = file.Length;
// this is what makes iOS work
response.Content.Headers.ContentLength = (range.To.HasValue ? range.To.Value + 1 : file.Length) - (range.From ?? 0);
}
response.StatusCode = HttpStatusCode.OK;
}
I should probably put in an HTTP 206 (partial content) status when dealing with ranges, but I was working on this for nearly two days before coming up with a solution.
The only problem I have yet to fully track down is that from time-to-time, the Application_EndRequest doesn't fire for some of these. I am able to log the response being sent by the endpoint, but it's like iOS disconnects the connection somewhere and the request hangs until it times out internally.
Check HLS streaming which required for iOS. You can not play video file directly pointing to video file.
https://developer.apple.com/streaming/

C#: HttpClient, File upload progress when uploading multiple file as MultipartFormDataContent

I'm using this code to upload multiple files and it working very well. It uses modernhttpclient library.
public async Task<string> PostImages (int platform, string url, List<byte []> imageList)
{
try {
int count = 1;
var requestContent = new MultipartFormDataContent ();
foreach (var image in imageList) {
var imageContent = new ByteArrayContent (image);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
requestContent.Add (imageContent, "image" + count, "image.jpg");
count++;
}
var cookieHandler = new NativeCookieHandler ();
var messageHandler = new NativeMessageHandler (false, false, cookieHandler);
cookieHandler.SetCookies (cookies);
using (var client = new HttpClient (messageHandler)) {
client.DefaultRequestHeaders.TryAddWithoutValidation ("User-Agent", GetUserAgent (platform));
using (var r = await client.PostAsync (url, requestContent)) {
string result = await r.Content.ReadAsStringAsync ();
System.Diagnostics.Debug.WriteLine ("PostAsync: " + result);
return result;
}
}
} catch (Exception e) {
System.Diagnostics.Debug.WriteLine (e.Message);
return null;
}
}
Now I need the progress when uploading the files. I searched in google and found I need to use ProgressStreamContent
https://github.com/paulcbetts/ModernHttpClient/issues/80
Since ProgressStreamContent contains a constructor that takes a stream, I converted the MultipartFormDataContent to stream and used it in its constructor. But, its not working. Upload fails. I think its because it is a stream of all the files together which is not what my back end is expecting.
public async Task<string> PostImages (int platform, string url, List<byte []> imageList)
{
try {
int count = 1;
var requestContent = new MultipartFormDataContent ();
// here you can specify boundary if you need---^
foreach (var image in imageList) {
var imageContent = new ByteArrayContent (image);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
requestContent.Add (imageContent, "image" + count, "image.jpg");
count++;
}
var cookieHandler = new NativeCookieHandler ();
var messageHandler = new NativeMessageHandler (false, false, cookieHandler);
cookieHandler.SetCookies (RestApiPaths.cookies);
var stream = await requestContent.ReadAsStreamAsync ();
var client = new HttpClient (messageHandler);
client.DefaultRequestHeaders.TryAddWithoutValidation ("User-Agent", RestApiPaths.GetUserAgent (platform));
var request = new HttpRequestMessage (HttpMethod.Post, url);
var progressContent = new ProgressStreamContent (stream, 4096);
progressContent.Progress = (bytes, totalBytes, totalBytesExpected) => {
Console.WriteLine ("Uploading {0}/{1}", totalBytes, totalBytesExpected);
};
request.Content = progressContent;
var response = await client.SendAsync (request);
string result = await response.Content.ReadAsStringAsync ();
System.Diagnostics.Debug.WriteLine ("PostAsync: " + result);
return result;
} catch (Exception e) {
System.Diagnostics.Debug.WriteLine (e.Message);
return null;
}
}
What should I do here to get this working? Any help is appreciated
I have a working version of ProgressableStreamContent. Please note, I am adding headers in the constructor, this is a bug in original ProgressStreamContent that it does not add headers !!
internal class ProgressableStreamContent : HttpContent
{
/// <summary>
/// Lets keep buffer of 20kb
/// </summary>
private const int defaultBufferSize = 5*4096;
private HttpContent content;
private int bufferSize;
//private bool contentConsumed;
private Action<long,long> progress;
public ProgressableStreamContent(HttpContent content, Action<long,long> progress) : this(content, defaultBufferSize, progress) { }
public ProgressableStreamContent(HttpContent content, int bufferSize, Action<long,long> progress)
{
if (content == null)
{
throw new ArgumentNullException("content");
}
if (bufferSize <= 0)
{
throw new ArgumentOutOfRangeException("bufferSize");
}
this.content = content;
this.bufferSize = bufferSize;
this.progress = progress;
foreach (var h in content.Headers) {
this.Headers.Add(h.Key,h.Value);
}
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return Task.Run(async () =>
{
var buffer = new Byte[this.bufferSize];
long size;
TryComputeLength(out size);
var uploaded = 0;
using (var sinput = await content.ReadAsStreamAsync())
{
while (true)
{
var length = sinput.Read(buffer, 0, buffer.Length);
if (length <= 0) break;
//downloader.Uploaded = uploaded += length;
uploaded += length;
progress?.Invoke(uploaded, size);
//System.Diagnostics.Debug.WriteLine($"Bytes sent {uploaded} of {size}");
stream.Write(buffer, 0, length);
stream.Flush();
}
}
stream.Flush();
});
}
protected override bool TryComputeLength(out long length)
{
length = content.Headers.ContentLength.GetValueOrDefault();
return true;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
content.Dispose();
}
base.Dispose(disposing);
}
}
Also note, it expects HttpContent, not stream.
This is how you can use it.
var progressContent = new ProgressableStreamContent (
requestContent,
4096,
(sent,total) => {
Console.WriteLine ("Uploading {0}/{1}", sent, total);
});

Http post method hanging before getting response using c# [duplicate]

Failed to get response for large file HTTP put create file using c#
I am using file watcher service service monitor, when user created file or folder we are uploading to cloud
if file size more than 512 MB it is taking too much time to get the response
here I am confusing here the issue with my code or server
and reason for this error
if any changes on my code suggest me.
{
var fileFolderObj1 = new FileFolder();
var postURL = apiBaseUri + "/filefolder/create/file/user/" + userId; // +"?type=file";
code = HttpStatusCode.OK;
HttpWebResponse response = null;
FileInfo f = new FileInfo(filePath);
long filesizeF = f.Length;
try
{
string selectedFile = null;
selectedFile = filePath;
var fi = System.IO.Path.GetFileName(filePath);
////commented for some reason
var postParameters = new Dictionary<string, object>();
postParameters.Add("file", new FileParameter(filePath, ""));
postParameters.Add("parentId", parentId);
postParameters.Add("newName", fi);
postParameters.Add("cloudId", cloudId);
postParameters.Add("isSecure", isSecure);
//postParameters.Add("fileSize", fi.Length);
postParameters.Add("fileSize", filesizeF);
var userAgent = "Desktop";
var formDataBoundary = "----WebKitFormBoundary" + DateTime.Now.Ticks.ToString("x");
var uri = new Uri(postURL);
var createFileRequest = WebRequest.Create(uri) as HttpWebRequest;
this.SetBasicAuthHeader(createFileRequest, userId, password);
createFileRequest.ContentType = "multipart/form-data";
createFileRequest.Method = "PUT";
createFileRequest.Timeout = System.Threading.Timeout.Infinite;
createFileRequest.KeepAlive = false;/*true;*/
createFileRequest.UserAgent = userAgent;
createFileRequest.CookieContainer = new CookieContainer();
try
{
using (var requestStream = createFileRequest.GetRequestStream())
{
}
using (response = (HttpWebResponse)createFileRequest.GetResponse())
{
StreamReader(response.GetResponseStream()).ReadToEnd();
fileFolderObj1 = JsonConvert.DeserializeObject<FileFolder>(reslut);
}
}
catch (Exception exc)
{
if (response != null)
{
code = response.StatusCode;
}
}
}
catch (Exception exc)
{
}
}
}
private static readonly Encoding encoding = Encoding.UTF8;
private void WriteMultipartFormData(Dictionary<string, object> postParameters, string boundary, Stream requestStream, ILogService logService = null)
{
var needsCLRF = false;
foreach (var param in postParameters)
{
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
{
requestStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
}
needsCLRF = true;
if (param.Value is FileParameter)
{
var fileToUpload = (FileParameter)param.Value;
// Add just the first part of this param, since we will write the file data directly to the Stream
var header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
boundary,
param.Key,
fileToUpload.FileName ?? param.Key,
fileToUpload.ContentType ?? "application/octet-stream");
requestStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));
// Write the file data directly to the Stream, rather than serializing it to a string.
FileStream fileStream = new FileStream(fileToUpload.FileName, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[4096];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0,buffer.Length)) != 0)
{
requestStream.Write(buffer, 0, bytesRead);
logService.Debug("WRITEMULTIPART FORM DATA Bufferlent Running :{0}", bytesRead);
}
fileStream.Close();
}
else
{
var postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
boundary,
param.Key,
param.Value);
requestStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
}
}
// Add the end of the request. Start with a newline
var footer = "\r\n--" + boundary + "--\r\n";
requestStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
}
}

Categories

Resources