Microsoft.Azure.NotificationHub - Async call in sync method - c#

I currently have to provide a sync as async method in my API: Please find the code below. The only problem is that I don’t have a
sync method in the backend. I use Azure.NotificationHub client. That client has only *Async methods. Is my way reasonable?
public PushHubNotificationResult SendPushMessage(string userId, string message)
{
PushHubNotificationResult result = new PushHubNotificationResult();
try
{
result = SendPushMessageAsync(userId, message).GetAwaiter().GetResult();
} catch (Exception ex)
{
result.Status = PushHubNotificationResultType.Error;
result.Error = ex.Message;
result.Exception = ex;
}
return result;
}
public async Task<PushHubNotificationResult> SendPushMessageAsync(string userId, string message)
{
PushHubNotificationResult result = new PushHubNotificationResult();
// EnableTestSend see: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-fixer/#self-diagnose-tips
// Create a new Notification Hub client.
Microsoft.Azure.NotificationHubs.NotificationHubClient hub =
Microsoft.Azure.NotificationHubs.NotificationHubClient.CreateClientFromConnectionString(NotificationHub, NotificationHubName);
// Sending the message so that all template registrations that contain "messageParam"
// will receive the notifications. This includes APNS, GCM, WNS, and MPNS template registrations.
Dictionary<string, string> templateParams = new Dictionary<string, string>();
templateParams["messageParam"] = message;
string userTag = "_UserId:" + userId; // That line sets the IMEI or SerialNo (WLAN only device) == userId to which the push message is sent
try
{
// Send the push notification and log the results.
NotificationOutcome outcome = await hub.SendTemplateNotificationAsync(templateParams, userTag);
result.Status = PushHubNotificationResultType.Success;
foreach (RegistrationResult hubResult in outcome.Results)
{
result.PushNotificationHub = hubResult.ApplicationPlatform;
result.RegistrationId = hubResult.RegistrationId;
result.Outcome = hubResult.Outcome;
}
}
catch (System.Exception ex)
{
result.Status = PushHubNotificationResultType.Error;
result.Error = ex.Message;
result.Exception = ex;
}
return result;
}
thanks for any advice,
Eric

If you want to use sync-over-async, it's very important that you use ConfigureAwait(false) in your async code, otherwise you are very likely to get a deadlock.
NotificationOutcome outcome =
await hub.SendTemplateNotificationAsync(templateParams, userTag).ConfigureAwait(false);
The async method already converts exceptions to PushHubNotificationResultType.Error, why does the sync version do it too?

Related

How to delete a Pool user in AWS Cognito and C#?

I have used the aws-samples example named aws-cognito-dot-net-desktop-app in C# and Android:
aws-cognito-dot-net-desktop-app
It works very well and correctly registers the user in Cognito.
To register a user, do the following:
bool success = await helper.SignUpUser(etUserName.Text, etPasswordUser.Text, etEmailUser.Text, etPhoneUser.Text);
That way the user is created, but a code needs to be entered that is sent to the user's email. The code entry is as follows:
CognitoHelper cognitoHelper = new CognitoHelper();
return await cognitoHelper.VerifyAccessCode(userName, codeSentToMail);
and the user registers without problems, that is to say, it works correctly:
Now I want to delete any user created, for which I am creating a task as follows:
internal async Task<bool> DeleteUser(string username)
{
try
{
AmazonCognitoIdentityProviderClient provider =
new Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials(), RegionEndpoint.USEast1);
DeleteUserPoolRequest request = new DeleteUserPoolRequest();
request.UserPoolId = username;
DeleteUserPoolResponse deleteUserPoolClientResponse = await provider.DeleteUserPoolAsync(request);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return false;
}
}
When executing DeleteUserPoolRequest, an exception is thrown indicating an error of type Amazon.Runtime.ErrorType.Unknown
Any idea what I'm doing wrong?
Any comments or suggestions are welcome.
public static async Task<bool> DeleteUserFromAws(string emailId)
{
try
{
AmazonCognitoIdentityProviderClient cognito =
new AmazonCognitoIdentityProviderClient(awsAccessKeyId, awsSecretAccessKey, Region1);
CognitoUserPool cognitoUserPool = new CognitoUserPool(poolId, appClienId, cognito);
AdminGetUserRequest adminGetUserRequest = new AdminGetUserRequest();
adminGetUserRequest.Username = emailId;
adminGetUserRequest.UserPoolId = poolId;
AdminGetUserResponse adminGetUserResponse = await cognito.AdminGetUserAsync(adminGetUserRequest);
var getUserNameByEmaliID = adminGetUserResponse.Username;
AmazonCognitoIdentityProviderClient provider =
new AmazonCognitoIdentityProviderClient(awsAccessKeyId, awsSecretAccessKey, Region1);
AdminDeleteUserRequest request = new AdminDeleteUserRequest();
CancellationToken cancellationToken = default;
request.Username = getUserNameByEmaliID;
request.UserPoolId = poolId;
await provider.AdminDeleteUserAsync(request,cancellationToken);
return true;
}
catch (Exception ex)
{
Logger.log(ex, (Int32)Category.Fatal, (Int32)Priority.High);
throw;
}
}

