BackgroundTask in Lifecycle Events works but not automatically - windows-phone-8

I am trying to update the data in my secondary tile using a background task. It gets updated when I select my background task from the lifecycle events dropdown. However it doesn't work automatically. Does it mean that my SystemTrigger is not getting fired? Please help.
Here is my code:
public static void CheckIfBackgroundTaskExist()
{
if (BackgroundTaskRegistration.AllTasks.Count < 1)
{
RegisterBackgroundTask();
}
}
public static void RegisterBackgroundTask()
{
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "SecondaryTileUpdate";
builder.TaskEntryPoint = "BackgroundTaskLiveTile.SecondaryTileUpdater";
//IBackgroundTrigger trigger = new MaintenanceTrigger(15, false);
IBackgroundTrigger trigger = new SystemTrigger(SystemTriggerType.TimeZoneChange, false);
builder.SetTrigger(trigger);
IBackgroundTaskRegistration task = builder.Register();
}
public async void Run(IBackgroundTaskInstance taskInstance)
{
//HERE: request a deferral
var deferral = taskInstance.GetDeferral();
var list = await SecondaryTile.FindAllAsync();
foreach (SecondaryTile liveTile in list)
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(url, HttpCompletionOption.ResponseContentRead);
if (!response.IsSuccessStatusCode)
{
//
}
if (response != null)
{
string content = await response.Content.ReadAsStringAsync();
try
{
MyProperty= JsonConvert.DeserializeObject<MyClass>(content);
}
catch
{
//MessageBox.Show("Unable to retrieve data");
}
}
// Update Secondary Tiles
if (liveTile.TileId == "MySecondaryTileId")
{
await UpdateMyTile();
}
}
}

Related

UWP app crashes while performing an async method

I have created two methods in my BaseViewModel (MVVMLight App) to perform any async code with some logic:
public async Task PerformOperation(Func<Task> action)
{
IsBusy = true;
try
{
await action?.Invoke();
}
catch(Exception ex)
{
// logging is here
}
finally
{
IsBusy = false;
}
}
public async Task PerformOperation(params Operation[] actions)
{
IsBusy = true;
MultipleOperatrions = true;
OperationStatuses = new ObservableCollection<OperationStatus>();
try
{
foreach(var action in actions)
{
var status = new OperationStatus() { StatusText = action.StatusText };
OperationStatuses.Add(status);
try
{
await action?.AsyncAction();
status.Success = true;
}
catch
{
status.Success = false;
}
finally
{
status.IsFinished = true;
}
}
}
catch (Exception ex)
{
// logging is here
}
finally
{
await Task.Delay(1000);
IsBusy = false;
MultipleOperatrions = false;
OperationStatuses = new ObservableCollection<OperationStatus>();
}
}
My models:
public class Operation
{
public Func<Task> AsyncAction { get; private set; }
public string StatusText { get; private set; }
public Operation(Func<Task> action, string statusText)
{
AsyncAction = action;
StatusText = statusText;
}
}
My code of calling the methods in the view model:
...
private IAsyncCommand _buildCommand;
public IAsyncCommand BuildCommand => _buildCommand ?? (_buildCommand = new AsyncCommand(Build));
#endregion
#region Methods
public async Task Build()
{
// IT WORKS
// this method is used for performing only a single operation
// await PerformOperation(async () => { await Task.Delay(3000); });
// IT CRASHES THE APP
// for many tasks
await PerformOperation(new Operation(async () => { await Task.Delay(3000); }, "Preparing..."));
}
...
So, if I call PerformOperation to call just only a single method - it works fine. But it doesn't for the method of performing of several operations - the application just crashes without any exception or messages. I subscribed in App.cs to UnhandledException event to catch it but the app just crashes.

