.Net Task reporting progress? - c#

I have a task that runs that uploads a byte array through a web service. I want to report the progress whenever it hits 10, 20, 30, 40 etc percent. In order to update that in the DB though, i need to pass a guid to the web service to identify the file reporting progress. I cannot reach that object from inside the task though. Any ideas?
Entry point:
Guid smGuid;
smGuid = Guid.NewGuid();
Task t1 = new Task(action, pubAttFullPath);
t1.Start();
string attFullFilePath = System.IO.Path.GetFullPath(
mailItem.Attachments[i].FileName);
string attExtension = System.IO.Path.GetExtension(
mailItem.Attachments[i].FileName);
pubAttFullPath = attFullFilePath;
pubAttFileName = mailItem.Attachments[i].FileName;
Task Code:
Action<object> action = (object obj) =>
{
//Set filename from object
string FileName;
FileName = System.IO.Path.GetFileName(obj.ToString());
//Declare Web Service
TransferFile.TransferFile ws_TransferFile = new TransferFile.TransferFile();
//
bool transfercompleted = false;
using (FileStream fs = new FileStream(
obj.ToString(),
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
//Declare Buffers and Counts
byte[] buffer = new byte[49152];
long fileSize = fs.Length;
long totalReadCount = 0;
int readCount;
int currentPacketNumber = 0;
int percentageComplete = 0;
//Loop and copy file until it changes to not exactly the same byte count as the buffer
//which means the file is about to complete.
while ((readCount = fs.Read(buffer, 0, buffer.Length)) > 0)
{
if (!transfercompleted)
{
totalReadCount += readCount;
byte[] bytesToTransfer;
if (readCount == buffer.Length)
{
//Copy bytes until buffer is different
bytesToTransfer = buffer;
ws_TransferFile.WriteBinaryFile(bytesToTransfer, FileName);
percentageComplete = (int)(totalReadCount / (double)fileSize * 100);
}
else
{
// Only a part is requred to upload,
// copy that part.
List<byte> b = new List<byte>(buffer);
bytesToTransfer = b.GetRange(0, readCount).ToArray();
ws_TransferFile.WriteBinaryFile(bytesToTransfer, FileName);
percentageComplete = 100;
transfercompleted = true;
fs.Close();
break;
}
}
}
}
};

How about just passing it in as a bound variable?
Guid smGuid;
smGuid = Guid.NewGuid();
Task t1 = new Task( _ => action( smGuid, pubAttFullPath ), null );
t1.Start();
Task code:
Action<Guid, string> action = (smGuid, FileName) =>
{
//Declare Web Service
TransferFile.TransferFile ws_TransferFile = new TransferFile.TransferFile();
//
bool transfercompleted = false;
// And so on...
}

Related

is there any way to get data from service to web api

I am trying sending the data of file in chunks to web api through worker service. But chunks can not be received by web api, here is my code
Here is some code of worker service
int chunkSize = 100;
using (Stream streamx = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[chunkSize];
int bytesRead = 0;
long bytesToRead = streamx.Length;
while (bytesToRead > 0)
{
int n = streamx.Read(buffer, 0, chunkSize);
if (n == 0) break;
// Let's resize the last incomplete buffer
if (n != buffer.Length)
Array.Resize(ref buffer, n);
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent byteContent = new ByteArrayContent(buffer);
form.Add(byteContent, "fileByte");
HttpResponseMessage response1 = null;
try
{
response1 = client.PostAsync("http://localhost:15594/weatherforecast/PostData", form).Result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
var k = response1.Content.ReadAsStringAsync().Result;
response = null;
bytesRead += n;
bytesToRead -= n;
}
Here is some code of web api
[HttpPost]
[Route("PostData")]
public IActionResult PostData()
{
var request = HttpContext.Request;
var vals = request.Form.TryGetValue("fileByte", out StringValues sv).ToString();
NameValueCollection vals2 = new NameValueCollection();
int count = vals2.Count;
string cv = null;
foreach(var i in vals2)
{
cv += i;
}
}
Here I have solved the issue, basically I want to upload a file in chunks ,
Here the code of file uploading to webapi ,
int chunkSize = 1024
using (Stream streamx = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[chunkSize];
int bytesRead = 0;
long bytesToRead = streamx.Length;
while (bytesToRead > 0)
{
int n = streamx.Read(buffer, 0, chunkSize);
if (n == 0) break;
if (n != buffer.Length)
Array.Resize(ref buffer, n);
MultipartFormDataContent multiContent = new MultipartFormDataContent();
ByteArrayContent bytes = new ByteArrayContent(buffer);
multiContent.Add(bytes, "file", fi.Name);
HttpResponseMessage response1 = null;
try
{
response1 = client.PostAsync("http://localhost:15594/weatherforecast/PostData", multiContent).Result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
var k = response1.Content.ReadAsStringAsync().Result;
response = null;
bytesRead += n;
bytesToRead -= n;
}
}
'''
here is code snippet of webapi
'''
[HttpPost]
[Route("PostData")]
public IActionResult PostData()
{​​​​​​​
var form = Request.Form;
foreach (var formFile in form.Files)
{​​​​​​​
var fileName = formFile.FileName;
var savePath = Path.Combine(#"E:\Program\_210302_1WebApplication_API\_210302_1WebApplication_API\wwwroot", fileName);
using (var fileStream = new FileStream(savePath, FileMode.Append))
{​​​​​​​
formFile.CopyTo(fileStream);
}​​​​​​​
}​​​​​​​
}​​​​​​​
'''

How receive bitmap's continuously from android on C# Socket?

I'm working in a remote administration tool to my own use and the project is stopped because a error on receiver function on Server side that is this.:
Arithmetic operation resulted in an overflow. (Adding integers)
in this line:
var imageData = new byte[length];
void server_Received(Listener l, Info i, string received) {
string[] cmd = received.Split('|');
switch (cmd[1])
{
case "PRINT":
//MessageBox.Show("print");
Thread threadPrint;
threadPrint = new Thread(() =>
{
var lengthData = new byte[4];
var lengthBytesRead = 0;
while (lengthBytesRead < lengthData.Length)
{
var read = i.sock.Receive(lengthData, lengthBytesRead, lengthData.Length - lengthBytesRead, SocketFlags.None);
if (read == 0) return;
lengthBytesRead += read;
}
var length = BitConverter.ToInt32(lengthData, 0);
var imageData = new byte[length];
var imageBytesRead = 0;
while (imageBytesRead < imageData.Length)
{
var read = i.sock.Receive(imageData, imageBytesRead, imageData.Length - imageBytesRead, SocketFlags.None);
if (read == 0) return;
imageBytesRead += read;
}
using (var stream = new MemoryStream(imageData))
{
var bitmap = new Bitmap(stream);
Invoke(new ImageCompleteDelegate(ImageComplete), new object[] { bitmap });
}
});
threadPrint.Start();
break;
}
}
the code to receiver i taked from this reference (see Client code) and was adapted to my need like you can see above.
Here is how i'm sending the bitmap on android (Java):
try {
dos = new DataOutputStream(SocketBackgroundService.xclientSocket.getOutputStream());
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(dos)
)
);
out.println("|PRINT|");
out.flush();
dos.writeInt(array.length);
dos.write(array, 0, array.length);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
Then, i want know what can be done to solve this trouble?
Thanks in advance.
The solution was insert:
Array.Reverse(lengthData);
before of:
var length = BitConverter.ToInt32(lengthData, 0);

Downloading file error: Cannot convert type

I'm trying to download a file from my DropBox account.
I get an error with
var task = Task.Run((Func<Task>)Download("", "largetest.mpk", folderName));
The error:
Cannot convert type 'System.Threading.Tasks.Task' to 'System.Func<System.Threading.Tasks.Task>
private void button1_Click(object sender, EventArgs e)
{
string folderName = #"c:\dropboxTest\test.exe";
var task = Task.Run((Func<Task>)Download("", "largetest.mpk", folderName));
task.Wait();
}
async Task Download(string folder, string targetfile, string localPath)
{
var dbx = new DropboxClient(Form1.api);
var response = await dbx.Files.DownloadAsync(folder + "/" + targetfile);
ulong fileSize = response.Response.Size;
const int bufferSize = 1024 * 1024;
var buffer = new byte[bufferSize];
string folderName = #"C:\dropboxTest\teasdfst.exe";
using (var stream = await response.GetContentAsStreamAsync())
{
using (var localfile = new FileStream(folderName, FileMode.OpenOrCreate))
{
var length = stream.Read(buffer, 0, bufferSize);
while (length > 0)
{
localfile.Write(buffer, 0, length);
// Console.WriteLine(localfile.);
var percentage = 100 * (ulong)localfile.Length / fileSize;
// Update progress bar with the percentage.
// progressBar.Value = (int)percentage
//Console.WriteLine(percentage);
length = stream.Read(buffer, 0, bufferSize);
}
}
}
}
You should write your function like this
void Download(string folder, string targetfile, string localPath)
{
var dbx = new DropboxClient(Form1.api);
var response = dbx.Files.Download(folder + "/" + targetfile);
ulong fileSize = response.Response.Size;
const int bufferSize = 1024 * 1024;
var buffer = new byte[bufferSize];
string folderName = #"C:\dropboxTest\teasdfst.exe";
using (var stream = response.GetContentAsStream())
{
using (var localfile = new FileStream(folderName, FileMode.OpenOrCreate))
{
var length = stream.Read(buffer, 0, bufferSize);
while (length > 0)
{
localfile.Write(buffer, 0, length);
// Console.WriteLine(localfile.);
var percentage = 100 * (ulong)localfile.Length / fileSize;
// Update progress bar with the percentage.
// progressBar.Value = (int)percentage
//Console.WriteLine(percentage);
length = stream.Read(buffer, 0, bufferSize);
}
}
}
}
and then call with Task.Run like below
private void button1_Click(object sender, EventArgs e)
{
string folderName = #"c:\dropboxTest\test.exe";
var task = Task.Run(() => Download("", "largetest.mpk", folderName));
task.Wait(); // remove this if you don't want to block UI thread.
}
Hope this helps !!
You do not need to do all of that. No conversions, no casts, no Task.Run.
Just write
const string folderName = #"c:\dropboxTest\test";
private async void button1_Click(object sender, EventArgs e)
{
await Download("", "largetest.mpk", folderName);
}
Note that we directly await the method call. Note how the call to Task.Wait has been removed.
Note that except in the case of event handlers, which need to be void methods, async methods should return Task objects. This is very important, especially for proper exception handling. This is the only case where async void is proper.
Your Download method, which should be renamed to DownloadAsync by convention, already has the proper return type Task and should not be changed in that regard.

How to split file into parts and download

I'm working on a split downloader for c#. It is downloading fine (so the logic is working) but the problem is that whatever file it downloads it corrupts. I have no idea on how to fix it. Here's the code:
private void mergeClean()
{
const int chunkSize = 1 * 1024; // 2KB
using (var output = File.Create("output.jpg"))
{
foreach (var file in Files)
{
using (var input = File.OpenRead(file))
{
var buffer = new byte[chunkSize];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
}
foreach (var file in Files)
{
File.Delete(file);
}
}
private void SaveFileStream(String path, Stream stream)
{
var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
stream.CopyTo(fileStream);
fileStream.Dispose();
}
public void SplitDownload(string URL)
{
System.Net.WebRequest req = System.Net.HttpWebRequest.Create(URL);
req.Method = "HEAD";
System.Net.WebResponse resp = req.GetResponse();
var responseLength = double.Parse(resp.Headers.Get("Content-Length"));
var partSize = Math.Ceiling(responseLength / 10);
var previous = 0;
for (int i = (int)partSize; i <= responseLength; i = i + (int)partSize)
{
Thread t = new Thread(() => Download(URL, previous, i));
t.Start();
t.Join();
previous = i;
}
mergeClean();
}
private void Download(string URL, int Start, int End)
{
Console.WriteLine(String.Format("{0},{1}", Start, End));
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(URL);
myHttpWebRequest.AddRange(Start, End);
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
Stream streamResponse = myHttpWebResponse.GetResponseStream();
String name = GenerateTempName();
SaveFileStream(name, streamResponse);
Files.Add(name);
}
Here is an example of what it does:
UPDATED CODE:
static string GenerateTempName(int start)
{
String name = String.Format("{0:D6}.tmp", start);
return name;
}
static public List<string> Files = new List<string>();
static private void mergeClean()
{
Files.Sort();
const int chunkSize = 1 * 1024; // 2KB
using (var output = File.Create("output.jpg"))
{
foreach (var file in Files)
{
using (var input = File.OpenRead(file))
{
var buffer = new byte[chunkSize];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
}
foreach (var file in Files)
{
File.Delete(file);
}
}
You need to recombine file from pieces in correct order - current code create random file names and even if items are added to list of files they are added in random order due to unpredictable time when segment download finishes.
Possible fix: use block start offset as part of the file name String name = String.Format("file{0:D6}.tmp", Start) and sort files by name before combining them back.
Note that {0:D6} formatting is used to pad index with 0 to allow sorting by name to be easier and avoid need for natural sort code.

Silverlight becomes unresponsive when downloading a file

I'm trying to use the following snippet in order download files via the SaveFileDialog in Silverlight:
public void SaveMediaLocal(string fileName)
{
FileInfo fInfo = new FileInfo(fileName);
if (fInfo.Exists)
{
if (fInfo.Length > 0)
{
string extension = fInfo.Extension;
SaveFileDialog dialog = new SaveFileDialog()
{
DefaultExt = extension,
Filter = String.Format("{1} files (*.{0})|*.{0}|All files (*.*)|*.*", extension, fInfo.Extension),
FilterIndex = 1,
DefaultFileName = fInfo.Name
};
if (dialog.ShowDialog() == true)
{
try
{
bool cancelFlag = false;
byte[] buffer = new byte[1024 * 1024]; // 1GB buffer
using (FileStream dest = (FileStream)dialog.OpenFile())
{
using (FileStream source = new FileStream(fInfo.FullName, FileMode.Open, FileAccess.Read))
{
long fileLength = source.Length;
long totalBytes = 0;
int currentBlockSize = 0;
while ((currentBlockSize = source.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytes += currentBlockSize;
double percentage = (double)totalBytes * 100.0 / fileLength;
dest.Write(buffer, 0, currentBlockSize);
}
}
}
}
catch
{
}
}
}
else
{
//no results
}
}
}
When I use this snippet; Silverlight freezes until the download completes.
When I use this snippet instead, the UI is responsive, but doesn't work on bigger files.
using (Stream stream = dialog.OpenFile())
{
Byte[] bytes = File.ReadAllBytes(fileName);
stream.Write(bytes, 0, bytes.Length);
}
Is there something that I'm missing here?
Don't do the operation on the GUI thread. That is why it gets unresponsive. Either create a new thread or async process and do the operation in the background.

Categories

Resources