Continuous push message giving BadRequest from Azure

My service is register with azzure notification hub. And using my .net server API it push notification to particular device within particular time frame.
Everything goes right except when I try to send multiple push in same code it stuck with "BadRequest" except first one.
Below is the code
public static async void SendAzzurePushNotification()
{
for (int i = 0; i < 10; i++)
{
HttpStatusCode pushNotificationStatus = await CreateAndPushAsync("user_37");
Console.WriteLine(pushNotificationStatus);
}
}
static async Task<HttpStatusCode> CreateAndPushAsync(string tag)
{
HttpStatusCode pushNotificationStatus = HttpStatusCode.NotImplemented;
try
{
HttpResponseMessage response = null;
string uri = "<HUBURI>";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("SharedAccessSignature", <SASTOKEN>);
client.DefaultRequestHeaders.Add("ServiceBusNotification-Format", "gcm");
client.DefaultRequestHeaders.Add("ServiceBusNotification-Tags", tag);
client.DefaultRequestHeaders.Add("x-ms-version", "2015-01");
response = await client.PostAsync(uri,
new StringContent("{\"data\":{\"message\":\"Notification Hub test notification\"}}", Encoding.UTF8, "application/json"));
pushNotificationStatus = response.StatusCode;
}
catch (Exception ex)
{
throw;
}
return pushNotificationStatus;
}
Above code give me Created status for first time and then BadRequest after that. If same api I call from client like postman. It work fine.
I also tried nuget package from azure notification hub, regarding which code is as below. Which solve my above issue but it won't return me any status code which I can have in my above code for success.
NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<CONNECTIONSTRING>", "<HUB>");
NotificationOutcome outcome = await hub.SendGcmNativeNotificationAsync("{\"data\":{\"message\":\"Notification Hub test notification\"}}", "user_37");
Call send method with your tags and your notification-data
private static readonly string Endpoint = #"Your End Point";
private static readonly string HubName = #"You Hub Name";
private static NotificationHubClient Hub { get { return NotificationHubClient.CreateClientFromConnectionString(Endpoint, HubName); } }
public static async Task Send(string[] tags, object data)
{
try
{
string payload = string.Empty;
string json_gcm = string.Empty;
if (data.GetType() != typeof(string))
{
//If your notification data is of type
payload = JsonConvert.SerializeObject(data);
json_gcm = "{ \"data\" : " + payload + "}";
}
else
{
//If your notification data is simply is in string
payload = Convert.ToString(data);
json_gcm = "{ \"data\" : {\"message\":\"" + payload + "\"}}";
}
// Android
NotificationOutcome gcmOutcome = null;
gcmOutcome = await Hub.SendGcmNativeNotificationAsync(json_gcm, tags);
if (gcmOutcome != null)
{
if (!((gcmOutcome.State == NotificationOutcomeState.Abandoned) || (gcmOutcome.State == NotificationOutcomeState.Unknown)))
{
//Do code when notification successfully send to Android
}
}
}
catch (Exception ex)
{
//Do code when any exception occurred while sending notification
}
}
NotificationOutcomeState: Gives you status code in the form of enum that represent your notification has been successfully sent or not.
You may ignore if-else block as your need.
Try once may it help you

Is it possible that async code takes more time than sync?