SignalR + Win RT(Windows 8.1) + using unsigned certificate not working [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
After searching for more than 4 hours, making a Win RT + SignalR work with a selfsigned certificate. Found it! So I share a solution here.
You get the error:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
The remote certificate is invalid according to the validation procedure.
public class DefaultHttpClientUnsigned : DefaultHttpClient
{
protected override HttpMessageHandler CreateHandler()
{
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Expired);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.IncompleteChain);
var handler = new WinRtHttpClientHandler(filter);
return handler;
}
}
Then for creating the connection:
var connection = new HubConnection(address);
var client = new DefaultHttpClientUnsigned();
connection.Start(client);
// https://www.nuget.org/packages/WinRtHttpClientHandler
The source code for the WinRtHttpClientHandler (if it's not available anymore)
public class WinRtHttpClientHandler : HttpMessageHandler
{
private static readonly Version NoVersion = new Version(0, 0);
private static readonly Version Version10 = new Version(1, 0);
private static readonly Version Version11 = new Version(1, 1);
private readonly rt.HttpClient _client;
private bool _disposed = false;
public WinRtHttpClientHandler(IHttpFilter httpFilter)
{
_client = new rt.HttpClient(httpFilter);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
CheckDisposed();
var rtMessage = await ConvertHttpRequestMessaageToRt(request, cancellationToken).ConfigureAwait(false);
var resp = await _client.SendRequestAsync(rtMessage).AsTask(cancellationToken).ConfigureAwait(false);
var netResp = await ConvertRtResponseMessageToNet(resp, cancellationToken).ConfigureAwait(false);
return netResp;
}
internal static async Task<rt.HttpRequestMessage> ConvertHttpRequestMessaageToRt(HttpRequestMessage message, CancellationToken token)
{
var rt = new rt.HttpRequestMessage()
{
Method = new rt.HttpMethod(message.Method.Method),
Content = await GetContentFromNet(message.Content).ConfigureAwait(false),
RequestUri = message.RequestUri,
};
CopyHeaders(message.Headers, rt.Headers);
foreach (var prop in message.Properties)
rt.Properties.Add(prop);
return rt;
}
internal static async Task<HttpRequestMessage> ConvertRtRequestMessageToNet(rt.HttpRequestMessage message, CancellationToken token)
{
var req = new HttpRequestMessage()
{
Method = new HttpMethod(message.Method.Method),
RequestUri = message.RequestUri,
Content = await GetNetContentFromRt(message.Content, token).ConfigureAwait(false),
};
foreach (var header in message.Headers)
req.Headers.TryAddWithoutValidation(header.Key, header.Value);
foreach (var prop in message.Properties)
req.Properties.Add(prop);
return req;
}
internal static void CopyHeaders(IEnumerable<KeyValuePair<string, IEnumerable<string>>> source, IDictionary<string, string> destination)
{
var headers = from kvp in source
from val in kvp.Value
select new KeyValuePair<string, string>(kvp.Key, val);
foreach (var header in headers)
destination.Add(header);
}
internal static async Task<rt.IHttpContent> GetContentFromNet(HttpContent content)
{
if (content == null)
return null;
var stream = await content.ReadAsStreamAsync().ConfigureAwait(false);
var c = new rt.HttpStreamContent(stream.AsInputStream());
CopyHeaders(content.Headers, c.Headers);
return c;
}
internal static async Task<HttpContent> GetNetContentFromRt(rt.IHttpContent content, CancellationToken token)
{
if (content == null)
return null;
var str = await content.ReadAsInputStreamAsync().AsTask(token).ConfigureAwait(false);
var c = new StreamContent(str.AsStreamForRead());
foreach (var header in content.Headers)
c.Headers.TryAddWithoutValidation(header.Key, header.Value);
return c;
}
internal static async Task<HttpResponseMessage> ConvertRtResponseMessageToNet(rt.HttpResponseMessage message, CancellationToken token)
{
var resp = new HttpResponseMessage((HttpStatusCode)(int)message.StatusCode)
{
ReasonPhrase = message.ReasonPhrase,
RequestMessage = await ConvertRtRequestMessageToNet(message.RequestMessage, token).ConfigureAwait(false),
Content = await GetNetContentFromRt(message.Content, token).ConfigureAwait(false),
Version = GetVersionFromEnum(message.Version),
};
foreach (var header in message.Headers)
resp.Headers.TryAddWithoutValidation(header.Key, header.Value);
return resp;
}
internal static Version GetVersionFromEnum(rt.HttpVersion version)
{
switch (version)
{
case rt.HttpVersion.None:
return NoVersion;
break;
case rt.HttpVersion.Http10:
return Version10;
break;
case rt.HttpVersion.Http11:
return Version11;
break;
default:
throw new ArgumentOutOfRangeException("version");
}
}
private void CheckDisposed()
{
if (_disposed)
throw new ObjectDisposedException("WinRtHttpClientHandler");
}
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
_client.Dispose();
_disposed = true;
}
base.Dispose(disposing);
}
}
Hope this helps some people out there.

