Calling a method asynchronously using Task.Run - c#

Can someone help me how to make the call to the method SendSms(textMessageItems) asynchronous? What is the best method/practice? I am presuming that Task.Run Async-Await can be used here since I am using .Net4.5 using MVC4 WebApi. But I would like to hear from the experts as I am new to this. I am using this code in my web Server which is in IIS7 and this method could take sometime to process and so would like to process it asynchronously so that the response can return right away to the caller.
Also since I am calling the SendSms inside a for loop would it cause any issue? Do you think I should pass it as a collection List and then process? Please advise.
using Twilio.Mvc;
using Twilio.TwiML.Mvc;
using Twilio.TwiML;
public class SmsController : ApiController
{
[HttpPost]
public HttpResponseMessage Post([FromBody]SmsRequest smsReq)
{
var response = new Twilio.TwiML.TwilioResponse();
//validation checks..
try
{
if ((txtMessageResponse != null) && (txtMessageResponse.SmsMessageInfo.Count > 0))
{
_smsStagingList = txtMessageResponse.SmsMessageInfo;
foreach (TextMessageStaging prepareTextMessageResponse in _smsStagingList)
{
smsDTO textMessageItems = new smsDTO();
textMessageItems.PhoneNumber = prepareTextMessageResponse.PhoneNumber;
textMessageItems.SmsMessage = prepareTextMessageResponse.SmsMessageBody;
isTxtMessageSent = SendSms(textMessageItems);
//If the messages were sent then no need to set the flag to be updated
if (isTxtMessageSent)
{
txtMessageStatusToBeUpdated = false;
}
}
return Request.CreateResponse(HttpStatusCode.OK, twilioResponse.Element);
}
else
{
//send error response
}
catch (Exception msgProcessingError)
{
//send error response again as processing error
}
finally
{
//set the outbound flag in the table
}
}
private bool SendSms(smsDTO textMessageItems)
{
bool isTxtMessageSent = false;
PushMessageRequest txtMessageRequest = new PushMessageRequest();
PushMessageResponse txtMessageResponse = null;
txtMessageRequest.SmsMessageInfo = new SendTextMessage(); //instantiate the dto
txtMessageRequest.SmsMessageInfo.ToPhone = textMessageItems.PhoneNumber;
txtMessageRequest.SmsMessageInfo.TextMessage = textMessageItems.SmsMessage;
try
{
using (ITextService textService = ObjectFactory.SendSmsMessage())
{
txtMessageResponse = textService.SendSmsMessage(txtMessageRequest);
}
isTxtMessageSent = txtMessageResponse.IsSuccessful;
}
catch (Exception ex)
{
isTxtMessageSent = false;
}
return isTxtMessageSent;
}

I recommend that you not use Task.Run. AFAIK, Twilio does not have an async API, so you should ask them about that. You could of course write your own, e.g., based on HttpClient.
would like to process it asynchronously so that the response can return right away to the caller
Please note that async does not change the HTTP protocol, as described on my blog. It is possible, but extremely dangerous, to return a response from ASP.NET while the request has not finished processing (also a link to my blog).

Related

How can you wait on AppDomain to process async callback in C# and then return the results?

I have some code that loads up and AppDomain(call it domain) calling an object function within the domain. The purpose is to get a list of items from a usb device using the device API to retrieve the information. The API requires a callback to return the information.
var AppDomain.CreateDomain(
$"BiometricsDomain{System.IO.Path.GetRandomFileName()}");
var proxy = domain.CreateInstanceAndUnwrap(proxy.Assembly.FullName, proxy.FullName
?? throw new InvalidOperationException()) as Proxy;
var ids = obj.GetIdentifications();
The proxy code loaded into the domain is as follows
public class Proxy : MarshalByRefObject
{
public List<String> GetIdentifications()
{
var control = new R100DeviceControl();
control.OnUserDB += Control_OnUserDB;
control.Open();
int nResult = control.DownloadUserDB(out int count);
// need to be able to return the list here but obviously that is not
// going to work.
}
private void Control_OnUserDB(List<String> result)
{
// Get the list of string from here
}
}
Is there a way to be able to wait on the device and return the information as needed when the callback is called? Since the GetIdentifications() has already returned I don't know how to get the
You can consider wrapping the Event-Based Asynchronous Pattern (EAP) operations as one task by using a TaskCompletionSource<TResult> so that the event can be awaited.
public class Proxy : MarshalByRefObject {
public List<String> GetIdentifications() {
var task = GetIdentificationsAsync();
return task.Result;
}
private Task<List<String>> GetIdentificationsAsync() {
var tcs = new TaskCompletionSource<List<string>>();
try {
var control = new R100DeviceControl();
Action<List<string>> handler = null;
handler = result => {
// Once event raised then set the
// Result property on the underlying Task.
control.OnUserDB -= handler;//optional to unsubscribe from event
tcs.TrySetResult(result);
};
control.OnUserDB += handler;
control.Open();
int count = 0;
//call async event
int nResult = control.DownloadUserDB(out count);
} catch (Exception ex) {
//Bubble the error up to be handled by calling client
tcs.TrySetException(ex);
}
// Return the underlying Task. The client code
// waits on the Result property, and handles exceptions
// in the try-catch block there.
return tcs.Task;
}
}
You can also improve on it by adding the ability to cancel using a CancellationToken for longer than expected callbacks.
With that the proxy can then be awaited
List<string> ids = proxy.GetIdentifications();
Reference How to: Wrap EAP Patterns in a Task
NOTE: Though there may be more elegant solutions to the problem of asynchronous processing, the fact that this occurs in a child AppDomain warrants child AppDomain best practices. (see links below)
i.e.
do not allow code meant for a child AppDomain to be executed in the parent domain
do not allow complex types to bubble to the parent AppDomain
do not allow exceptions to cross AppDomain boundaries in the form of custom exception types
OP:
I am using it for fault tolerance
First I would probably add a Open or similar method to give time for the data to materialise.
var proxy = domain.CreateInstanceAndUnwrap(proxy.Assembly.FullName, proxy.FullName
?? throw new InvalidOperationException()) as Proxy;
proxy.Open(); // <------ new method here
.
. some time later
.
var ids = obj.GetIdentifications();
Then in your proxy make these changes to allow for data processing to occur in the background so that by the time you call GetNotifications data may be ready.
public class Proxy : MarshalByRefObject
{
ConcurrentBag<string> _results = new ConcurrentBag<string>();
public void Open()
{
var control = new R100DeviceControl();
control.OnUserDB += Control_OnUserDB;
control.Open();
// you may need to store nResult and count in a field?
nResult = control.DownloadUserDB(out int count);
}
public List<String> GetIdentifications()
{
var copy = new List<string>();
while (_results.TryTake(out var x))
{
copy.Add(x);
}
return copy;
}
private void Control_OnUserDB(List<String> result)
{
// Get the list of string from here
_results.Add (result);
}
}
Now you could probably improve upon GetNotifications to accept a timeout in the event either GetNotifications is called before data is ready or if you call it multiply but before subsequent data to arrive.
More
How to: Run Partially Trusted Code in a Sandbox
Not sure why you just don't maintain a little state and then wait for the results in the call:
public class Proxy : MarshalByRefObject
{
bool runningCommand;
int lastResult;
R100DeviceControl DeviceControl { get{ if(deviceControl == null){ deviceControl = new R100DeviceControl(); deviceControl.OnUserDB += Control_OnUserDB; } return deviceControl; } }
public List<String> GetIdentifications()
{
if(runningCommand) return null;
DeviceControl.Open();
runningCommand = true;
lastResult = control.DownloadUserDB(out int count);
}
private void Control_OnUserDB(List<String> result)
{
runningCommand = false;
// Get the list of string from here
}
}
Once you have a pattern like this you can easily switch between async and otherwise whereas before it will look a little harder to understand because you integrated the async logic, this way you can implement the sync method and then make an async wrapper if you desire.

ASP.NET Web API POST sending a VM and returning other VM

I'm trying to call API sending a viewmodel and receive back another one, using HttpClient.PutAsync, unsuccessfully.
My API works fine running PostMan, but it's a disaster in Xamarin.Forms (PostAsync stops working and the controls is sent back to calling method, I mean, It is terminated not even getting handled by "catch")
What is the proper way to do that? Thanks in advance.
My C# class:
public class MyNecessaryService
{
private const string wsUrl = "https://my-ws-uri/api/blahblahblah;
public async Task<OutputViewModel> PleaseDoIt(InputViewModel input)
{
OutputViewModel output = new OutputViewModel();
try
{
// let's get started
var httpClient = new HttpClient();
// turns "my input view model" into JSON format
var jsonConvert = JsonConvert.SerializeObject(input);
// parameters is part of HTTP request
var httpContent = new StringContent(jsonConvert);
// "please send me a JSON"
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// do it now, please
var httpResponseMessage = await httpClient.PostAsync(wsUrl,httpContent);
// ------ hellgate ------
// PostAsync call never reach this line, neither the "catch" parts.
// It jumps FTL back to calling async method ...
var isSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
// if the response contains stuff I'd like to read ...
if (isSuccessStatusCode && httpResponseMessage.Content != null)
{
// ...get my content, ...
var responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
// ...turns JSON into "my output view model"
output = JsonConvert.DeserializeObject<OutputViewModel>(responseContent);
}
}
catch (WebException wex)
{
Debug.WriteLine("WebException =======> " + wex.Message);
}
catch (Exception ex)
{
Debug.WriteLine("Exception =======> " + ex.Message);
}
finally
{
// nothing for a while...
}
return output;
}
}
The Calling method:
public async Task<OutputViewModel> GetMyData(InputViewModel input)
{
// ... declarations and decision making ....
var service = new MyNecessaryService();
output = await service.PleaseDoIt(input);
return output;
}
Solution found!
The API was called from a blocking Command Button.
Reviewing the stack:
A XAML Page has some entries for the Input and a Button:
<Entry ... />
<Entry ... />
<Button Text="GetData" Command="{Binding GetDataCommand}"/>
The PageViewModel has the Button Command to get the data from the API:
private Command command;
public ICommand GetDataCommand
{
get
{
getDataCommand = command ?? new Command(DoCommand, CanExecute);
return command;
}
}
This method, called from Command, must be awaitable.
Otherwise the API call will be blocked.
private async void DoCommand()
{
// ... prepare input model and call GetMyData ...
output = await GetMyData(input); // not blocking anymore...
// ... go on and show next Page
}

C# - Try something twice if if-statement is true

I have a code parsing a website and adding some values to a list. Sometimes I need to parse the website two times and add the second parsevalues to the same list.
This is some of the code:
public async Task<IEnumerable<Info>>....
{
var values = new List<Info>();
var request = something;
var request_rewritten = rewritten request to run the second time;
......
if request contains something do all the under two times. Both for the request and the rewritten request and add it to result.
......
var response = await RequestBytes(request);
var results = Encoding.GetEncoding("iso-8859-1").GetString(response.Content);
_fDom = results;
try
{
do something and a lot of code
......
values.Add(result);
return result
}
}
If request contains something I need try try a second time. Both for the original request and the rewritten request and add both to the result. Can this be done?
You can follow this pattern. Add an additional parameter to your method indicating retries remaining.
void DoSomething(arg1, arg2, int retriesRemaining = 0)
{
try
{
DoWork();
}
catch
{
if (retriesRemaining) DoSomething(arg1, arg2, --retriesRemaining);
}
}
I suppose if you want to avoid writing a method (which is the best answer to your question) you can use a flag:
bool bRunAgain = true;
while (bRunAgain)
{
// Your logic, check result and see if you need to run it again
if (your condition to run again == false)
{
bRunAgain = false;
}
}
Here is a common solution. Pass an action to this method and specify retries count
public bool ExecuteWithRetry(Action doWork, int maxTries=1) {
for(var tryCount=1; tryCount<=maxTries; tryCount++){
try{
doWork();
} catch(Exception ex){
if(tryCount==MaxTriex){
Console.WriteLine("Oops, no luck with DoWork()");
return false;
}
}
return true;
}
}
so in your method
void Something(){
....
if(ExecuteWithRetry(()=>NotTrustyMethod(), 2)) {
//success
} else {
//fail
}
}
void NotTrustyMethod(){ ...}
This solution you can use for any case where you need retry option for methods with any type of arguments (or without them)

Call to Web API from Xamarin Android not returning results

Hi I have created a solution with 3 projects in it. My solution has a Windows console app, a Xamarin Android project and a portable class library (PCL). I have referenced my PCL in both the Console and Android app. My PCL has my Models and ViewModels and i am calling a Web API from the viewModels. Here is a sample viewModel
public class RoutineViewModel
{
public async Task<IEnumerable<Routine>> GetRoutines()
{
//Lets Get List from Routines Web API
try
{
var client = new HttpClient();
var json = await client.GetStringAsync(BroadCastApiUrls.Routines);
var results = JsonConvert.DeserializeObject<IEnumerable<Routine>>(json);
if (results.Any())
return results;
return null;
}
catch (Exception ex)
{
//Some logging code here
return null;
}
}
}
I am making via an instance of this RoutineViewModel in a Method call from a button click handler, here is the code calling the GetRoutines Method
//In the Activity class
readonly RoutineViewModel routineViewModel = new RoutineViewModel();
private async Task<bool> LoadRoutines()
{
try
{
var routines = await routineViewModel.GetRoutines();
if (routines != null)
{
routinesList = routines.ToList();
listView.Adapter = new RoutinesListAdapter(this, routinesList);
}
else
{
var builder = new AlertDialog.Builder(this);
var alert = builder.Create();
alert.SetTitle("No Results!");
// alert.SetIcon(Resource.Drawable)
alert.SetMessage("No Routines From API!");
alert.DismissEvent += alert_DismissEvent;
alert.Show();
return true;
}
}
catch (Exception ex)
{
//Some logging and clean up code
}
return false;
}
This call returns the expected results from my console app but the same method call on my android simulator returns no results. What am i missing here? its driving me nuts.
Edit
From the loadRoutines click handler the call is
bool isLoaded = await LoadRoutines();
You're probably calling Task<T>.Result or Task.Wait further up the call stack, which will work on Console apps but fail in a GUI context. I explain this behavior in more detail on my blog.
The best solution is to use await instead of Result or Wait. Note that this means you'll have to decide what your UI looks like while the routines are loading, and then update it with the results when the loading completes.

Portable Class Library HttpClient

For one of my projects I want to develop a library that can be used in different platforms (Desktop, Mobile, Surface, etc). Hence have opted Porable Class Library.
I am developing a class for calling different API calls' using HttpClient. I am stuck with how to call the method, response and work around. This is my code :-
public static async Task<JObject> ExecuteGet(string uri)
{
using (HttpClient client = new HttpClient())
{
// TODO - Send HTTP requests
HttpRequestMessage reqMsg = new HttpRequestMessage(HttpMethod.Get, uri);
reqMsg.Headers.Add(apiIdTag, apiIdKey);
reqMsg.Headers.Add(apiSecretTag, ApiSecret);
reqMsg.Headers.Add("Content-Type", "text/json");
reqMsg.Headers.Add("Accept", "application/json");
//response = await client.SendAsync(reqMsg);
//return response;
//if (response.IsSuccessStatusCode)
//{
string content = await response.Content.ReadAsStringAsync();
return (JObject.Parse(content));
//}
}
}
// Perform AGENT LOGIN Process
public static bool agentStatus() {
bool loginSuccess = false;
try
{
API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Wait();
// ACCESS Response, JObject ???
}
catch
{
}
finally
{
}
Like ExecuteGet, I will also create for ExecutePost. My query is from ExecuteGet, if (1) I pass JObject on parsing when IsSuccessStatusCode only, then how can I know about any other errors or messages to inform the user. (2) If I pass response, then how do I assign it here
response = API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Wait();
that is giving error.
What would be the best approach to handle this situation ? And I got to call multiple API's, so different API will have different result sets.
Also, can you confirm that designing this way and adding PCL reference I will be able to access in multiple projects.
UPDATE :-
As mentioned in below 2 answers I have updated my code. As mentioned in the provided link I am calling the from the other project. This is my code :-
Portable Class Library :-
private static HttpRequestMessage getGetRequest(string url)
{
HttpRequestMessage reqMsg = new HttpRequestMessage(HttpMethod.Get, url);
reqMsg.Headers.Add(apiIdTag, apiIdKey);
reqMsg.Headers.Add(apiSecretTag, ApiSecret);
reqMsg.Headers.Add("Content-Type", "text/json");
reqMsg.Headers.Add("Accept", "application/json");
return reqMsg;
}
// Perform AGENT LOGIN Process
public static async Task<bool> agentStatus() {
bool loginSuccess = false;
HttpClient client = null;
HttpRequestMessage request = null;
try
{
client = new HttpClient();
request = getGetRequest("http://api.mintchat.com/agent/autoonline");
response = await client.SendAsync(request).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
JObject o = JObject.Parse(content);
bool stat = bool.Parse(o["status"].ToString());
///[MainAppDataObject sharedAppDataObject].authLogin.chatStatus = str;
o = null;
}
loginSuccess = true;
}
catch
{
}
finally
{
request = null;
client = null;
response = null;
}
return loginSuccess;
}
From the other WPF project, in a btn click event I am calling this as follows :-
private async void btnSignin_Click(object sender, RoutedEventArgs e)
{
/// Other code goes here
// ..........
agent = doLogin(emailid, encPswd);
if (agent != null)
{
//agent.OnlineStatus = getAgentStatus();
// Compile Error at this line
bool stat = await MintWinLib.Helpers.API_Utility.agentStatus();
...
I get these 4 errors :-
Error 1 Predefined type 'System.Runtime.CompilerServices.IAsyncStateMachine' is not defined or imported D:\...\MiveChat\CSC
Error 2 The type 'System.Threading.Tasks.Task`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f89d50a3a'. D:\...\Login Form.xaml.cs 97 21
Error 3 Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly? D:\...\Login Form.xaml.cs 97 33
Error 4 Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly? D:\...\Login Form.xaml.cs 47 28
I tried adding System.Threading.Tasks from the PCL library only, that gave 7 different errors. Where am I going wrong ? What to do to make this working ?
Please guide me on this. Have spend lots of hours figuring the best to develop a library accessible to desktop app & Win Phone app.
Any help is highly appreciative. Thanks.
If you call an async api when making the http calls, you should also expose that async endpoint to the user, and not block the request using Task.Wait.
Also, when creating a third party library, it is recommanded to use ConfigureAwait(false) to avoid deadlocks when the calling code tries to access the Result property or the Wait method. You should also follow guidelines and mark any async method with Async, so the method should be called ExecuteStatusAsync
public static Task<bool> AgentStatusAsync()
{
bool loginSuccess = false;
try
{
// awaiting the task will unwrap it and return the JObject
var jObject = await API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").ConfigureAwait(false);
}
catch
{
}
}
And inside ExecuteGet:
response = await client.SendAsync(reqMsg).ConfigureAwait(false);
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
In case IsSuccessStatusCode is false, you may throw an exception to the calling code to show something went wrong. To do that, you can use the HttpResponseMessage.EnsureSuccessStatusCode which throws an exception if the status code != 200 OK.
Personally, if ExecuteGet is a public API method i would definitely not expose it as a JObject but a strongly typed type.
If you want the result of the task, you need to use the Result property:
var obj = API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Result;
However, it's usually not a good idea to wait synchronously for an async method to complete, because it can cause deadlocks. The better approach is to await the method:
var obj = await API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline");
Note that you need to make the calling method async as well:
public static async Task<bool> agentStatus()
Sync and async code don't play together very well, so async tends to propagate across the whole code base.

Categories