Multiple processes in one button - c#

First of all hello guys i just wanted to add button that downloads zip files from link and then unzips and i ran into problems i get this error:
"System.IO.IOException: 'The process cannot access the file
'C:\GTA\TEST.zip' because it is being used by another process.'"
It looks really simple but i can't solve it so i hope you guys help me. this is code:
private void button2_Click(object sender, EventArgs e)
{
string root = #"C:\GTA";
//this if directory doesn't exist
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
progressBar1.Value = 0;
WebClient webcl = new WebClient();
webcl.DownloadFileCompleted += Webcl_DownloadFileCompleted;
webcl.DownloadProgressChanged += Webcl_DownloadProgressChanged;
webcl.DownloadFileAsync(new Uri("https://download1474.mediafire.com/17r5hin4vceg/izkb8vk7pudg5g4/TEST.zip"), #"C:\GTA\TEST.zip");
string targetfolder = #"C:\GTA\UNZIPEDFolder";
string sourceZipFile = #"C:\GTA\TEST.zip";
ZipFile.ExtractToDirectory(sourceZipFile, targetfolder);
}

I'm no expert here, however you get the file asynchronosly without awaiting it.
DownloadFileAsync
So you make a call to extract the file while it's being downloaded.

You calling ExtractToDirectory before file will be actually downloaded, as file downloading is async. So, you need to await when downloading process will finish. To do so, you will need the following
make the whole event click handler async - private async void button2_Click(object sender, EventArgs e).
replace DownloadFileAsync which returns void and thus is not async/await-friendly with DownloadFileTaskAsync, which is awaitable.
Then you will able to await downloading with await webcl.DownloadFileTaskAsync(...args here...);
finally, you can remove DownloadFileCompleted subscription, as you may be sure that after await the file downloading is completed.
By the way, WebClient is considered as an old API and is not recommended for using in the new code. You may consider to switch to HttpClient.

To elaborate a bit on the two previous answers, you are in fact trying to unzip the file before you have downloaded it. You should change your code as follows:
private async void button2_Click(object sender, EventArgs e)
{
string root = #"C:\GTA";
//this if directory doesn't exist
if (!Directory.Exists(root))
{
Directory.CreateDirectory(root);
}
progressBar1.Value = 0;
WebClient webcl = new WebClient();
webcl.DownloadFileCompleted += Webcl_DownloadFileCompleted;
webcl.DownloadProgressChanged += Webcl_DownloadProgressChanged;
await webcl.DownloadFileAsync(new Uri("https://download1474.mediafire.com/17r5hin4vceg/izkb8vk7pudg5g4/TEST.zip"), #"C:\GTA\TEST.zip");
string targetfolder = #"C:\GTA\UNZIPEDFolder";
string sourceZipFile = #"C:\GTA\TEST.zip";
ZipFile.ExtractToDirectory(sourceZipFile, targetfolder);
}
Note the async as well as the await before DownloadFileAsync().
Additionally, you might want to refactor that a bit and move the download / unzip part out of the Button Event Handler.

Related

Asynchronous functions in Xamarin C# Android - Application stuck with thread

I'm trying to figure out a bug in my C# Xamarin Android code. Simple thing this application is ought to do - connect to the REST API, download the contents as a string for further analysis. At first my mistake was not including async tasks and using voids instead, but when I changed them the code seems to be stuck at point of retrieval of data.
String content;
private void OnClick1(object sender, EventArgs e)
{
output.Text = "";
GetJSONTextFromWeb("https://ameobea.me/osutrack/api/get_changes.php?user=XXXXXX&mode=0", "XXXXXX", "0");
while (content==null)
{
DoNothing();
}
output.Text = content;
}
private async Task GetJSONTextFromWeb(String address, String user, String modeID)
{
URL url = new URL(address);
URLConnection conn = url.OpenConnection();
//conn.AddRequestProperty("user", user); those lines are
//conn.AddRequestProperty("mode", modeID); removed for investigation.
//conn.Connect(); //this one caused the same issue.
content = (String)conn.Content; //Here the code seems to freeze without any warning.
}
private void DoNothing()
{
//literally. Made to await for the result.
}
Anyone knows the possible reason?
I'd suggest swapping out the use of that particular library in favor of the System.Http assembly, it's supported in Xamarin and is a lot better documented. I'd change your above code to something like below (Don't forget to declare System.Net.Http in the same place that you've declared your other assemblies).
using System.Net.Http;
async private void OnClick1(object sender, EventArgs e)
{
output.Text = "";
// await the return of a string from the url address
// awaiting this removes the need for the pointless while loop you were doing
content = await GetJSONTextFromWeb("https://ameobea.me/osutrack/api/get_changes.php?user=XXXXXX&mode=0");
output.Text = content;
}
private async Task<string> GetJSONTextFromWeb(String address)
{
// The library you were using is a poorly documented port from a JAVA library
// I'd suggest using the http library, it's supported in Xamarin and has better docs
var client = new HttpClient();
var data = await client.GetStringAsync(address);
return data;
}

WebClient DownloadString with TextChanged Event C#

I have an trouble in C# program which using php scripts to translate words and download the result string into TextBox.
My program has two TextBoxes
txtWord, txtTranslatedWord
and that's the simplified code
WebClient c = new WebClient();
private void txtWord_TextChanged(object sender, EventArgs e)
{
string response = c.DownloadString("http://example.com/Services/Translator/lang/EnglishToArabic.php?Word=" + txtWord.Text);
switch (response.ToLower())
{
case "not exist":
{
txtTranslatedWord.Text = "{Sorry but no translation for this word!}";
break;
}
default:
{
txtTranslatedWord.Text = response;
break;
}
}
}
The problem its when the text is changed the program lagging and looks like it would Stopped Working.
The program worked successfully but after so much lagging ,
especially if the writer is writing so fast.
I tried BackgroundWorker and make an delay like when user stop writing for 2 second then program start to translate but still lagging without any luck.
Is there any easy way to do this without problems?
Try to use asynchrony.
WebClient does not support concurrent I/O operations, so will be use HttpClient.
HttpClient client = new HttpClient();
private async void txtWord_TextChanged(object sender, EventArgs e)
{
var response = await client.GetStringAsync(
"http://example.com/Services/Translator/lang/EnglishToArabic.php?Word=" + txtWord.Text);
switch (response.ToLower())
{
case "not exist":
{
txtTranslatedWord.Text = "{Sorry but no translation for this word!}";
break;
}
default:
{
txtTranslatedWord.Text = response;
break;
}
}
}
Your problem is that every character your user types into the textbox results in a WebClient download that has to complete before the next keypress can be accepted. I'd suggest you do the following...
Create a timer that starts or restarts each time the user enters a character and that when expires disables the textbox and runs the search before re-enabling the textbox. You'd also do well to use an asynchronous WebClient call.

UWP share feature not working in Windows 10 Mobile

I have created a very simple UWP application with a single button. Clicking it should show the built-in share popup to share a PDF file.
The fact is that I have it working for Windows 10 (Desktop) but it doesn't work for mobile (the popup doesn't appear on the screen).
The PDF file comes as a byte array (because it will come from a remote service).
This is the code in MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DataTransferManager.GetForCurrentView().DataRequested += OnDataRequested;
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
// This should come from a service
PdfBytes = await Microsoft.Toolkit.Uwp.StorageFileHelper.ReadBytesFromPackagedFileAsync("Document.pdf");
}
public byte[] PdfBytes { get; set; }
private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
var si = await StorageFile.CreateStreamedFileAsync("Document.pdf", stream =>
{
var writeStream = stream.AsStreamForWrite();
writeStream.Write(PdfBytes, 0, PdfBytes.Length);
stream.Dispose();
}, null);
args.Request.Data.Properties.Title = "PDF Document";
args.Request.Data.Properties.Description = "Some description";
args.Request.Data.SetStorageItems(new IStorageItem[] { si });
deferral.Complete();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
DataTransferManager.ShowShareUI();
}
}
Is it correct? If it's not, how should I share the PDF (from its bytes)?
Thank you for your feedback. It seems that CreateStreamedFileAsync method does not work properly with Share contract in Mobile. We've logged this issue internally and I will update here once there is any progress.
For now, as a workaround, you can store the file in TemporaryFolder first and then share it like the following:
private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
var tempFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("Document.pdf", CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBytesAsync(tempFile, PdfBytes);
args.Request.Data.Properties.Title = "PDF Document";
args.Request.Data.Properties.Description = "Some description";
args.Request.Data.SetStorageItems(new IStorageItem[] { tempFile });
deferral.Complete();
}
Temporary app data store is the right place for data that you don’t want persisted after the current app session. The system can delete data stored at this location as needed to free up space. You can use it for any intermediate or temporary files. If you are writing large amounts of data to Temp, it is a good idea to clear it when your app is initialized to avoid the system or the user having to take action to free up storage. And you can do this by calling:
await ApplicationData.ClearAsync(ApplicationDataLocality.Temporary);
You have similar issue I had I believe
Have you tried changing
private async void OnDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
var deferral = args.Request.GetDeferral();
var si = await StorageFile.CreateStreamedFileAsync("Document.pdf", stream =>
{
var writeStream = stream.AsStreamForWrite();
writeStream.Write(PdfBytes, 0, PdfBytes.Length);
stream.Dispose();
args.Request.Data.Properties.Title = "PDF Document";
args.Request.Data.Properties.Description = "Some description";
args.Request.Data.SetStorageItems(new IStorageItem[] { si });
deferral.Complete();
}, null);
}
I havent checked this code, so it probably wont compile but I have found that I had issue that looks similar to yours, if threads are involved. Take look at my issue here UWP DataTransferManager ShowShareUI() Opens Sharing Dialog with "This app can't share right now" and Closes it Immediately After
I faced the same issue, My share worked good in desktop application but not in mobile. After big struggle I found that the deferral is not working in windows 10 mobile.
So better remove these lines and try. Its working
var deferral = args.Request.GetDeferral();
deferral.Complete();