How cancel Async Call in Windows Phone?

I have a list wich is loaded with elements each time the user make a research...These elements contain an Icon which is dowloaded with an async method GetByteArrayAsync of the HttpClient object. I have an issue when the user make a second research while the icon of the first list are still downloading.Because the list of elements is changing while Icon downloads are processing on each element of the first list. So my guess is that I need to cancel these requests each time the user proceed to a new research...Ive readen some stuuf on Task.run and CancellationTokenSource but I can't find really helpful example for my case so here is my code...Hope you can help me with that ...Thank you
public static async Task<byte[]> DownloadElementFile(BdeskElement bdeskElement)
{
//create and send the request
DataRequest requesteur = new DataRequest();
byte[] encryptedByte = await requesteur.GetBytesAsync(dataRequestParam);
return encryptedByte;
}
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
HttpClient httpClient = new HttpClient(handler);
try
{
byte[] BytesReceived = await httpClient.GetByteArrayAsync(datarequesparam.TargetUri);
if (BytesReceived.Length > 0)
{
return BytesReceived;
}
else
{
return null;
}
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
}
EDIT
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
HttpClient httpClient = new HttpClient(handler);
try
{
cts = new CancellationTokenSource();
HttpResponseMessage reponse = await httpClient.GetAsync(datarequesparam.TargetUri,cts.Token);
if (reponse.StatusCode == HttpStatusCode.OK)
{
byte[] BytesReceived = reponse.Content.ReadAsByteArrayAsync().Result;
if (BytesReceived.Length > 0)
{
return BytesReceived;
}
else
{
return null;
}
}
else
{
return null;
}
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
catch(OperationCanceledException)
{
throw new OperationCanceledException();
}
EDIT2
I need to cancel this funntion when the user make a new research and the list "listBoxGetDocsLibs" changed.
private async void LoadIconDocLibs()
{
foreach (var doclib in listBoxGetDocsLibs)//ERROR HERE COLLECTION HAS CHANGED
{
doclib.Icon = new BitmapImage();
try
{
byte[] Icon = await ServerFunctions.GetDocLibsIcon(doclib);
if (Icon != null)
{
{
var ms = new MemoryStream(Icon);
BitmapImage photo = new BitmapImage();
photo.DecodePixelHeight = 64;
photo.DecodePixelWidth = 92;
photo.SetSource(ms);
doclib.Icon = photo;
}
}
}
catch(OperationCanceledException)
{
}
}
}
First you need to define CancellationTokenSource:
private System.Threading.CancellationTokenSource cts;
place above code somewhere, where you can access it with your Button or other method.
Unfortunately GetByteArrayAsync lacks Cancelling - so it cannot be used with cts.Token, but maybe you can accomplish your task using GetAsync - which supports Cancelling:
ctsDownload = new System.Threading.CancellationTokenSource();
HttpResponseMessage response = await httpClient.GetAsync(requestUri, cts.Token);
Then you can get your content from response.
And when you want to Cancel your Task it can look like this:
private void cancelBtn_Click(object sender, RoutedEventArgs e)
{
if (this.cts != null)
this.cts.Cancel();
}
When you Cancel task an Exception will be thrown.
If you want to cancel your own async Task, a good example you can find at Stephen Cleary blog.
EDIT - you can also build your own method (for example with HttpWebRequest) which will support Cancelling:
For this purpose you will have to extend HttpWebRequest (under WP it lacks GetResponseAsync):
// create a static class in your namespace
public static class Extensions
{
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest webRequest)
{
TaskCompletionSource<HttpWebResponse> taskComplete = new TaskCompletionSource<HttpWebResponse>();
webRequest.BeginGetResponse(
asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
catch (Exception exc) { taskComplete.SetException(exc); }
}, webRequest);
return taskComplete.Task;
}
}
Then your method can look like this:
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam, CancellationToken ct)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(datarequesparam.TargetUri);
request.Method = "GET";
request.Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000");
request.AllowReadStreamBuffering = false;
try
{
if (request != null)
{
using (HttpWebResponse response = await request.GetResponseAsync())
using (Stream mystr = response.GetResponseStream())
using (MemoryStream output = new MemoryStream())
{
const int BUFFER_SIZE = 10 * 1024;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
{
output.Write(buf, 0, bytesread);
ct.ThrowIfCancellationRequested();
}
return output.ToArray();
}
}
else return null;
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
}
You can freely change Buffer Size which will affect how often Cancellation will be checked.
I haven't tried this but I think it should work.