I have a piece of code that execute HTTP requests (inside a loop) from some currency API and do some work on the data which received.
Because it was slow, I changed it to asynchronously function using: Task.Run()
However, when I measure calculation time (using Stopwatch..) of the function
with the async method, it takes more time (or even) than the sync one.
How can it possible? Am I do it wrong?
[HttpPost,Route("GetCurrenciesData")]
public IHttpActionResult GetCurrenciesData(InputCurrenciesData cls)
{
try
{
var watch = Stopwatch.StartNew();
var data2 = GetBL.mySyncMethod(cls.currenciesList);
watch.Stop();
string first = watch.Elapsed.ToString(); // --> this faster
watch = Stopwatch.StartNew();
var data = GetBL.myAsyncMethod(cls.currenciesList);
string second = watch.Elapsed.ToString(); // --> this slower
return Ok(data);
}
catch (Exception ex)
{
getGeneric.WriteError(ex.Message, ex.StackTrace);
return BadRequest();
}
}
Example code of the sync function:
public GenericClass mySyncMethod(string[] currencies)
{
try
{
foreach (string currency in currencies)
{
getDataFromApi(currency);
}
return getDataChart;
}
catch (Exception ex)
{
WriteError(ex.Message, ex.StackTrace);
return null;
}
}
Example of the async :
public GenericClass myAsyncMethod(string[] currencies)
{
try
{
List<Task> TaskList = new List<Task>();
foreach (string currency in currenies)
{
var myTask = new Task(() =>
{
getDataFromApi(currency);
});
myTask.Start();
TaskList.Add(myTask);
}
Task.WaitAll(TaskList.ToArray());
return getDataChart;
}
catch (Exception ex)
{
WriteError(ex.Message, ex.StackTrace);
return null;
}
}
The code of the function getDataFromApi:
private void getDataFromApi(string currency)
{
string currencyCode = getCurrenciesDictionary[currency];
//Get api's URL from Web.config and concatenation the wanted currency code
string URL = string.Format(GetConfig("Api"), currencyCode);
/*HTTP request to retrieve data from Api*/
using (HttpClientHandler handler = new HttpClientHandler())
{
handler.UseDefaultCredentials = true;
using (HttpClient httpClient = new HttpClient(handler))
{
var ResultAsync = httpClient.GetAsync(URL).Result;
if (ResultAsync.IsSuccessStatusCode)
{
var content = ResultAsync.Content;
string Data = content.ReadAsStringAsync().Result;
try
{
var ret = JsonConvert.DeserializeObject<RootObject>(Data);
/*add new class to currencyRate list - class which represent the currency and its rates*/
getDataChart.CurrencyRate.Add(new CurrencyRate
{
Currency = currency,
Rates = ret.dataset.data.AsEnumerable().
Select(date => Double.Parse(date[1].ToString())).ToList()
});
}
catch (Exception ex)
{
WriteError(ex.Message + " currency: " + currency + "/n/ URL: " + URL, ex.StackTrace);
}
}
}
}
try and read some of this guy:
http://blog.stephencleary.com/2012/02/async-and-await.html
http://blog.stephencleary.com/2016/12/eliding-async-await.html
he's telling in a few words how it works. The main point is that you get some overhead using async/await, however, you're freeing resources. So any task that will run, will run on the synchronized context. but you can handle much more request.
Besides the fact that you are not really using async functionality with the .result kills actually the async part.
In a short line, doing it async doesn't necessarily speed it up. If you have more CPU-bound tasks, that can run simultaneously you will major performance, however, in your case, you will not performance, but resources like Kevin tells in his comments.
hope it helps!

(Async & await) vs (without Async & await) in Web API

I am new with Async and await using C# Programming. In WebAPI, we have created two API Controllers one with Async and await Programming and other is without that. We have done load testing using JMeter and we have got following results.
Users Sync Async
100 No Errors No Errors
500 No Errors No Errors
750 No Errors Errors - (59.0 %) - 502 Bad Gateway
763 No Errors Errors
764 No Errors Errors
765 Errors - (0.13 %) - 502 Bad Gateway Errors
1000 Errors Errors
Can you any please explain/suggest which approach is best or how can we proceed ?
API Code :
GetPersonalDetailsController - Async and await Used
public async Task<IHttpActionResult> GET([FromUri] RequestQueryListDTO objAPIRequest)
{
DateTime startResponseTime = DateTime.Now;
Response objResponse = null;
string strResponse = string.Empty;
var HeaderType = Request.Content.Headers.ContentType;
ProductBAL objProductBAL = null;
try
{
if (objAPIRequest != null)
{
Task<Response> tskGetProductDetails = Task<Response>.Run(() =>
{
objProductBAL = new ProductBAL();
return objProductBAL.GetProductDetails(objAPIRequest);
//Business Access Layer Logic calling
});
objResponse = await tskGetProductDetails;
}
else
{
objResponse = new Response();
objResponse.ReturnCode = -1;
objResponse.ReturnMessage = "Missing Parameters.";
}
}
catch (Exception ex)
{
\\ Exception Logging
}
finally
{
objProductBAL = null;
}
objResponse.ResponseTime = Math.Round((DateTime.Now - startResponseTime).TotalMilliseconds).ToString();
if (objResponse.ReturnCode == Convert.ToInt32(General.ReturnCode))
{
return Content<Response>(HttpStatusCode.BadRequest, objResponse);
}
else
{
return Ok(objResponse);
}
}
========================================================================
GetPDPController - Without using Async and await
public IHttpActionResult GET([FromUri] RequestQueryListDTO objAPIRequest)
{
DateTime startResponseTime = DateTime.Now;
Response objResponse = null;
string strResponse = string.Empty;
var HeaderType = Request.Content.Headers.ContentType;
try
{
if (objAPIRequest != null)
{
//Business Access Layer Logic calling
}
else
{
objResponse = new Response();
objResponse.ReturnCode = -1;
objResponse.ReturnMessage = "Missing Parameters.";
}
}
catch (Exception ex)
{
// Exception Logging Code
}
finally
{
objProductBAL = null;
}
objResponse.ResponseTime = Math.Round((DateTime.Now - startResponseTime).TotalMilliseconds).ToString();
if (objResponse.ReturnCode == Convert.ToInt32(General.ReturnCode))
{
return Content<Response>(HttpStatusCode.BadRequest, objResponse);
}
else
{
return Ok(objResponse);
}
}
My suggestion is have two methods, one Async and one not. That way you can test more.
GetProductDetails
GetProductDetailsAsync
you would then need to change the signature of the calling method aka GET
public IHttpActionResult GET([FromUri] RequestQueryListDTO objAPIRequest)
{
var objResponse = new Response();
//check the properties of objAPIRequest
if(bad)
{
//add stuff if you want
return Content<Response>(HttpStatusCode.BadRequest, objResponse);
}
//Business Access Layer Logic calling
//-----------------------
ProductBAL objProductBAL = new ProductBAL();
//you need to change this to async
var productDetails = objProductBAL.GetProductDetails(objAPIRequest);
//-----------------------
return Ok(objResponse);
}

c# - Ignore exception on client side when server is down

I use RestSharp to pass data between the clien-side (Xamarin android app) and my server.
When there is an error (usually because the server is down) the method that execute the request throw an exception.
I want the exception to go back all the way to the method who called it, so I can throw an error to the user.
For example, I want to login, but lets say the server is down.
A - The method that execute the request
public Task<T> ExecuteAsync<T>(RestRequest request) where T : new()
{
var client = new RestClient
{
BaseUrl = new Uri(BaseUrl),
Authenticator = new HttpBasicAuthenticator(_accountName, _password)
};
var taskCompletionSource = new TaskCompletionSource<T>();
client.ExecuteAsync<T>(request, restResponse =>
{
if (restResponse.ErrorException != null)
{
throw (new Exception("Server returned an error"));
}
taskCompletionSource.SetResult(restResponse.Data);
});
return taskCompletionSource.Task;
}
B - Method that uses method A to execute a request
public static async Task<LoginObject> Login(string accessNumber, string password, string token)
{
var request = new RestRequest
{
Method = Method.POST,
Resource = "Login"
};
request.AddJsonBody(
new
{
accessNumber = accessNumber,
password = password,
token = token
});
var isDone = await Api.ExecuteAsync<LoginObject>(request);
return isDone;
}
C - The method where I want to handle the exception
public async Task Login(string PhoneNumber, string Password)
{
try
{
LoginObject login = await LoginServices.Login(PhoneNumber, Password, Token);
if (login.IsOk)
{
// Move to next activity
}
else
{
Toast.MakeText(this, "Login Error", ToastLength.Short).Show();
}
}
catch (Exception ex) // Here I want to throw the server error
{
Toast.MakeText(this, "Server Error", ToastLength.Short).Show();
return null;
}
}
Now when I run the code, the error is being thrown in A, and the app crash,
I want it to go from A to B and from B to C, and then I'll show an error to the user.
Edit: I tried to put a try/catch block but it still throws the exception in A.
Change method A to have async in the signature and then change your last line to return await taskCompletionSource.Task;
In your A-method, please use taskCompletionSource.SetException like this:
if (restResponse.ErrorException != null)
{
//throw new Exception("Server returned an error");
taskCompletionSource.SetException(new Exception("Server returned an error"));
}
else
{
taskCompletionSource.SetResult(restResponse.Data);
}
In your B-method replace this line:
var isDone = await Api.ExecuteAsync<LoginObject>(request);
with this to re-throw the exception to you C-method:
LoginObject isDone=null;
try
{
isDone = await Api.ExecuteAsync<LoginObject>(request);
}
catch (Exception e)
{
throw e;
}
This article is talking about TaskCompletionSource

Categories