I'm trying to create a background agent that periodically updates a user's Live Tiles on Windows Phone.
Currently, my code for the agent is:
string where = "";
private GeoCoordinate MyCoordinate = null;
HttpWebResponse webResponse;
...
protected override void OnInvoke(ScheduledTask task)
{
System.Diagnostics.Debug.WriteLine("Invoked");
findMe();
NotifyComplete();
}
private void ResponseCallback(IAsyncResult asyncResult)
{
HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;
webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult);
MemoryStream tempStream = new MemoryStream();
webResponse.GetResponseStream().CopyTo(tempStream);
}
private async void findMe()
{
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = PositionAccuracy.High;
try
{
Geoposition currentPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude);
// var uri = new Uri("http://www.streetdirectory.com//api/?mode=nearby&act=location&output=json&callback=foo&start=0&limit=1&country=sg&profile=template_1&x=" + MyCoordinate.Longitude + "&y=" + MyCoordinate.Latitude + "&dist=1");
// var client = new HttpClient();
var webRequest = (HttpWebRequest)HttpWebRequest.CreateHttp("http://www.streetdirectory.com//api/?mode=nearby&act=location&output=json&callback=foo&start=0&limit=1&country=sg&profile=template_1&x=" + MyCoordinate.Longitude + "&y=" + MyCoordinate.Latitude + "&dist=1");
webRequest.BeginGetResponse(new AsyncCallback(ResponseCallback), webRequest);
System.Diagnostics.Debug.WriteLine("findMe after response");
System.Diagnostics.Debug.WriteLine(MyCoordinate.Latitude);
System.Diagnostics.Debug.WriteLine(MyCoordinate.Longitude);
// var response = await client.GetStringAsync(uri);
System.Diagnostics.Debug.WriteLine(webResponse.ToString());
JToken token = JArray.Parse(webResponse.ToString())[0];
// JToken token = JArray.Parse(response)[0];
var name = token.Next.First.First;
var address = token.Next.Last.First;
where = name + ", " + address;
}
catch (Exception)
{
System.Diagnostics.Debug.WriteLine("findMe died");
where = "";
}
System.Diagnostics.Debug.WriteLine("findMe complete");
UpdateAppTile();
}
private void UpdateAppTile()
{
System.Diagnostics.Debug.WriteLine("UpdateAppTile");
ShellTile appTile = ShellTile.ActiveTiles.First();
if (appTile != null)
{
StandardTileData tileData = new StandardTileData
{
BackContent = where
};
appTile.Update(tileData);
}
System.Diagnostics.Debug.WriteLine("Update Completed: " + where);
}
When I attempt to run this, the code reaches webRequest.BeginGetResponse and subsequently stops. The next line, and ResponseCallback are not reached.
An older version of my code is commented out, which I thought was the problem but it experienced the same problem as well.
The problem is that you are calling NotifyComplete() before the callback returns.
By calling NotifyComplete you're telling the OS that you've finished all your work and the agent can be terminated. Obviously this isn't the case when you're waiting for your webrequest callback.
The simple solution is to move this call into the callback method. obviously you'll need to handle error exceptions and the request timeout taking longer than the agent will wait for as well though.
Changing to using awaitable code may make this easier for you.
Related
This question already has an answer here:
What would be a good way to Cancel long running IO/Network operation using Tasks?
(1 answer)
Closed 2 years ago.
I'm playing with TcpClient and when i use some Async operations they ignore the CancellationToken. After some reading, i know that it is intentionally and also knows that exists some ways to cancel awaits on Asyncs operations.
I just read next StackOverflow questions and articles that clarifies some points:
How to cancel a Task in await?
https://devblogs.microsoft.com/pfxteam/how-do-i-cancel-non-cancelable-async-operations/
Following previous articles, I could cancel NetworkStream.ReadAsync but that mechanisms doesn't work when i use them on NetworkStream.WriteAsync.
I have this code as minimal example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
CancellationTokenSource ctSource;
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
string http_resp = "";
var request_uri = new Uri("http://icanhazip.com");
//BIG FILE as postdata to test the WriteAsync (use one that you have on your disk)
string contents = File.ReadAllText(#"C:\Portables\4test.txt");
string post_data = contents;
ctSource = new CancellationTokenSource();
CancellationToken ct = ctSource.Token;
Task<string> task = HttpRequestAsync(post_data, request_uri, ct);
try
{
http_resp = await task;
}
catch
{
http_resp = "General error";
}
textBox1.Text = http_resp;
button1.Enabled = true;
}
private static async Task<string> HttpRequestAsync(string post_data, Uri request_uri, CancellationToken ct)
{
string result = string.Empty;
string http_method = "POST";
string post_content_type = "application/x-www-form-urlencoded";
var hostname = request_uri.Host;
var port = request_uri.Port;
var scheme = request_uri.Scheme;
using (TcpClient tcpClient = new TcpClient())
{
tcpClient.SendTimeout = 15;
tcpClient.ReceiveTimeout = 15;
try
{
await tcpClient.ConnectAsync(hostname, port);
}
catch (Exception d1)
{
if (ct.IsCancellationRequested)
{
result = "Cancelation requested on ConnectAsync";
}
else
{
result = d1.Message + "\r\n" + d1.GetType().FullName + d1.StackTrace; ;
}
return result;
}
//Build HTTP headers
string reqString = "";
string header_host = "Host: " + hostname + "\r\n";
string header_close = "Connection: Close\r\n";
string basic_headers = "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0\r\n";
basic_headers += "Referer: https://www.google.com\r\n";
string header_post = "";
if (http_method == "POST")
{
string header_content_type = "";
header_content_type = "Content-type: " + post_content_type + "\r\n";
int content_length = 0;
content_length = post_data.Length;
string header_content_length = "Content-length: " + content_length + "\r\n";
header_post = header_content_type + header_content_length;
}
reqString = http_method + " " + request_uri.PathAndQuery + " " + "HTTP/1.1" + "\r\n" + header_host + basic_headers + header_close + header_post + "\r\n";
if (http_method == "POST")
{
reqString += post_data;
}
var header_bytes = Encoding.ASCII.GetBytes(reqString.ToString());
//Starting the I/O Network operations
using (NetworkStream tcp_stream = tcpClient.GetStream())
{
try
{
//HERE is where i have problems cancelling this await while WriteAsync is working.
await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct).WithCancellation(ct);
//await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct);
}
catch (Exception d2)
{
if (ct.IsCancellationRequested)
{
result = "Cancelation requested on WriteAsync";
}
else
{
result = d2.Message + "\r\n" + d2.GetType().FullName + d2.StackTrace;
}
return result;
}
using (var memory = new MemoryStream())
{
try
{
await tcp_stream.CopyToAsync(memory, 81920, ct);
}
catch (Exception d3)
{
if (ct.IsCancellationRequested)
{
result = "Request cancelled by user (on read)";
}
else
{
result = d3.Message + "\r\n" + d3.GetType().FullName + d3.StackTrace;
}
return result;
}
memory.Position = 0;
byte[] data = memory.ToArray();
result = Encoding.UTF8.GetString(data);
}
}
}
return result;
}
private void button2_Click(object sender, EventArgs e)
{
ctSource.Cancel();
}
}
It works good when i use it on ReadAsync:
await tcp_stream.ReadAsync(response, 0, response.Length, ct).WithCancellation(ct);
It doesn't work when i use it on WriteAsync:
await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct).WithCancellation(ct);
No error is returned, simply the await isn't cancelled. To be more clear i added a minimal example as a Visual Studio 2015 project that you can download here: https://github.com/Zeokat/minimal_ex/archive/master.zip
It also includes a file 4test.rar that you can decompress into a file of 39MB 4test.txt. I use this text file as post_data contents for test because is big enougth to call the Cancel action while the WriteAsync is running.
Can someone give me a hand on this? I spend some days trying to fix this but couldn't achieve a proper solution.
Thanks in advance.
Dont use .WithCancellation(ct) use only await tcp_stream.WriteAsync(header_bytes, 0, header_bytes.Length, ct).
cts = new CancellationTokenSource();
pass ct = cts.Token
in cancel_event() :
if(cts != null) cts.Cancel();
There is a simple video editor, saving video to a file is implemented in the background, implementation of the documentation https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/process-media-files-in-the-Background . The program works, but there is a nuance - saving the video in the background occurs only when the main stream is inactive, that is, when the application is minimized to the taskbar or closed. If the application is deployed then the background video save task is suspended. Tell me how to implement the background task when the main application is active? Thank you!
Class background tasks:
using Windows.ApplicationModel.Background;
using Windows.Storage;
using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;
using System.Threading;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Media.Editing;
using Windows.Foundation;
using Windows.UI.Core;
using Lumia.Imaging;
using Lumia.Imaging.Adjustments;
using Lumia.Imaging.Artistic;
using System.Collections.Generic;
using Windows.Foundation.Collections;
using VideoEffectComponent;
namespace MediaProcessingBackgroundTask
{
public sealed class MediaProcessingTask : IBackgroundTask
{
IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;
MediaComposition composition;
MediaClip clip;
EffectList effList = new EffectList();
PropertySet configurationPropertySet = new PropertySet();
PropertySet DustPropertySet = new PropertySet();
PropertySet ScretcchPropertySet = new PropertySet();
Windows.Media.Effects.VideoEffectDefinition videoEffect;
BrightnessEffect brightnessEff = new BrightnessEffect();
ContrastEffect contrastEff = new ContrastEffect();
HueSaturationEffect saturationEff = new HueSaturationEffect();
public async void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("In background task Run method");
backgroundTaskInstance = taskInstance;
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
taskInstance.Progress = 0;
deferral = taskInstance.GetDeferral();
Debug.WriteLine("Background " + taskInstance.Task.Name + " is called # " + (DateTime.Now).ToString());
try
{
await TranscodeFileAsync();
ApplicationData.Current.LocalSettings.Values["TranscodingStatus"] = "Completed Successfully";
SendToastNotification("File transcoding complete.");
}
catch (Exception e)
{
Debug.WriteLine("Exception type: {0}", e.ToString());
ApplicationData.Current.LocalSettings.Values["TranscodingStatus"] = "Error ocurred: " + e.ToString();
}
deferral.Complete();
}
private async Task TranscodeFileAsync()
{
transcoder = new MediaTranscoder();
try
{
var settings = ApplicationData.Current.LocalSettings;
settings.Values["TranscodingStatus"] = "Started";
var inputFileName = ApplicationData.Current.LocalSettings.Values["InputFileName"] as string;
var outputFileName = ApplicationData.Current.LocalSettings.Values["OutputFileName"] as string;
var redCurve = ApplicationData.Current.LocalSettings.Values["CurvRed"] as Point[];
var greenCurve = ApplicationData.Current.LocalSettings.Values["CurvGreen"] as Point[];
var blueCurve = ApplicationData.Current.LocalSettings.Values["CurvBlue"] as Point[];
var sat = ApplicationData.Current.LocalSettings.Values["SatVal"];
var brid = ApplicationData.Current.LocalSettings.Values["BridVal"];
var con = ApplicationData.Current.LocalSettings.Values["ContrVal"];
var dust = ApplicationData.Current.LocalSettings.Values["dustCVal"];
var scetch = ApplicationData.Current.LocalSettings.Values["scetchCVal"];
saturationEff.Saturation = (double)sat;
brightnessEff.Level = (double)brid;
contrastEff.Level = (double)con;
CurvesEffect curves = new CurvesEffect();
Curve RedC = new Curve();
Curve GreenC = new Curve();
Curve BlueC = new Curve();
RedC.Points = redCurve;
GreenC.Points = greenCurve;
BlueC.Points = blueCurve;
curves.Blue = BlueC;
curves.Green = GreenC;
curves.Red = RedC;
if (inputFileName == null || outputFileName == null)
{
return;
}
var inputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(inputFileName);
var outputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(outputFileName);
composition = await MediaComposition.LoadAsync(inputFile);
clip = composition.Clips[0];
effList.Add(saturationEff);
effList.Add(brightnessEff);
effList.Add(contrastEff);
effList.Add(curves);
configurationPropertySet.Add(new KeyValuePair<string, object>("Effect", effList));
DustPropertySet = new PropertySet();
DustPropertySet["DustCount"] = dust;
ScretcchPropertySet = new PropertySet();
ScretcchPropertySet["ScetchAmount"] = scetch;
videoEffect = new Windows.Media.Effects.VideoEffectDefinition("Lumia.Imaging.VideoEffect", configurationPropertySet);
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(Vignet).FullName, VignetPropertySet));
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(ExampleVideoEffect).FullName, ScretcchPropertySet));
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(Dust).FullName, DustPropertySet));
clip.VideoEffectDefinitions.Add(videoEffect);
MediaEncodingProfile mp = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);
Debug.WriteLine("PrepareFileTranscodeAsync");
settings.Values["TranscodingStatus"] = "Preparing to transcode ";
var startTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
Debug.WriteLine("Starting transcoding #" + startTime);
var progressT = new Progress<double>(TranscodeProgress);
settings.Values["TranscodingStatus"] = "Transcoding ";
settings.Values["ProcessingFileName"] = inputFileName;
var saveOperation = composition.RenderToFileAsync(outputFile, MediaTrimmingPreference.Precise, mp);// AsTask(cancelTokenSource.Token, progressT);
saveOperation.Completed = (info, status) =>
{
SendToastNotification("Video saved.");
clip.VideoEffectDefinitions.Clear();
composition = null;
deferral.Complete();
if (status != AsyncStatus.Completed)
{
// ShowErrorMessage("Error saving composition");
}
};
await saveOperation.AsTask(cancelTokenSource.Token, progressT);
Debug.WriteLine("Source content could not be transcoded.");
var endTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
Debug.WriteLine("End time = " + endTime);
}
catch (Exception e)
{
Debug.WriteLine("Exception type: {0}", e.ToString());
throw;
}
}
void TranscodeProgress(double percent)
{
Debug.WriteLine("Transcoding progress: " + percent.ToString().Split('.')[0] + "%");
backgroundTaskInstance.Progress = (uint)percent;
}
private void SendToastNotification(string toastMessage)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText01;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode(toastMessage));
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested..." + reason.ToString());
}
}
}
Register and launch the background task
MediaProcessingTrigger mediaProcessingTrigger;
string backgroundTaskBuilderName = "TranscodingBackgroundTask";
BackgroundTaskRegistration taskRegistration;
private void RegisterBackgroundTask()
{
// New a MediaProcessingTrigger
mediaProcessingTrigger = new MediaProcessingTrigger();
var builder = new BackgroundTaskBuilder();
builder.Name = backgroundTaskBuilderName;
builder.TaskEntryPoint = "MediaProcessingBackgroundTask.MediaProcessingTask";
builder.SetTrigger(mediaProcessingTrigger);
// unregister old ones
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if (cur.Value.Name == backgroundTaskBuilderName)
{
cur.Value.Unregister(true);
}
}
taskRegistration = builder.Register();
taskRegistration.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
taskRegistration.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
return;
}
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
{
string progress = "Progress: " + args.Progress + "%";
Debug.WriteLine(progress);
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
TextSave.Text = progress;
ProgressSave.Value = args.Progress;
});
}
private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine(" background task complete");
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
TasckCompleted();
});
}
private async void LaunchBackgroundTask()
{
var success = true;
if (mediaProcessingTrigger != null)
{
MediaProcessingTriggerResult activationResult;
activationResult = await mediaProcessingTrigger.RequestAsync();
switch (activationResult)
{
case MediaProcessingTriggerResult.Allowed:
// Task starting successfully
break;
case MediaProcessingTriggerResult.CurrentlyRunning:
// Already Triggered
case MediaProcessingTriggerResult.DisabledByPolicy:
// Disabled by system policy
case MediaProcessingTriggerResult.UnknownError:
// All other failures
success = false;
break;
}
if (!success)
{
// Unregister the media processing trigger background task
taskRegistration.Unregister(true);
}
}
}
saving the video in the background occurs only when the main stream is inactive , that is, when the application is minimized to the taskbar or closed.
In your above code snippet, the background task is triggered by LaunchBackgroundTask() method. When the background task occurred depends on where you invoke this method that you didn't show the relative code snippet. According to your description that background task only triggered when main stream is inactive, I think you invoke this method inside the event handle which is fired once app inactive, for example, you invoked the method inside EnteredBackground event. In that case, you may need to add LaunchBackgroundTask() method invoking foreground to meet your requirements, for example, just invoke it in a button click event.
private void btnlaunch_Click(object sender, RoutedEventArgs e)
{
LaunchBackgroundTask();
}
The MediaProcessingTask is out-of-process background task, once the background task is triggered, no matter the app is active or inactive it will continue running. But if you mean re-deployed, by testing on my side, this will uninstall the app firstly which will un-register the background task and force it stopped.
I am programming an application for downloading articles from an SQL Database on the internet. I have programmed the Website for managing the articles. Now I'm downloading the article List in gzip Format and then I decompress them to a xml-File. When I'm done I want to insert the articles to the mobile phone. This works great. Now I want to add an progress Bar to see the state of the insertion. I tried with Threading but this doesn't work. I'm posting some pieces of code from my application and also the progressUpdate methods.
private void btn_send_Click(object sender, EventArgs e)
{
label1.Text = "Download started";
string ArticlesURL = "URLTOSITE";
InvokeAsync(ArticlesURL);
}
private void InvokeAsync(string URL)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.AllowWriteStreamBuffering = true;
allDone.Reset();
request.BeginGetRequestStream(new AsyncCallback(ReadArticlesCallback), request);
allDone.WaitOne();
request.BeginGetResponse(new AsyncCallback(ResponseArticlesCallback), request);
}
private static void ReadArticlesCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
//End the operation.
Stream postSream = request.EndGetRequestStream(asynchronousResult);
string postData = "articles=test";
//Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//Write to the request stream.
postSream.Write(byteArray, 0, postData.Length);
postSream.Close();
allDone.Set();
}
private static void ResponseArticlesCallback(IAsyncResult asynchronousResult)
{
Form1 f = new Form1();
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse resp = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = resp.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
nbrArticles = Convert.ToInt16(responseString);
// Close the stream object.
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse.
resp.Close();
f.truncate_articles();
f.get_articles();
}
private void get_articles()
{
string url = "URLTOSITE";
int startPoint = 0;
DownloadZipFile((object)startPoint, url);
DecompressFile();
getXmlAndInsertInDB();
}
private void getXmlAndInsertInDB()
{
int total = nbrArticles;
int count = total / 100; //How much articles are 1 percent
int i = 0;
String barcode = "";
String name = "";
bool state = false;
XmlTextReader reader = new XmlTextReader("Program Files\\SmartDeviceProject1\\articles.xml");
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element: //The node is an element
while (reader.MoveToNextAttribute()) //Get the attributes like barcode, lastname, firstname, pincode
switch (reader.Name)
{
case "barcode":
barcode = reader.Value.ToString();
state = false;
break;
case "name":
name = reader.Value.ToString();
state = true;
break;
}
break;
}
if (state == true)
{
cmd.CommandText = "INSERT INTO articles(barcode, name) " +
"VALUES('" + barcode + "','" + name + "');";
cmd.ExecuteNonQuery();
state = false;
i++;
if (i == count)
{
Thread t = new Thread(new ThreadStart(this.incrementProgressBar));
t.Start();
//incrementProgressBar();
i = 0;
}
}
}
reader.Close();
}
private void updateProgressBarMethod(int progress)
{
if (progressBar1.InvokeRequired)
{
//It was called from a non UI thread so we create a delegate
//and have the UI Thread call this method again
UpdateProgressBar = new UpdateProgressBarDelegate(updateProgressBarMethod);
this.Invoke(UpdateProgressBar, progress);
}
else
{
//Called from the UI Thread OK to update
//update your progress bar here
progressBar1.Value += progress;
}
}
private void incrementProgressBar()
{
//Call the method to update progress Bar on UI thread
//we do not need a delegate here that will be taken care of
//in the method
updateProgressBarMethod(1);
Application.DoEvents();
}
I think the problem is that I am using Callbacks. I have read that the Callbacks are also starting Threads. So I think the problem is there but I can't solve it.
I've found another very good site for threading with mobile applications: Updating the User Interface from a Worker Thread
Now with the new code, the debugger stops always at the same piece of code without any notification or exception :( Here is my new code:
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
this.Invoke(new EventHandler(WorkerUpdate)); //The Debugger stops here!
i = 0;
step++;
Thread.Sleep(700);
}
public void WorkerUpdate(object sender, EventArgs e)
{
this.lbl_percent.Text = this.info_percent;
this.lbl_percent.Update();
this.progressBar1.Value = step;
this.progressBar1.Update();
}
The Debugger stops at: this.Invoke(new EventHandler(WorkerUpdate));
I would suggest using the Background worker class. I had a similar problem and implemented the Background worker and it fixed my problem. Hopefully it will fix yours also
http://www.dotnetperls.com/backgroundworker
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
I found another thread discussing this and thought it would help:
Is there a BackgroundWorker replacement for .NET Compact Framework 3.5?
Your code will always hang at this point:
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
this.Invoke(new EventHandler(WorkerUpdate)); //The Debugger stops here!
i = 0;
step++;
Thread.Sleep(700);
}
Make these changes:
public delegate void MethodInvoker(); // this is not defined in CF
if (i == count)
{
this.info_percent = "Synchro " + step.ToString() + "%";
object sender = null; // make this whatever you want/need
EventArgs e = new EventArgs();
if (this.InvokeRequired) {
MethodInvoker mi = delegate { WorkerUpdate(sender, e); } };
this.BeginInvoke(mi);
} else {
WorkerUpdate(sender, e);
}
i = 0;
step++;
// Thread.Sleep(700); Why is this here?
}
This should prevent those obnoxious freezes.
First post here, sorry for starting with asking questions.
In my Windows Phone 7 app I have a working livetile that is beeing triggered by a background agent. But how can I modify the code so the httpwebrequest timeouts after 10 seconds?
Thanks in advance.
protected override void OnInvoke(ScheduledTask task)
{
//TODO: Add code to perform your task in background
var request = (HttpWebRequest)WebRequest.Create(
new Uri("site.com"));
request.BeginGetResponse(r =>
{
var httpRequest = (HttpWebRequest)r.AsyncState;
var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
using (var reader = new StreamReader(httpResponse.GetResponseStream()))
{
var response = reader.ReadToEnd();
Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
{
string strResult = response;
/// If application uses both PeriodicTask and ResourceIntensiveTask
if (task is PeriodicTask)
{
// Execute periodic task actions here.
ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains("TileID=2"));
if (TileToFind != null)
{
StandardTileData NewTileData = new StandardTileData
{
BackgroundImage = new Uri("Pin-to-start.png", UriKind.Relative),
Title = strResult,
Count = null
};
TileToFind.Update(NewTileData);
}
}
else
{
// Execute resource-intensive task actions here.
}
NotifyComplete();
}));
}
}, request);
}
Here is copy/paste from code that i use in one of my apps. It will abort the connection after 60 seconds.
private static void DoWebRequest(string uri)
{
string id = "my_request";
Timer t = null;
int timeout = 60; // in seconds
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Accept = "*/*";
request.AllowAutoRedirect = true;
// disable caching.
request.Headers["Cache-Control"] = "no-cache";
request.Headers["Pragma"] = "no-cache";
t = new Timer(
state =>
{
if (string.Compare(state.ToString(), id, StringComparison.InvariantCultureIgnoreCase) == 0)
{
logger.Write("Timeout reached for connection [{0}], aborting download.", id);
request.Abort();
t.Dispose();
}
},
id,
timeout * 1000,
0);
request.BeginGetResponse(
r =>
{
try
{
if (t != null)
{
t.Dispose();
}
// your code for processing the results
}
catch
{
// error handling.
}
},
request);
}
catch
{
}
}
But how can I modify the code so the httpwebrequest timeouts after 10 seconds?
You mean so it'll call NotifyComplete() regardless of timeouts?-) The catch is that after 15 seconds the task terminates, and gets disabled until it's re-launched by the user (inside your app).
I would recommend using TPL for Silverlight and utilizing the ability to use Tasks for setting a Timeout.
Something like:
protected override void OnInvoke(ScheduledTask task)
{
var fetchTask = FetchData(TimeSpan.FromSeconds(10));
fetchTask.ContinueWith(x =>
{
Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
{
string strResult = x.Result; // mind you, x.Result will be "null" when a timeout occours.
...
NotifyComplete();
}));
});
}
private Task<string> FetchData(TimeSpan timeout)
{
var tcs = new TaskCompletionSource<string>();
var request = (HttpWebRequest)WebRequest.Create(new Uri("site.com"));
Timer timer = null;
timer = new Timer(sender =>
{
tcs.TrySetResult(null);
timer.Dispose();
}, null, (int)timeout.TotalMilliseconds, Timeout.Infinite);
request.BeginGetResponse(r =>
{
var httpRequest = (HttpWebRequest)r.AsyncState;
var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);
using (var reader = new StreamReader(httpResponse.GetResponseStream()))
{
var response = reader.ReadToEnd();
tcs.TrySetResult(response);
}
});
return tcs.Task;
}
I am using webrequest to fetch some image data. The url may be invaild sometime. In case of invalid URL, begingetresponse is taking time equals to timeout period. Also the control become unresponsive during that period. In other word the async callback is not working asynchronously. Is this expected behaviour?
try
{
// Async requests
WebRequest request = WebRequest.Create(uri);
request.Timeout = RequestTimeOut;
RequestObject requestObject = new RequestObject();
requestObject.Request = request;
request.BeginGetResponse(this.ProcessImage, requestObject);
}
catch (Exception)
{
ShowErrorMessage(uri);
}
private void ProcessImage(IAsyncResult asyncResult)
{
try
{
RequestObject requestObject = (RequestObject)asyncResult.AsyncState;
WebRequest request = requestObject.Request;
WebResponse response = request.EndGetResponse(asyncResult);
Bitmap tile = new Bitmap(response.GetResponseStream());
// do something
}
catch (Exception)
{
ShowErrorMessage();
}
}
looks like this is an issue with .NET. BeginGetResponse blocks until DNS is resolved. In case of wrong URL (like http://somecrap) it tries until it gets timeout. See the following links -
link1 and link2
I just ran into this same situation. While it's not a perfect workaround I decided to use the Ping.SendAsync() to ping the site first. Good part is the async part return immediately. Bad part is the extra step AND not all sites respond to Ping requests.
public void Start(WatchArgs args)
{
var p = new System.Net.NetworkInformation.Ping();
args.State = p;
var po = new System.Net.NetworkInformation.PingOptions(10, true);
p.PingCompleted += new PingCompletedEventHandler(PingResponseReceived);
p.SendAsync(args.Machine.Name, 5 * 1000, Encoding.ASCII.GetBytes("watchdog"), po, args);
}
private void PingResponseReceived(object sender, .PingCompletedEventArgs e)
{
WatchArgs args = e.UserState as WatchArgs;
var p = args.State as System.Net.NetworkInformation.Ping;
p.PingCompleted -= new System.Net.NetworkInformation.PingCompletedEventHandler(HttpSmokeWatcher.PingResponseReceived);
args.State = null;
if (System.Net.NetworkInformation.IPStatus.Success == e.Reply.Status)
{
// ... BeginGetResponse now
}
else
{
/// ... machine not available
}
}
Just code and running for a day but initial result look promising.