Downloading a file from AWS S3 in Xamarin iOS Hangs mostly - c#

I am trying to download an XML file of size 85MB in my Xamarin iOS iPad App.
Sometimes download completes successfully, but other times download hangs inbetween somewhere without giving any error. Progress stops.
AWS SDK version:
AWSSDK.S3 3.3.20.4
AWSSDK.Core 3.3.24.8
I tried both methods 1- TransferUtility 2- GetObject.
Here is my code:
var clientRequest = new AmazonS3Client(AWSAccessKey,
AWSSecretKey,
Amazon.RegionEndpoint.USEast1);
try
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = AWSBucketName,
Key = Path + "File1.xml"
};
using (GetObjectResponse response = await clientRequest.GetObjectAsync(request))
{
response.WriteObjectProgressEvent += displayDownloadProgress;
await response.WriteResponseStreamToFileAsync(destPath, false);
}
}
catch (AmazonS3Exception e)
{
Console.WriteLine("Error encountered ***. Message:'{0}' when writing an object", e.Message);
}
catch (Exception e)
{
Console.WriteLine("Unknown encountered on server. Message:'{0}' when writing an object", e.Message);
}
I tried both methods one by one.
var utility = new TransferUtility(cas.AWSAccessKey,
cas.AWSSecretKey,
Amazon.RegionEndpoint.USEast1);
TransferUtilityDownloadRequest dr = new TransferUtilityDownloadRequest();
dr.BucketName = AWSBucketName;
dr.Key = Path + "File1.xml";
dr.FilePath = destPath;
dr.WriteObjectProgressEvent += displayDownloadProgress;
await utility.DownloadAsync(dr);
public void displayDownloadProgress(object sender, WriteObjectProgressArgs args)
{
Debug.WriteLine("Download Progress: " + (args.PercentDone));
InvokeOnMainThread(() =>
{
BTProgressHUD.ShowContinuousProgress("Download Progress: " + args.PercentDone.ToString() + "%", ProgressHUD.MaskType.Gradient);
});
if (args.PercentDone >= 100)
{
BTProgressHUD.Dismiss();
}
}

Related

How i can set delay method to my upload function C#