Waiting and Return a result with DownloadStringAsync WP8

I do a webrequest with DownloadStringAsync() but I need to return the result only when the DownloadStringCompleted event has been called. After the downloadasync-method, I need to wait for the result and then I could return it in a string property. So I implemented a while(Result == "") but I don't know what to do there. I already tried Thread.sleep(500) but it seems the download never gets completed. And the code remains in the while forever.
string Result = "";
public String Query(DataRequestParam dataRequestParam)
{
try
{
WebClient web = new WebClient();
if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
{
System.Net.NetworkCredential account = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
web.Credentials = account;
}
web.DownloadStringCompleted += OnDownloadStringCompleted;
web.DownloadStringAsync(dataRequestParam.TargetUri);
while (Result == "")
{
//What am i supposed to do here ?
}
return Result;
}
catch(WebException we)
{
MessageBox.Show(we.Message);
return null;
}
}
private void OnDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
//Error treating
}
else
{
Result = e.Result;
}
}
UI CODE
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (e.NavigationMode != NavigationMode.Back)
{
ServerFunctions.SetUserProfil(User.UserLogin,User.UserPassword);
this.listBoxGetDocsLibs.Clear();
List<BdeskDocLib> list = new List<BdeskDocLib>();
try
{
//HERE THE START OF THE DOWNLOAD
ServerFunctions.GetDocLibs(true);
}
catch (Exception ex)
{
//error
}
foreach (BdeskDocLib docLib in list)
{
this.listBoxGetDocsLibs.Add(docLib);
}
}
}
the ServerFunction static class
public static List<BdeskDocLib> GetDocLibs(bool onlyDocLibPerso)
{
string xmlContent = GetXml(URL_GETDOCLIBS);
List<BdeskDocLib> result = BdeskDocLib.GetListFromXml(xmlContent, onlyDocLibPerso);
return result;
}
private static String GetXml(string partialUrl)
{
string url = GenerateUrl(partialUrl);
DataRequestParam dataRequestParam = new DataRequestParam();
dataRequestParam.TargetUri = new Uri(url);
dataRequestParam.UserAgent = "BSynchro";
dataRequestParam.AuthentificationLogin = userLogin;
dataRequestParam.AuthentificationPassword = userPwd;
//HERE I START THE QUERY method
// NEED QUERY RETURNS A STRING or Task<String>
DataRequest requesteur = new DataRequest();
xmlResult=requesteur.Query(dataRequestParam);
if (CheckErrorConnexion(xmlResult) == false)
{
throw new Exception("Erreur du login ou mot de passe");
}
return xmlResult;
}
There is nothing good in blocking main UI (unless you really need to). But if you want to wait for your result you can make some use of async-await and TaskCompletitionSource - you can find more about on this blog and how to use TCS in this answer:
public static Task<string> myDownloadString(DataRequestParam dataRequestParam)
{
var tcs = new TaskCompletionSource<string>();
var web = new WebClient();
if (!string.IsNullOrEmpty(dataRequestParam.AuthentificationLogin))
{
System.Net.NetworkCredential account = new NetworkCredential(dataRequestParam.AuthentificationLogin, dataRequestParam.AuthentificationPassword);
web.Credentials = account;
}
web.DownloadStringCompleted += (s, e) =>
{
if (e.Error != null) tcs.TrySetException(e.Error);
else if (e.Cancelled) tcs.TrySetCanceled();
else tcs.TrySetResult(e.Result);
};
web.DownloadStringAsync(dataRequestParam.TargetUri);
return tcs.Task;
}
public async Task<string> Query(DataRequestParam dataRequestParam)
{
string Result = "";
try
{
Result = await myDownloadString(dataRequestParam);
}
catch (WebException we)
{
MessageBox.Show(we.Message);
return null;
}
return Result;
}
(I've not tried this code, there maight be some mistakes, but it should work)
Basing on this code you can also extend your WebClient with awaitable version of download string.

Http Post with Blackberry 6.0 issue

I am trying to post some data to our webservice(written in c#) and get the response. The response is in JSON format.
I am using the Blackberry Code Sample which is BlockingSenderDestination Sample. When I request a page it returns with no problem. But when I send my data to our webservice it does not return anything.
The code part that I added is :
ByteMessage myMsg = bsd.createByteMessage();
//myMsg.setStringPayload("I love my BlackBerry device!");
myMsg.setMessageProperty("querytpe","myspecialkey");//here is my post data
myMsg.setMessageProperty("uname","myusername");
myMsg.setMessageProperty("pass","password");
((HttpMessage) myMsg).setMethod(HttpMessage.POST);
// Send message and wait for response myMsg
response = bsd.sendReceive(myMsg);
What am i doing wrong? And what is the alternatives or more efficients way to do Post with Blackberry.
Regards.
Here is my whole code:
class BlockingSenderSample extends MainScreen implements FieldChangeListener {
ButtonField _btnBlock = new ButtonField(Field.FIELD_HCENTER);
private static UiApplication _app = UiApplication.getUiApplication();
private String _result;
public BlockingSenderSample()
{
_btnBlock.setChangeListener(this);
_btnBlock.setLabel("Fetch page");
add(_btnBlock);
}
public void fieldChanged(Field button, int unused)
{
if(button == _btnBlock)
{
Thread t = new Thread(new Runnable()
{
public void run()
{
Message response = null;
String uriStr = "http://192.168.1.250/mobileServiceOrjinal.aspx"; //our webservice address
//String uriStr = "http://www.blackberry.com";
BlockingSenderDestination bsd = null;
try
{
bsd = (BlockingSenderDestination)
DestinationFactory.getSenderDestination
("name", URI.create(uriStr));//name for context is name. is it true?
if(bsd == null)
{
bsd =
DestinationFactory.createBlockingSenderDestination
(new Context("ender"),
URI.create(uriStr)
);
}
//Dialog.inform( "1" );
ByteMessage myMsg = bsd.createByteMessage();
//myMsg.setStringPayload("I love my BlackBerry device!");
myMsg.setMessageProperty("querytpe","myspecialkey");//here is my post data
myMsg.setMessageProperty("uname","myusername");
myMsg.setMessageProperty("pass","password");
((HttpMessage) myMsg).setMethod(HttpMessage.POST);
// Send message and wait for response myMsg
response = bsd.sendReceive(myMsg);
if(response != null)
{
BSDResponse(response);
}
}
catch(Exception e)
{
//Dialog.inform( "ex" );
// process the error
}
finally
{
if(bsd != null)
{
bsd.release();
}
}
}
});
t.start();
}
}
private void BSDResponse(Message msg)
{
if (msg instanceof ByteMessage)
{
ByteMessage reply = (ByteMessage) msg;
_result = (String) reply.getStringPayload();
} else if(msg instanceof StreamMessage)
{
StreamMessage reply = (StreamMessage) msg;
InputStream is = reply.getStreamPayload();
byte[] data = null;
try {
data = net.rim.device.api.io.IOUtilities.streamToBytes(is);
} catch (IOException e) {
// process the error
}
if(data != null)
{
_result = new String(data);
}
}
_app.invokeLater(new Runnable() {
public void run() {
_app.pushScreen(new HTTPOutputScreen(_result));
}
});
}
}
..
class HTTPOutputScreen extends MainScreen
{
RichTextField _rtfOutput = new RichTextField();
public HTTPOutputScreen(String message)
{
_rtfOutput.setText("Retrieving data. Please wait...");
add(_rtfOutput);
showContents(message);
}
// After the data has been retrieved, display it
public void showContents(final String result)
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
_rtfOutput.setText(result);
}
});
}
}
HttpMessage does not extend ByteMessage so when you do:
((HttpMessage) myMsg).setMethod(HttpMessage.POST);
it throws a ClassCastException. Here's a rough outline of what I would do instead. Note that this is just example code, I'm ignoring exceptions and such.
//Note: the URL will need to be appended with appropriate connection settings
HttpConnection httpConn = (HttpConnection) Connector.open(url);
httpConn.setRequestMethod(HttpConnection.POST);
OutputStream out = httpConn.openOutputStream();
out.write(<YOUR DATA HERE>);
out.flush();
out.close();
InputStream in = httpConn.openInputStream();
//Read in the input stream if you want to get the response from the server
if(httpConn.getResponseCode() != HttpConnection.OK)
{
//Do error handling here.
}