I am using following code to call a web service in update UI using Task
//------- REFRESH BOOK LIST ------
public Task<string> GetBookList()
{
return Task.Factory.StartNew(() => {
// GET BOOK LIST
WebServiceController webServices = new WebServiceController ();
string bookList = webServices.GetBookList ();
if (bookList.Contains("BooksList")) {
// PARSE
ParseListData parseData = new ParseListData ();
parseData.ParseList (bookList);
}
return bookList;
});
}
I call this code using
GetBookList ().ContinueWith (task => {
if (task.IsFaulted) {
// STOP ACTIVITY INDICATOR
RemoveActivityIndicator (true);
throw new AggregateException (task.Exception.InnerException.Message);
}
// RUNS WHEN TASK IS FINISHED
InvokeOnMainThread (() => {
// STOP ACTIVITY INDICATOR
RemoveActivityIndicator (true);
string bookList = task.Result;
if (bookList.Contains("Error:") || !bookList.Contains("BooksList"))
{
// SHOW ERROR MESSAGE
}
});
});
If there is an error in the return string (bookList) then i want to check for bookList.Contains("Error:") as above and show error message. The problem in that is bookList string is assigned in the Task GetBookList() function. How do i get that value in GetBookList ().ContinueWith to show error.
How to write a Task in above situation to return a string.
Use Task<string>, then the Task's Result property can be used to store your String value.
Related
When I am throwing exception my function to bubble it out and catch it in the task exception, rather then continuation it breaks the code- below is my code
public override void Run()
{
SendRenewalsEmail("ddd#xxx.com", " Email Body from test More", "Test Email from Service another Test");
}
private async void SendRenewalsEmail(string userEmail, string emailBody, string emailSubject)
{
string replyFromEmailAddress = "renewals#xxx.net";
string cc = "";
string bcc = "ccc#xxxx.com";
SMTPMailHelperAsync sMTPMailHelperAsync = new SMTPMailHelperAsync();
var x= await sMTPMailHelperAsync.SendEmailAsync(userEmail, cc, bcc, emailSubject, SMTPMailHelperAsync.ProcessTemplate(emailBody, "Renewals.html", emailSubject), replyFromEmailAddress);
if (x.MailSent)
{
throw new Exception("after mail Test more service");
}
}
and the Task where it is being captured
var task= Task<PluginInstance>.Run<PluginInstance>(() => {
thisPlugin.LastRunStart = DateTime.Now.ToLocalTime();
try
{
thisPlugin.Plugin.Run();
thisPlugin.LastRunStatus = Enums.RunStatus.Success;
thisPlugin.LastRunMessage = "";
}
catch (Exception ex)
{
thisPlugin.LastRunStatus = Enums.RunStatus.Failed;
thisPlugin.LastRunMessage = ex.Message;
}
thisPlugin.LastRunEnd = DateTime.Now.ToLocalTime();
return thisPlugin;
});
ListOfTask.Add(task);
Now I am trying to capture the exception in the Task exception but is not. getting below exception
You must not use async void. This is a special case, reserved only for event handlers. Your async method must return a Task:
private async Task SendRenewalsEmail(…)
Then, your Plugin.Run method is broken. It should be async as well.
Once you start with async - await, you do it to the top.
I thought that I got threads in .NET, but when I have added LINQ expression it made me a little confused.
Like I wrote in the topic of this discussion I dont why the thread doesnt return control to the main action of my controller.
I have written what makes me silly in comments, so let me skip to the true example:
public class ValuesController : ApiController
{
public async Task<List<SomeProduct>> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s).Result;
//1-The above code doesnt enter into CONVERT function (I have a breakpoint there)
return oss.ToList();//2- this list enter into COnvertt
}
private async Task<SomeProduct> Convert(Mother ms, Child ss)
{
var ossNEW = new SomeProduct();
await update(ossNEW, ms);
return ossNEW;
}
private async Task update(SomeProduct oss, Mother ms)
{//3 - Naturally it comes here
await Task.Run(()=>
{
//This task is executed (It is example code, pls do not care, that threads do not have any sense
oss.copyOfTheLastOne = ms.internalField.First().theLastOne;
oss.valeFromAnUpdateFunction = "works";
}); //Flow comes here and THIS line does not return control to the main action, why? :)
}
}
public class SomeProduct
{
public string copyOfTheLastOne;
public string valeFromAnUpdateFunction;
}
public class Mother
{
public List<Child> internalField;
}
public class Child
{
public string theLastOne;
}
I have solved this example by adding an "executor", which takes list of the tasks and manage it.
public class ValuesController : ApiController
{
public async Task<List<SomeProduct>> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s);
List<Task<SomeProduct>> downloadTasks = oss.ToList();
List<SomeProduct> ossNew = new List<SomeProduct>();
while (downloadTasks.Count > 0)
{
var firstFinishedTask = await Task.WhenAny(downloadTasks);
downloadTasks.Remove(firstFinishedTask);
ossNew.Add(await firstFinishedTask);
}
return ossNew;
}
private async Task<SomeProduct> Convert(Mother ms, Child ss)
{
var ossNEW = new SomeProduct();
await update(ossNEW, ms);
return ossNEW;
}
private async Task update(SomeProduct oss, Mother ms)
{
await Task.Run(()=>
{
oss.copyOfTheLastOne = ms.internalField.First().theLastOne;
oss.valeFromAnUpdateFunction = "works";
});
}
To fully understand the problem, I would like to know why the UPDATE function does not return control to the main action and why RESULT on CONVERT function does not force to run program synchronously?
I would like to know why the UPDATE function does not return control to the main action and why RESULT on CONVERT function does not force to run program synchronously?
You're running into a common deadlock problem that I explain in full on my blog, due to the use of Result. Use await instead of Result and your problem goes away (in your case, since you have a collection, you'll want to await Task.WhenAll):
public async Task<SomeProduct[]> Get()
{
var collection = new List<Mother>() {
new Mother()
{
internalField = new List<Child>()
{
new Child()
{
theLastOne = "VAL"
},
new Child()
{
theLastOne = "VAL"
}
}
}
};
var oss =
from m in collection
from s in m.internalField
select Convert(m, s);
return Task.WhenAll(oss);
}
On a side note, you shouldn't use Task.Run in your implementations, particularly on ASP.NET. On ASP.NET, Task.Run completely removes all the benefits of async and adds overhead.
I am following this sample to implement a background server universal app. Here is the experimental code:
void MainPage::OnConnectionReceived(StreamSocketListener^ sender, StreamSocketListenerConnectionReceivedEventArgs^ args)
{
OutputDebugString(L"Connection received\n");
// No idea how to transfer request handling from foreground to background task!
}
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
// Code to register background task is omitted
auto listener = ref new StreamSocketListener();
listener->Control->QualityOfService = SocketQualityOfService::Normal;
try
{
listener->EnableTransferOwnership(Task->TaskId, SocketActivityConnectedStandbyAction::Wake);
}
catch (...)
{
OutputDebugString(L"Error: cannot transfer ownership\n");
}
listener->ConnectionReceived += ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>(this, &MainPage::OnConnectionReceived);
create_task(listener->BindServiceNameAsync("56789", SocketProtectionLevel::PlainSocket))
.then([this]()
{
OutputDebugString(L"Server started on port 56789\n");
auto m_httpClient = ref new HttpClient();
auto request = ref new HttpRequestMessage(HttpMethod::Get, ref new Uri("http://" + ip + ":56789/"));
auto request_operation = m_httpClient->SendRequestAsync(request, HttpCompletionOption::ResponseContentRead);
return create_task(request_operation);
}).then([this](task<HttpResponseMessage^> previousTask)
{
try {
auto response = previousTask.get();
// Code to process the response is omitted as it is irrelevant to the question
}
catch (Exception^ ex)
{
OutputDebugString(("Error: " + ex->Message + "\n")->Data());
}
});
}
At run time, I get the error: The attempted operation is not supported for the type of object referenced. which suggests that BindServiceNameAsync fails and I have no idea why as I have followed the documentation to do EnableTransferOwnership before doing the binding. What did I do wrong here?
You are getting The attempted operation is not supported for the type of object referenced. because you are using SocketActivityConnectedStandbyAction::Wake. Change it to SocketActivityConnectedStandbyAction::DoNotWake.
The following pseudo-code should give you an idea what else you need to do to make StreamSocketListener working with SocketActivityTrigger:
// TODO: task = socketTaskBuilder.Register();
socketListener = new StreamSocketListener();
socketListener.ConnectionReceived += OnConnected;
await socketListener.BindServiceNameAsync(port);
socketListener.EnableTransferOwnership(
task.TaskId,
SocketActivityConnectedStandbyAction.DoNotWake);
// This is required, otherwise you may get error:
// A device attached to the system is not functioning.
// (Exception from HRESULT: 0x8007001F)
await socketListener.CancelIOAsync();
socketListener.TransferOwnership(socketId);
Then, in the background task do:
public async void Run(IBackgroundTaskInstance taskInstance)
{
var deferral = taskInstance.GetDeferral();
var details = taskInstance.TriggerDetails as
SocketActivityTriggerDetails;
var socketInformation = details.SocketInformation;
var streamSocket = socketInformation.StreamSocket;
var socketListener = socketInformation.StreamSocketListener;
switch (details.Reason)
{
case SocketActivityTriggerReason.ConnectionAccepted:
// TODO: read, write, etc.
break;
default:
// ...
break;
}
// ...
deferral.Complete();
}
I am working on a Windows Universal App. I Want to get the Data from a Bluetooth Device to the Windows Phone. I am Using the Concept of RFCommCommunicationTrigger for this Purpose.
Here's the code Snippet I am Using
var rfTrigger = new RfcommConnectionTrigger();
// Specify what the service ID is
rfTrigger.InboundConnection.LocalServiceId = RfcommServiceId.FromUuid(new Guid("<some_base_guid>"));
//Register RFComm trigger
var rfReg = RegisterTaskOnce(
"HWRFCommTrigger",
"BackgroundLibrary.RFBackgroundTask",
rfTrigger, null
);
SetCompletedOnce(rfReg, OnTaskCompleted);
Here the Function of RegisterTaskOnce
static private IBackgroundTaskRegistration RegisterTaskOnce(string taskName, string entryPoint, IBackgroundTrigger trigger, params IBackgroundCondition[] conditions)
{
// Validate
if (string.IsNullOrEmpty(taskName)) throw new ArgumentException("taskName");
if (string.IsNullOrEmpty(entryPoint)) throw new ArgumentException("entryPoint");
if (trigger == null) throw new ArgumentNullException("trigger");
// Look to see if the name is already registered
var existingReg = (from reg in BackgroundTaskRegistration.AllTasks
where reg.Value.Name == taskName
select reg.Value).FirstOrDefault();
Debug.WriteLine("Background task "+ taskName+" is already running in the Background");
// If already registered, just return the existing registration
if (existingReg != null)
{
return existingReg;
}
// Create the builder
var builder = new BackgroundTaskBuilder();
builder.TaskEntryPoint = entryPoint;
builder.Name = taskName;
builder.SetTrigger(trigger);
// Conditions?
if (conditions != null)
{
foreach (var condition in conditions)
{
builder.AddCondition(condition);
}
}
// Register
return builder.Register();
}
Here's the code for SetCompletedOnce this will add a Handler only once
static private void SetCompletedOnce(IBackgroundTaskRegistration reg, BackgroundTaskCompletedEventHandler handler)
{
// Validate
if (reg == null) throw new ArgumentNullException("reg");
if (handler == null) throw new ArgumentNullException("handler");
// Unsubscribe in case already subscribed
reg.Completed -= handler;
// Subscribe
reg.Completed += handler;
}
I have also Written the BackgroundLibrary.RFBackgroundTask.cs
public sealed class RFBackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
try
{
Debug.WriteLine(taskInstance.TriggerDetails.GetType());
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
Debug.WriteLine("RFComm Task Running");
Debug.WriteLine(taskInstance.TriggerDetails.GetType().ToString());
}
catch (System.Exception e)
{
Debug.WriteLine("RFComm Task Error: {0}", e.Message);
}
deferral.Complete();
}
}
The Run Method is Invoked Every Time The Device tries to Open the Connection.
The type of the Trigger that is obtained (the type I am debugging in the run method of the RFBackgroundTask.cs) is printed as
Windows.Devices.Bluetooth.Background.RfcommConnectionTriggerDetails
But I am Unable use that because I dont have this Class in the BackgroundLibrary project.
The Documentation says that this Provides information about the Bluetooth device that caused this trigger to fire.
It has Variables like Socket,RemoteDevice etc.
I think I am Missing something very simple
Can you please help me out .
Once your background task is launched, simply cast the TriggerDetails object to an RfcommConnectionTriggerDetails object:
public sealed class RFBackgroundTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
try
{
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
RfcommConnectionTriggerDetails details = (RfcommConnectionTriggerDetails)taskInstance.TriggerDetails;
StreamSocket = details.Socket; // Rfcomm Socket
// Access other properties...
}
catch (System.Exception e)
{
Debug.WriteLine("RFComm Task Error: {0}", e.Message);
}
deferral.Complete();
}
}
I'm calling a powershell script from C#. The script is pretty small and is "gps;$host.SetShouldExit(9)", which list process, and then send back an exit code to be captured by the PSHost object.
The problem I have is when the pipeline has been stopped and disposed, the output reader PSHost collection still seems to be written to, and is filling up. So when I try and copy it to my own output object, it craps out with a OutOfMemoryException when I try to iterate over it. Sometimes it will except with a Collection was modified message. Here is the code.
private void ProcessAndExecuteBlock(ScriptBlock Block)
{
Collection<PSObject> PSCollection = new Collection<PSObject>();
Collection<Object> PSErrorCollection = new Collection<Object>();
Boolean Error = false;
int ExitCode=0;
//Send for exection.
ExecuteScript(Block.Script);
// Process the waithandles.
while (PExecutor.PLine.PipelineStateInfo.State == PipelineState.Running)
{
// Wait for either error or data waithandle.
switch (WaitHandle.WaitAny(PExecutor.Hand))
{
// Data
case 0:
Collection<PSObject> data = PExecutor.PLine.Output.NonBlockingRead();
if (data.Count > 0)
{
for (int cnt = 0; cnt <= (data.Count-1); cnt++)
{
PSCollection.Add(data[cnt]);
}
}
// Check to see if the pipeline has been closed.
if (PExecutor.PLine.Output.EndOfPipeline)
{
// Bring back the exit code.
ExitCode = RHost.ExitCode;
}
break;
case 1:
Collection<object> Errordata = PExecutor.PLine.Error.NonBlockingRead();
if (Errordata.Count > 0)
{
Error = true;
for (int count = 0; count <= (Errordata.Count - 1); count++)
{
PSErrorCollection.Add(Errordata[count]);
}
}
break;
}
}
PExecutor.Stop();
// Create the Execution Return block
ExecutionResults ER = new ExecutionResults(Block.RuleGuid,Block.SubRuleGuid, Block.MessageIdentfier);
ER.ExitCode = ExitCode;
// Add in the data results.
lock (ReadSync)
{
if (PSCollection.Count > 0)
{
ER.DataAdd(PSCollection);
}
}
// Add in the error data if any.
if (Error)
{
if (PSErrorCollection.Count > 0)
{
ER.ErrorAdd(PSErrorCollection);
}
else
{
ER.InError = true;
}
}
// We have finished, so enque the block back.
EnQueueOutput(ER);
}
and this is the PipelineExecutor class which setups the pipeline for execution.
public class PipelineExecutor
{
private Pipeline pipeline;
private WaitHandle[] Handles;
public Pipeline PLine
{
get { return pipeline; }
}
public WaitHandle[] Hand
{
get { return Handles; }
}
public PipelineExecutor(Runspace runSpace, string command)
{
pipeline = runSpace.CreatePipeline(command);
Handles = new WaitHandle[2];
Handles[0] = pipeline.Output.WaitHandle;
Handles[1] = pipeline.Error.WaitHandle;
}
public void Start()
{
if (pipeline.PipelineStateInfo.State == PipelineState.NotStarted)
{
pipeline.Input.Close();
pipeline.InvokeAsync();
}
}
public void Stop()
{
pipeline.StopAsync();
}
}
An this is the DataAdd method, where the exception arises.
public void DataAdd(Collection<PSObject> Data)
{
foreach (PSObject Ps in Data)
{
Data.Add(Ps);
}
}
I put a for loop around the Data.Add, and the Collection filled up with 600k+ so feels like the gps command is still running, but why. Any ideas.
Thanks in advance.
Found the problem. Named the resultant collection and the iterator the same, so as it was iterating, it was adding to the collection, and back into the iterator, and so forth. Doh!.