I have auto-upload application from ftp server and two progressbar's to update overall and current download state.
First one works fine (update% = currentFile as int / allFilesToDownload *100%). But i'd like to upload current file downloading.
My code:
Uri url = new Uri(sUrlToDnldFile);
int inde = files.ToList().IndexOf(file);
string subPath = ...
bool IsExists = System.IO.Directory.Exists(subPath);
if (!IsExists)
System.IO.Directory.CreateDirectory(subPath);
sFileSavePath = ...
System.Net.FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(new Uri(file));
System.Net.FtpWebResponse response = (System.Net.FtpWebResponse)request.GetResponse();
response.Close();
long iSize = response.ContentLength;
long iRunningByteTotal = 0;
WebClient client = new WebClient();
Stream strRemote = client.OpenRead(url);
FileStream strLocal = new FileStream(sFileSavePath, FileMode.Create, FileAccess.Write, FileShare.None);
int iByteSize = 0;
byte[] byteBuffer = new byte[1024];
while ((iByteSize = strRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
strLocal.Write(byteBuffer, 0, iByteSize);
iRunningByteTotal += iByteSize;
//THERE I'D LIKE TO UPLOAD CURRENT FILE DOWNLOAD STATUS
string a = iByteSize.ToString();
double b = double.Parse(a.ToString()) / 100;
string[] c = b.ToString().Split(',');
int d = int.Parse(c[0].ToString());
update(d);
//update(int prog) { bgWorker2.ReportProgress(prog); }
}
double dIndex = (double)(iRunningByteTotal);
double dTotal = (double)iSize;
// THIS CODE COUNTING OVERAL PROGRESS - WORKS FINE
double iProgressPercentage1 = double.Parse(ind.ToString()) / double.Parse(files.Count().ToString()) * 100;
ind++;
string[] tab = iProgressPercentage1.ToString().Split(',');
int iProgressPercentage = int.Parse(tab[0]);
currentFile = file;
bgWorker1.ReportProgress(iProgressPercentage);
strRemote.Close();
Unfortunately i still getting error, that I cant update progressBar2, becouse another process using it.
Is there any way to do it?
Thanks
update values thru dispatcher.BeginInvoke Methods something like.
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(()=>
{
progressbar2.value = newvalue;
}));
This Dispatcher Will push you work to the main thread which is holding the Progressbar2.
Related
I've been trying to upload files to my OneDrive via HTTP Requests following this document (https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_createuploadsession?view=odsp-graph-online) without success. I have the following steps rounded up (Authentication, folder creation for the file, create an upload session) but when I try the last step, byte upload to the created session, I get this error in the second PUT request:
Requested Range Not Satisfiable {"error":{"code":"invalidRange","message":"Optimistic concurrency failure during fragmented upload"}}
This is my code:
//Get File Data
byte[] FileByteArray = File.ReadAllBytes(FilePath);
//Create Upload Session
OutlookEndpoint = $"{AppSettings.DriveSettings.OneDriveSettings.Endpoint}/me/drive/items/{FolderId}:/{Name}:/createuploadsession";
OutlookResponseMessage = await OutlookClient.PostAsync(OutlookEndpoint, new StringContent("{}", Encoding.UTF8, "application/json"));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
OutlookUpload OutlookUpload = JsonConvert.DeserializeObject<OutlookUpload>(OutlookResponseContent);
//Check the Created URL
if (!string.IsNullOrEmpty(OutlookUpload.UploadUrl))
{
//Chunk Calculation
int TotalSize = FileByteArray.Length;
int AcumulativeSize = 0;
int ChunkSize = 327680;
int ChunkBuffer = ChunkSize;
int ChunkNumber = TotalSize / ChunkSize;
int ChunkLeftover = TotalSize - ChunkSize * ChunkNumber;
int ChunkCounter = 0;
while (true)
{
if (ChunkNumber == ChunkCounter)
{
ChunkSize = ChunkLeftover;
}
byte[] ChunkData = FileByteArray.Skip(ChunkBuffer * ChunkCounter).Take(ChunkSize).ToArray();
AcumulativeSize += ChunkData.Length;
//PUT Upload of Chunk
string UploadEndpoint = OutlookUpload.UploadUrl;
string BytesHeader = $"bytes {AcumulativeSize - ChunkSize}-{AcumulativeSize - 1}/{TotalSize}";
OutlookClient.DefaultRequestHeaders.Clear();
OutlookClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
OutlookClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Length", ChunkSize.ToString());
OutlookClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Range", BytesHeader);
OutlookResponseMessage = await OutlookClient.PutAsync(UploadEndpoint, new ByteArrayContent(ChunkData));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("SUCCESS");
}
else
{
Console.WriteLine(OutlookResponseMessage.ReasonPhrase);
}
if (ChunkNumber == ChunkCounter)
{
break;
}
ChunkCounter++;
}
}
}
Perhaps I'm missing something. I only get a SUCCESS message in the first PUT request, the others always give me the error described above. Here's an image of the error with the headers I send. Image
I'd appreciate any help, thanks for reading this far.
EDIT:
Got it working after modifying the the header configuration for the request and changing the way chunks are created.
//Get File Data
byte[] FileByteArray = File.ReadAllBytes(FilePath);
//Create Upload Session
OutlookEndpoint = $"{AppSettings.DriveSettings.OneDriveSettings.Endpoint}/me/drive/items/{FolderId}:/{Name}:/createuploadsession";
OutlookResponseMessage = await OutlookClient.PostAsync(OutlookEndpoint, new StringContent("{}", Encoding.UTF8, "application/json"));
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
OutlookUpload OutlookUpload = JsonConvert.DeserializeObject<OutlookUpload>(OutlookResponseContent);
//Check the Created URL
if (!string.IsNullOrEmpty(OutlookUpload.UploadUrl))
{
using MemoryStream FileStream = new MemoryStream(FileByteArray);
//Chunk Calculation
int ChunkSize = 320 * 1024;
int ChunkRemaining = 0;
byte[] ByteBuffer = new byte[ChunkSize];
int BytesRead = 0;
while ((BytesRead = FileStream.Read(ByteBuffer, 0, ByteBuffer.Length)) > 0)
{
if (BytesRead < ChunkSize)
{
byte[] LastBuffer = new byte[BytesRead];
Buffer.BlockCopy(ByteBuffer, 0, LastBuffer, 0, BytesRead);
ByteBuffer = new byte[BytesRead];
ByteBuffer = LastBuffer;
}
try
{
OutlookClient.DefaultRequestHeaders.Clear();
string UploadEndpoint = OutlookUpload.UploadUrl;
string BytesHeader = $"bytes {ChunkRemaining}-{ChunkRemaining + ByteBuffer.Length - 1}/{FileByteArray.Length}";
HttpRequestMessage MicrosoftResponseMessage = new HttpRequestMessage()
{
Content = new ByteArrayContent(ByteBuffer),
RequestUri = new Uri(UploadEndpoint),
Method = HttpMethod.Put,
};
MicrosoftResponseMessage.Content.Headers.Add("Content-Length", ByteBuffer.Length.ToString());
MicrosoftResponseMessage.Content.Headers.Add("Content-Range", BytesHeader);
OutlookResponseMessage = await OutlookClient.SendAsync(MicrosoftResponseMessage);
OutlookResponseContent = await OutlookResponseMessage.Content.ReadAsStringAsync();
if (OutlookResponseMessage.IsSuccessStatusCode)
{
Console.WriteLine("SUCCESS");
ChunkRemaining += ByteBuffer.Length;
if (ChunkRemaining == FileByteArray.Length)
{
Console.WriteLine("COMPLETED");
}
}
else
{
Console.WriteLine(OutlookResponseMessage.ReasonPhrase);
}
}
catch (Exception Exception)
{
Console.WriteLine(Exception.Message);
break;
}
}
}
}
Please note that on failures when the client sent a fragment the server had already received, the server will respond with HTTP 416 Requested Range Not Satisfiable. You can request upload status to get a more detailed list of missing ranges. Apparently the content-range and content-length were the problem. You changed the header configuration from the HttpClient to a HttpRequestMessage and it worked perfectly now.
So i have a method that does an invoke on a datagridview and works fine for the first thread that runs it, however when a second thread tries to utilise the method, the download part of it still functions, however the invoke statement stops working for the first thread and starts to change both
public void ByteTransferResume(int indexResume)
{
HttpWebRequest req;
HttpWebResponse resp;
req = (HttpWebRequest)HttpWebRequest.Create(FileLocationName);
req.AddRange((int)fileInfoDestination.Length);
resp = (HttpWebResponse)(req.GetResponse());
long fileLength = resp.ContentLength;
FileLocationLength = fileLength;
using (Stream responseStream = resp.GetResponseStream())
{
int iBufferSize = 1024;
iBufferSize *= 1000;
using (FileStream saveFileStream = new FileStream(FileDestination, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
int iByteSize;
byte[] downBuffer = new byte[iBufferSize];
while ((iByteSize = responseStream.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
saveFileStream.Write(downBuffer, 0, iByteSize);
FileInfo fileInfoDestinations = new FileInfo(FileDestination);
FileDestinationLength = (int)fileInfoDestinations.Length;
double downloadProgress = ((double)FileDestinationLength / FileLocationLength) * 100;
// MessageBox.Show(downloadProgress.ToString());
dgvDownloadInfo.Invoke(new dgvCommandDelegate(DGVCommand), new object[] { $"UPDATE Download_Info SET [Progress] = '{downloadProgress:F2}%' WHERE [File Name] = '{thread1[indexResume].Name}'" });
//MessageBox.Show(thread1[indexResume].Name);
//MessageBox.Show(indexResume.ToString());
// dgvDownloadInfo.Invoke(new dgvConnectionDelegate(DGVConnection));
Thread.Sleep(10);
}
}
}
}
Maybe this will help you:
public object _lock = new object();
public void ByteTransferResume(int indexResume)
{
lock (_lock)
{
HttpWebRequest req;
//rest of your method
}
}
I am trying to develop an app that will upload large files to a web server running PHP. Almost immediately, I stumbled upon a problem that the file is not split correctly.
Currently I have this piece of code
string adrese = "c:\\directory\\file.jpg";
int garums = 16384;
String ext = Path.GetExtension(adrese);
FileStream file = /*/File.Open(adrese, FileMode.Open);/*/
new FileStream(adrese, FileMode.Open, System.IO.FileAccess.Read);
long fgar = file.Length; //100%
long counter = garums;
first = true;
byte[] chunk = new byte[garums];
while (true)
{
int index = 0;
//long Controll = counter+garums;
while (index < chunk.Length)
{
int bytesRead = file.Read(chunk, index, chunk.Length - index);
if (bytesRead == 0)
{
/*byte[] biti = new byte[index];
for (int i = 0; i < index; i++)
{
biti[i] = chunk[i];
}
chunk = new byte[index];
chunk = biti;*/
break;
}
index += bytesRead;
}
if (index != 0) // Our previous chunk may have been the last one
{
byte[] biti = new byte[index];
for (int i = 0; i < index; i++)
{
biti[i] = chunk[i];
}
chunk = new byte[index];
chunk = biti;
// index is the number of bytes in the chunk
sutam(Convert.ToBase64String(chunk),ext);
}
double procentuali = ((counter * 100) / fgar);
if (procentuali > 99)
{
procentuali = 100;
}
progressBar1.Value = (int)Math.Round(procentuali);
label1.Text = "" + procentuali;
counter = counter+garums;
if (index != garums) // We didn't read a full chunk: we're done
{
return;
}
}
file.Close();
Everything works if I set garums to 1, but who will wait for a year or so to upload a file sized multiple GB's.
I would be pleased if you could tell me what is wrong and how to fix this.
Try this instead to upload in chunks:
private void ConvertToChunks()
{
//Open file
string file = MapPath("~/temp/1.xps");
FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
//Chunk size that will be sent to Server
int chunkSize = 1024;
// Unique file name
string fileName = Guid.NewGuid() + Path.GetExtension(file);
int totalChunks = (int)Math.Ceiling((double)fileStream.Length / chunkSize);
// Loop through the whole stream and send it chunk by chunk;
for (int i = 0; i < totalChunks; i++)
{
int startIndex = i * chunkSize;
int endIndex = (int)(startIndex + chunkSize > fileStream.Length ? fileStream.Length : startIndex + chunkSize);
int length = endIndex - startIndex;
byte[] bytes = new byte[length];
fileStream.Read(bytes, 0, bytes.Length);
ChunkRequest(fileName, bytes);
}
}
private void ChunkRequest(string fileName,byte[] buffer)
{
//Request url, Method=post Length and data.
string requestURL = "http://localhost:63654/hello.ashx";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestURL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// Chunk(buffer) is converted to Base64 string that will be convert to Bytes on the handler.
string requestParameters = #"fileName=" + fileName + "&data=" + HttpUtility.UrlEncode( Convert.ToBase64String(buffer) );
// finally whole request will be converted to bytes that will be transferred to HttpHandler
byte[] byteData = Encoding.UTF8.GetBytes(requestParameters);
request.ContentLength = byteData.Length;
Stream writer = request.GetRequestStream();
writer.Write(byteData, 0, byteData.Length);
writer.Close();
// here we will receive the response from HttpHandler
StreamReader stIn = new StreamReader(request.GetResponse().GetResponseStream());
string strResponse = stIn.ReadToEnd();
stIn.Close();
}
i have written a little "Update Programm" to keep an .exe up to date for the rest of my dev team. It used to work fine, but suddenly it stopped working.
I already noticed the problem: my remote stream does not start to read.
Uri patch = new Uri("http://********/*********/" + GetVersion().ToString() + ".exe");
Int64 patchsize = PatchSize(patch);
var CurrentPath = String.Format("{0}\\", Environment.CurrentDirectory);
Int64 IntSizeTotal = 0;
Int64 IntRunning = 0;
string strNextPatch = (version + ".exe");
using (System.Net.WebClient client = new System.Net.WebClient())
{
using (System.IO.Stream streamRemote = client.OpenRead(patch))
{
using (System.IO.Stream streamLocal = new FileStream(CurrentPath + strNextPatch, FileMode.Create, FileAccess.Write, FileShare.None))
{
int intByteSize = 0;
byte[] byteBuffer = new Byte[IntSizeTotal];
while ((intByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
streamLocal.Write(byteBuffer, 0, intByteSize);
IntRunning += intByteSize;
double dIndex = (double)(IntRunning);
double dTotal = (double)byteBuffer.Length;
double dProgressPercentage = (dIndex / dTotal);
int intProgressPercentage = (int)(dProgressPercentage * 100);
worker.ReportProgress(intProgressPercentage);
}
streamLocal.Close();
}
streamRemote.Close();
GetVersion() only returns the current version number of the current server version of the .exe.
The problem lies here:
while ((intByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
My streamRemote just does not return any bytes so this while clause is not filled.
Any advice for me?
I believe the problem is on the server. I'd run some checks:
Has anything changed on the configuration of the web server that stops you from downloading executables?
Are you connecting through a proxy?
Can you manually get to the same URL (under the same user credentials of your application)?
First,I uploaded a file in a external server and got a url from that server.Now i want to download that uploaded file from the external server through that url which i got from that server through asp.net and c#.
I wrote a c# code to download that file, but during that process i got an exception
"Exception of type 'System.OutOfMemoryException' was thrown".
The following is the c# code which i wrote to download:
double dlsize=0;
string Url = "http://www.sample.com/download.zip"; \\File Size: 75MB
int lastindex = Url.LastIndexOf("/");
string TempUrlName = Url.Substring(lastindex + 1, Url.Length - (lastindex + 1));
WebRequest oWebRequest = WebRequest.Create(Url);
oWebRequest.Timeout = -1;
WebResponse oWebResponse = oWebRequest.GetResponse();
if (oWebResponse.ContentType != "text/html; charset=UTF-8")
{
string myFile = oWebResponse.Headers.Get("Content-Length");
int TempmyFile = Convert.ToInt32(myFile);
double bytes_total = Convert.ToDouble(TempmyFile);
dlSize = Convert.ToDouble(bytes_total / (1024 * 1024));
System.IO.MemoryStream oMemoryStream = new MemoryStream();
byte[] buffer = new byte[4096];
using (System.IO.Stream oStream = oWebResponse.GetResponseStream())
{
int Count = 0;
do
{
Count = oStream.Read(buffer, 0, buffer.Length);
oMemoryStream.Write(buffer, 0, Count);
} while (Count != 0);
}
System.IO.FileStream oFileStream = new System.IO.FileStream("C:\Documents and Settings\arun\Desktop\New Folder\download.zip", System.IO.FileMode.Create);
oMemoryStream.WriteTo(oFileStream);
oFileStream.Flush();
oFileStream.Close();
oMemoryStream.Flush();
oMemoryStream.Close();
oWebResponse.Close();
}
It would be easier to do it like this:
WebClient webClient = new WebClient();
webClient.DownloadFile(remoteFileUrl, localFileName);