I am using upload function in my desktop application. i want if upload function become unsuccessful then this method retry to upload it. Currently when upload is unsuccessful then it be me error of unhandled exception .i need solution of this
**This is function**
async Task Uploaded()
{
using (var dbx = new DropboxClient(token))
{
bmp = new Bitmap(picboxcapture.Image);
string folder = "/folder/"+Login.recuser+"";
string filename = DateTime.Now.ToString() + " " + " " + MyTodo_Project.rectsk + ".JPG";
string URL = picboxcapture.Image.ToString();
ImageConverter converter = new ImageConverter();
MemoryStream(File.ReadAllBytes(#"C:\Users\home\Downloads\FazalNEwTEst.JPG"));
byte[] bytes = (byte[])converter.ConvertTo(picboxcapture.Image, typeof(byte[]));
var mem = new MemoryStream(bytes);
var updated = dbx.Files.UploadAsync(folder + "/" + filename,
WriteMode.Overwrite.Instance, body: mem);
updated.Wait();
var tx = dbx.Sharing.CreateSharedLinkWithSettingsAsync(folder + "/" + filename);
tx.Wait();
URL = tx.Result.Url;
}
}
**The function call**
private async void save_Load(object sender, EventArgs e)
{
await Uploaded();
}
I want that when upload unsuccessful then it will retry to upload it in page load event . how can
i do this in C#
Just write your own retry handler. Or use Polly (recommended, as it's a mature and very successful library).
However, this is an example of how you might build your own.
Given
public class RetriesExceededException : Exception
{
public RetriesExceededException() { }
public RetriesExceededException(string message) : base(message) { }
public RetriesExceededException(string message, Exception innerException) : base(message, innerException) { }
}
public static async Task RetryOnExceptionAsync(int retryCount, int msDelay, Func<Task> func)
{
for (var i = 0; i < retryCount; i++)
{
try
{
await func.Invoke();
return;
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
if (i == retryCount - 1)
throw new RetriesExceededException($"{retryCount} retries failed", ex);
}
await Task.Delay(msDelay)
.ConfigureAwait(false);
}
}
Usage
await RetryOnExceptionAsync(3, 1000, Uploaded);

C# Console application pause working until right click on Console

I'm building a c# console application which read messages from MSMQ(Microsoft Message Queuing), I expected it to run forever but after a day running it stop reading message from MSMQ until I right click on its Console, my problem seems to be alittle bit similar to this: "Console Application "pausing" c#". Bellow is the function that I'm using:
private static void downloadHandler(object args)
{
while (true)
{
while (CURRENT_ACTIVE_THREAD < MAX_THREAD)
{
DownloadController.WriteLog("Current active Thread = " + CURRENT_ACTIVE_THREAD);
Console.WriteLine("Current active Thread = " + CURRENT_ACTIVE_THREAD);
Thread.Sleep(1000);
MessageQueue messageQueue;
if (MessageQueue.Exists(messageQueuePath))
{
messageQueue = new MessageQueue(messageQueuePath);
Message requestMessage = messageQueue.Receive();
try
{
requestMessage.Formatter = new BinaryMessageFormatter();
string msg = requestMessage.Body.ToString();
if (!string.IsNullOrEmpty(msg))
{
DownloadController.WriteLog("received message with message = " + msg);
CURRENT_ACTIVE_THREAD += 1;
RequestDownload request = new RequestDownload();
request = JsonConvert.DeserializeObject<RequestDownload>(msg);
DownloadController.WriteLog("received message with contentId = " + request.contentId + "from message queue | title= " + request.contentTitle + " | url = " + request.baseURL);
DownloadController downloader = new DownloadController();
Thread t = new Thread(new ParameterizedThreadStart(downloader.findURLandDownload));
object[] objs = new object[2];
objs[0] = request;
objs[1] = "1";
t.Start(objs);
Console.WriteLine("received message with contentId = " + request.contentId);
}
}
catch (Exception ex)
{
CURRENT_ACTIVE_THREAD -= 1;
Console.WriteLine("Exception: " + ex.Message);
DownloadController.WriteLog("There is exception while trying to read message from message queue, Exception = " + ex.Message);
}
}
}
}
}
So,could anyone please tell me what the problem is? Why this happening?
It might be you're while loop. I had while loops freeze or break my applications before. Might i suggest using timers instead ? I have some links you could use for reference:
c# wait for a while without blocking
https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
I do hope this fixes the problem you're having !
greatings,
Ramon.

Nested Async Download - Async within Async

I have some nested async methods calling each other and it is confusing. I am trying to convert a project which downloads the files in an async download.
On the click of the download button this is the method triggered:
private async void enableOfflineModeToolStripMenuItem_Click(object sender, EventArgs e)
{
for(int i = 0; i < _playlists.Count; i++)
{
DoubleDimList.Add(new List<String>());
for(int j = 0; j < 5; j++)
{
string sMp3 = IniReadValue(_playlists[i], "Track " + j);
DoubleDimList[i].Add(sMp3);
}
await Task.Run(() => _InetGetHTMLSearchAsyncs(DoubleDimList[i]));
}
}
It creates a 2d List which at the end looks like this DoubleDimList[3][20].
At the end of each sublist I am doing an async download as you can see. The method looks like this
private async Task _InetGetHTMLSearchAsyncs(List<string> urlList)
{
foreach (var url in urlList)
{
await Task.Run(() => _InetGetHTMLSearchAsync(url));
}
}
the _InetGetHTMLSearchAsync method looks like this and here is where it gets tricky
private async Task _InetGetHTMLSearchAsync(string sTitle)
{
Runs++;
if (AudioDumpQuery == string.Empty)
{
//return string.Empty;
}
string sResearchURL = "http://www.audiodump.biz/music.html?" + AudioDumpQuery + sTitle.Replace(" ", "+");
try
{
using (var client = new WebClient())
{
client.Headers.Add("Referer", #"http://www.audiodump.com/");
client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A");
client.DownloadStringCompleted += Client_DownloadStringCompleted;
await Task.Run(() => client.DownloadStringAsync(new Uri(sResearchURL)));
}
}
catch (Exception ex)
{
Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace);
Console.WriteLine("Runs: " + Runs);
return;
}
}
On Client_DownloadStringCompleted there is another async method called. Here it is
private async void Client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
string[] sStringArray;
string aRet = e.Result;
string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline);
if (aTable != null)
{
string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\"");
if (aInfos != null)
{
for (int i = 0; i < 1; i++)
{
sStringArray = aInfos[i].Split('*');
sStringArray[0] = sStringArray[0].Replace("'", "'");
aLinks.Add(sStringArray[0]);
}
await Task.Run(() => DownloadFile(aLinks[FilesDownloaded]));
}
}
}
From there, surprise! Another async call.
private async Task DownloadFile(string url)
{
try
{
using (var client = new WebClient())
{
client.Headers.Add("Referer", #"http://www.audiodump.biz/");
client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A");
client.DownloadFileCompleted += Client_DownloadFileCompleted;
await Task.Run(() => client.DownloadFileTaskAsync(url, mp3Path + "\\" + count + ".mp3"));
}
}
catch (Exception Ex)
{
Console.WriteLine("File download error: " + Ex.StackTrace);
}
}
Now the first part after the creation of the 2d List is to retrieve the download links of the mp3s. The second part is to download the mp3 as soon as a valid URL was provided. It works but in a bizarre way. Instead of downloading the file normally(1st, 2nd, 3rd...), it will download randomly the files(1st, 5th, 8th...).
It is my first go for async download and boy, I am already far from my limits.
Where am I messing this up? And the main question, will this ever work the way it is supposed to work?
Your code looks pretty good, except for two things:
You shouldn't be using Task.Run. The primary use case for Task.Run is for moving CPU-bound work off a GUI thread so it doesn't block the UI. I have a series on the proper use of Task.Run that goes into this in detail.
You should use a consistent asynchronous pattern, ideally TAP. Your code is currently using TAP everywhere except in _InetGetHTMLSearchAsync, which is using EAP. This is what is causing the odd behavior you're seeing.
A fixed _InetGetHTMLSearchAsync would look something like this:
private async Task _InetGetHTMLSearchAsync(string sTitle)
{
Runs++;
string sResearchURL = "http://www.audiodump.biz/music.html?" + AudioDumpQuery + sTitle.Replace(" ", "+");
try
{
using (var client = new WebClient())
{
client.Headers.Add("Referer", #"http://www.audiodump.com/");
client.Headers.Add("user-agent", "Mozilla / 5.0(Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.75.14(KHTML, like Gecko) Version / 7.0.3 Safari / 7046A194A");
string[] sStringArray;
string aRet = await client.DownloadStringTaskAsync(new Uri(sResearchURL));
string[] aTable = _StringBetween(aRet, "<BR><table", "table><BR>", RegexOptions.Singleline);
if (aTable != null)
{
string[] aInfos = _StringBetween(aTable[0], ". <a href=\"", "<a href=\"");
if (aInfos != null)
{
for (int i = 0; i < 1; i++)
{
sStringArray = aInfos[i].Split('*');
sStringArray[0] = sStringArray[0].Replace("'", "'");
aLinks.Add(sStringArray[0]);
}
await DownloadFile(aLinks[FilesDownloaded]); // Should really be called "DownloadFileAsync"
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Debug message: " + ex.Message + "InnerEx: " + ex.StackTrace);
Console.WriteLine("Runs: " + Runs);
return;
}
}

C# WebClient Downloads empty file

I'm working on an app that uses Bing's API to search and download images.
Bing's API provides a set of image links and I iterate over them and download each one.
The problem that I'm having is that sometimes the downloaded file size is 0Kb.
I assume that happens because WebClient first creates the filename and then tries to write to it. So when it can't write to it for some reason this happens. The problem is that it happens without throwing an exception so my 'Catch' statement can't catch this and delete the file.
public void imageFetcher(string performerName, int maxNumberOfImages, RichTextBox richTextBox)
{
string performersDirPath = Environment.CurrentDirectory + #"\Performers\";
string performerPath = performersDirPath + performerName + #"\";
if (!Directory.Exists(performersDirPath))
{
Directory.CreateDirectory(performersDirPath);
}
if (!Directory.Exists(performerPath))
{
Directory.CreateDirectory(performerPath);
}
// Searching for Images using bing api
IEnumerable<Bing.ImageResult> bingSearch = bingImageSearch(performerName);
int i = 0;
foreach (var result in bingSearch)
{
downloadImage(result.MediaUrl, performerPath + performerName + i + ".jpg",richTextBox);
i++;
if (i == maxNumberOfImages)
{
break;
}
}
}
The download method:
public void downloadImage(string imgUrl, string saveDestination, RichTextBox richTextBox)
{
if (File.Exists(saveDestination))
{
richTextBox.ForeColor = System.Drawing.Color.Red;
richTextBox.AppendText("The File: " + saveDestination + "Already exists");
}
else
{
try
{
using (WebClient client = new WebClient())
{
client.DownloadFileCompleted += new AsyncCompletedEventHandler(((sender, e) => downloadFinished(sender, e, saveDestination , richTextBox)));
Uri imgURI = new Uri(imgUrl, UriKind.Absolute);
client.DownloadFileAsync(imgURI, saveDestination);
}
}
catch (Exception e)
{
richTextBox.AppendText("There was an exception downloading the file" + imgUrl);
richTextBox.AppendText("Deleteing" + saveDestination);
File.Delete(saveDestination);
richTextBox.AppendText("File deleted!");
}
}
}
This happens also when I try to wait for the client to finish using:
client.DownloadFileAsync(imgURI, saveDestination);
while (client.IsBusy)
{
}
Can anyone please tell me what I'm doing wrong?
In other simular question the solution was to keep the Webclient instance open until download is finished.. I'm doing this with this loop:
while (client.IsBusy){}
Yet the results are the same.
Update:
I resorted to not use webclient, instead I used this code:
try
{
byte[] lnBuffer;
byte[] lnFile;
using (BinaryReader lxBR = new BinaryReader(stream))
{
using (MemoryStream lxMS = new MemoryStream())
{
lnBuffer = lxBR.ReadBytes(1024);
while (lnBuffer.Length > 0)
{
lxMS.Write(lnBuffer, 0, lnBuffer.Length);
lnBuffer = lxBR.ReadBytes(1024);
}
lnFile = new byte[(int)lxMS.Length];
lxMS.Position = 0;
lxMS.Read(lnFile, 0, lnFile.Length);
}
using (System.IO.FileStream lxFS = new FileStream(saveDestination, FileMode.Create))
{
lxFS.Write(lnFile, 0, lnFile.Length);
}
This solves the problem almost complelty, there are still one or two 0KB files but I assume it's because of network errors.
To see possible exceptions - try changing DownloadFileAsync to just DownloadFile - my problem was "Can not create SSL/TLS secure channel". Hope this will help someone.

DownloadFile works, DownloadFileAsync gets 0 bytes file

I'm trying to download git from this url
https://github.com/msysgit/msysgit/releases/download/Git-1.9.5-preview20150319/Git-1.9.5-preview20150319.exe
I did it using DownloadFile, it worked OK.
Now I try to do it with Async method, but it downloads 0 byte file. Here's the code:
public void downloadFile(string urlAddress, string location)
{
using (var downloadClient = new WebClient())
{
downloadClient.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(Completed);
downloadClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
Uri URL = urlAddress.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ? new Uri(urlAddress) : new Uri("http://" + urlAddress);
_downloadStopWatch.Start();
try
{
downloadClient.DownloadFileAsync(URL, location);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
_downloadStopWatch.Stop();
while (downloadClient.IsBusy) { }
}
}
where:
private string _location = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\test.exe";
And urlAddress is typed into textbox and passed textbox.text
I check the Completed handler and it says completed.
Why am I getting 0 byte file?
The completed methods parameter AsyncCompletedEventArgs returns an error The remote name could not be resolved: 'https'.
In that case you should fall back to http
Depending on your target framework you could also use await downloadClient.DownloadFileTaskAsync(urlAddress, location);

Categories

Resources