Why UploadProgressChanged in WebClient.UploadFileAsync work not correctly?

I'm upload file and get upload progress like this:
using (var wc = new WebClient())
{
wc.UploadProgressChanged += FileUploadProgressChanged;
wc.Headers.Add(HttpRequestHeader.ContentType, "image/png");
wc.UploadFileAsync(new Uri(url), filePath);
}
...
private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
ProgressBarUpload.Value = e.ProgressPercentage;
}
But after 50% e.ProgressPercentage return -441850 and then immediately returns 100. Why is this happening?
My solution:
private void FileUploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
ProgressBarUpload.Value = e.BytesSent * 100 / e.TotalBytesToSend;
}
I also found two questions similar to this, but I have not managed to solve the problem. But it can be useful to others:
WebClient UploadFileAsync strange behaviour in progress reporting (cause of the problem - problems with authorization)
Uploading HTTP progress tracking (cause of the problem - the third-party application)
Note. Аfter downloading the file we receive a response from the server, it would be better to display the download file is 95% and the remaining 5% leave to display the response from the server. And in the end after a successful download and response from the server, we will be 100%.
PS: In the code, I did not show it, just say to those who might need it.

DownladAsyncFile checking the file download completion

Is there any way to know which file has just now finished downloading from the DownloadFileCompleted event of WebClient.
Thanks in advance.
You can use UserState to do this. Something like this
WebClient client = new WebClient();
client.DownloadDataCompleted +=
new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
client.DownloadDataAsync(new Uri("YourURL"), "YourIdentifier");
Handler
static void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
var calledBy = e.UserState; //This will be "YourIdentifier"
}
Hope this works for you.
When downloading file use webClient.DownloadFileAsync(uri, name, state) method.
This 3rd parameter (state) will be sent to your in the UserState property of the DownloadFileCompleted event arguments.
Just pass the uri or the file name there and you will have it back nicely :)

Categories