Execution after Async method not running - c#

I have this method in my ViewModel:
private async void InicializarModulo(IModuloNeotek modulo)
{
var t = _service.InitializeModuloAsync(DataProvider.NombreInstanciaSqlServer,
modulo, Empresa.NombreEmpresa);
ServiceResult<IModuloNeotek> sResult = await t;
if (sResult.HasErrors)// this never runs
MessageBox.Show("Error");
}
This is my service call:
public async Task<ServiceResult<IModuloNeotek>> InitializeModuloAsync(string dataSource,
IModuloNeotek modulo, string nombreEmpresa)
{
return await Task.Run(() => InitializeModulo(dataSource, modulo, nombreEmpresa));
}
EDIT:
public ServiceResult<IModuloNeotek> InitializeModulo(string dataSource, IModuloNeotek modulo, string nombreEmpresa)
{
ServiceResult<IModuloNeotek> sResult;
if (DatabaseExists(dataSource, Strings.GetDbName(nombreEmpresa, modulo.NombreModulo)))
{
sResult = new ServiceResult<IModuloNeotek>(null);
sResult.Error =
string.Format(
"El modulo {0} ya esta inicializado para esta empresa.",
modulo.NombreModulo);
return sResult;
}
SqlQueryResult qResult = new SqlQueryResult();
string connString = GenerateConnectionString(dataSource);
switch (modulo.NombreModulo)
{
case "Contabilidad":
qResult = ExecuteScript(connString, GetScriptStream(TipoModulo.Contabilidad, nombreEmpresa));
if (qResult.Result)
{
string query =
string.Format("INSERT INTO Modulos (NombreModulo, Inicializado, EmpresaId)" +
"VALUES ('{0}', 'true', (SELECT IdEmpresa FROM Empresas WHERE NombreEmpresa=" +
"'{1}')) ", modulo.NombreModulo, nombreEmpresa);
qResult = ExeCuteQuery(query, dataSource, Resources.MaterDbName);
if (qResult.Result)
{
sResult = new ServiceResult<IModuloNeotek>(modulo);
return sResult;
}
}
break;
case "Proveedores":
break;
case "Produccion":
break;
}
sResult = new ServiceResult<IModuloNeotek>(null);
sResult.Error = qResult.Error;
sResult.InnerError = qResult.InnerError;
return sResult;
}
So, why it is not continuing execution? I tried everything, returning a Task from service and awaiting in ViewModel, not returning Task.Run, simply the task, I dont know that to do, any clues? thanks

Try changing:
private async void InicializarModulo(IModuloNeotek modulo)
to:
private async Task InicializarModulo(IModuloNeotek modulo)

Your service call is incorrect. It is already awaiting itself.
Update to not await.
private async void InicializarModulo(IModuloNeotek modulo)
{
var t = _service.InitializeModuloAsync(DataProvider.NombreInstanciaSqlServer, modulo, Empresa.NombreEmpresa);
ServiceResult<IModuloNeotek> sResult = await t;
if (sResult.HasErrors)// this never runs
MessageBox.Show("Error");
}
public Task<ServiceResult<IModuloNeotek>> InitializeModuloAsync(string dataSource, IModuloNeotek modulo, string nombreEmpresa)
{
return Task.Run(() => InitializeModulo(dataSource, modulo, nombreEmpresa));
}

Related

Async call inside foreach does not execute following switch

I don't know the async/await mechanism very well and I searched on Google, but without finding an acceptable answer.
I have a question about the code below:
When using .Result, the switch() block is executed.
// Here the flow starts - the callee is a VueJS axios ajax call
[Route("ChangeStatusOrders/ValidateStatus")]
[HttpPost]
public async Task<ActionResult> ValidateStatus(OrdersToBeProcessed model)
{
bool success = false;
string message = "";
try
{
model.ReturnData = await _statusBusiness.Validate(model);
success = true;
return Json(new { Success = true, ReturnData = model.ReturnData }, JsonRequestBehavior.AllowGet);
}
catch (ArgumentException ex)
{
message = $"Bad Request {ex.Message}";
_log.Error(message);
Response.StatusCode = 400;
return Json(new { Success = false, ErrorMessage = message }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
message = $"Spomething wrong message here - {ex.Message}";
_log.Error(message);
Response.StatusCode = 500;
return Json(new { Success = false, ErrorMessage = message }, JsonRequestBehavior.AllowGet);
}
finally
{
var param = new
{
model.Orders,
model.NotesText,
model.CompanyID,
model.CompanyName,
model.NewStatus,
model.ReturnData,
model.CodeType,
model.UserID,
model.isInternalUser,
Message = message
};
LogUserAction(ActionType.ChangeStatusOrders, success, param);
}
}
private readonly IDictionary<bool, Func<List<string>, int, List<Order>>> _dic;
constructor()
{
// below methods are not async
_dic = new Dictionary<bool, Func<List<string>, int, List<Pedido>>>
{
{ true, (p) => _orderRepository.GetByID(p) },
{ false, (p) => _orderRepository.GetByCompanyID(p) }
};
}
public async Task<ProcessResults> Validate(OrdersToBeProcessed model)
{
ProcessResults result = new ProcessResults();
bool useOurID = (model.CodeType == 1);
return await Task.Run(() =>
{
try
{
List<string> ordersList = SplitOrders(model.Orders);
List<string> buffer = ordersList.Distinct().ToList();
List<Order> ordersList = new List<Order>(buffer.Count());
buffer.ForEach(item =>
{
var tmp = new Order();
if (useOurID)
tmp.ID = Convert.ToInt64(item);
else
tmp.CompanyId = item;
orderList.Add(tmp);
});
List<Order> foundOrders = _dic[useOurId](buffer);
result.SuccessfullOrders = new List<ProcessedOrder>();
result.NotFoundOrders = new List<ProcessedOrder>();
result.NotAllowedOrders = new List<ProcessedOrder>();
// merge the list of order's id with those one's found in database
List<Orders> union = foundOrders.MergeAndReplace(ordersList).ToList();
foreach (var item in union)
{
ProcessedOrder ret = ValidateAsync(item).Result; // <-- here is an Async call
switch (ret.ProcessedResult)
{
case ProcessedResultEnum.CanBeProcessed:
result.SuccessfullOrders.Add(ret);
break;
case ProcessedResultEnum.OrderNotFound:
result.NotFoundOrders.Add(ret);
break;
case ProcessedResultEnum.CannotBeProcessed:
result.NotAllowedOrders.Add(ret);
break;
}
}
return result;
});
private async Task<Order> ValidateAsync(Order item)
{
ProcessedOrder ret = new ProcessedOrder();
ret.CompanyID = item.CompanyID;
ret.Name = item.Name;
ret.ID = item.ID;
ret.Status = (item.Status?.ID).ToString();
var queueOrderItems = await _queueOrderService.SearchByOrderIdAsync(item.ID);
if (item.ID == 0 || String.IsNullOrEmpty(iitem.CodigoEntidade))
{
ret.Message = "Order not found in database.";
ret.Result = ProcessedResultEnum.OrderNotFound;
}
else if (item.Status == null || queueOrderItems == null)
{
ret.Message = "Order Cannot Be Processed";
ret.Result = ProcessedResultEnum.CannotBeProcessed;
}
else
{
ret.Message = "Order Can Be Processed";
ret.Result = ProcessedResultEnum.CanBeProcessed;
}
return ret;
}
public async Task<SearchBiIdResult> SearchByOrderIdAsync(long orderID )
{
SearchByIDResult ret;
SearchByIDRequest request = new SearchByIDRequest() { OrderID = orderID };
// calls a WCF async method descibed below
SearchByIDResponse response = await _queueOrderItemsClient.SearchByIDAsync(request);
ret = _mapper.Map<SearchByIDResponse>(response);
return ret;
}
// WCF async method definition (in reference.cs)
public System.Threading.Tasks.Task<UI.Services.Business.QueuesService.SearchByIDResponse> SearchByIDAsync(UI.Services.Business.QueuesService.SearchByIDRequest request) {
return base.Channel.SearchByIDAsync(request);
}
However, if I replace .Result with
ProcessedOrder ret = await ValidateAsync(item);
the loop immediately returns back up to the foreach statement, without executing the switch() block.
Can someone explain to me why this behavior?
I changed
return await Task.Run(() =>
to
return await Task.Run(async () =>
and the foreach block behaved as expected.

In mvc4 of net4, try to invoke the result of asynchronous method in synchronization method, deadlock occurs

In mvc4 of net4, try to invoke the result of asynchronous method in synchronization method, deadlock occurs.
I want it to run synchronously
public RespData PushMsg(string tel, int push_type, int push_type_sub, string alert, string title, string content, string href)
{
var result = Push.HMSPushV3(tel, push_type, push_type_sub, alert, title, content, href).ConfigureAwait(false).GetAwaiter().GetResult();
return reuslt;
}
This is the asynchronous method being called
public async static Task<RespData> HMSPushV3(string tel, int push_type, int push_type_sub, string alert, string title, string content, string href)
{
RespData r = new RespData();
string[] arr = tel.Split(',');
try
{
var device_token_list = Push.GetPolicy().GetHMSPushDeviceToken(arr);
var data = new PushModel()
{
alert = alert, content = content, href = href, push_type = push_type, title = title, push_type_sub_enum = push_type_sub
};
{
//Locked up in this place
var messageId = await HMSPush.SendToData(device_token_list, JsonConvert.SerializeObject(data));
r.Msg = $"透传:msgId {messageId}";
}
{
var message = HMSPush.CreateAndroidMessage(data);
var messageId = await HMSPush.SendToNotification(device_token_list, message);
r.Msg += $" 通知栏:msgId {messageId}";
}
r.State = 1;
r.Data = JsonConvert.SerializeObject(data);
}
catch (Exception e)
{
DB.FileLog.Error(e.Message, e);
r.Msg = e.Message;
r.State = 0;
}
return r;
}
Try just adding ConfigureAwait(false) to your async method that you are awaiting.
This method does not mean that the call will not be awaited, just that it doesn't have to be continued on the same thread:
var messageId = await HMSPush.SendToData(device_token_list, JsonConvert.SerializeObject(data))
.ConfigureAwait(false);

async causes debugger jump

I have this code:
private async Task<DataSharedTheatres.TheatresPayload> GetTheatres()
{
var callMgr = new ApiCallsManager();
var fileMgr = new FileSystemManager();
string cachedTheatres = fileMgr.ReadFile(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TheatreTemp.txt"));
if (string.IsNullOrEmpty(cachedTheatres))
{
**string generalModelPull = await callMgr.GetData(new Uri("somecrazyapi.com/api" + apiAccessKey));**
bool saveResult = fileMgr.WriteToFile(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TheatreTemp.txt"), generalModelPull);
if (!saveResult)
{
testText.Text = "Failed to load Theatre Data";
return null;
}
cachedTheatres = fileMgr.ReadFile(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TheatreTemp.txt"));
}
return Newtonsoft.Json.JsonConvert.DeserializeObject<DataSharedTheatres.TheatresPayload>(cachedTheatres);
**}**
I set the breakpoint on the first highlighted line (which it hits), then I press F10, and debugger jumps to the last bracket! I am not understanding why.
GetData method:
public async Task<string> GetData(Uri source)
{
if (client.IsBusy)
client.CancelAsync ();
string result = await client.DownloadStringTaskAsync (source);
return result;
}
Because that's what "await" does. When you use "await" in an async method, it tells the compiler that you want the method to return at that point, and then to re-enter the method later only when the "awaited" task has completed.

Async await how to use return values

I have a windows service that I have inherited from another developer, it runs very slow and has numerous slow call to the eBay API. I wish to speed it up without too much refactoring.
I've just started to look at using c# async/await to try to get some of these slow call to run async.
Here's what i'm trying to achieve:
I have a 1 very busy method that makes lots of calls as below:
getProducts
getCategories
getVehicles
getImages
My thoughts were that I could simply change the methods to async and add Task<T> to the return type as below:
public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem)
{
String additionalProductDetails = string.Empty;
if (oItem.ItemSpecifics.Count > 0)
{
foreach (NameValueListType nvl in oItem.ItemSpecifics)
{
if (nvl.Value.Count > 0)
{
foreach (string s in nvl.Value)
{
additionalProductDetails += "<li><strong>" + nvl.Name + ":</strong> " + s + "</li>";
}
}
}
}
return additionalProductDetails;
}
Then call them with await:
Task<String> additionalProductDetials = ebayPartNumbers.ProcessAdditionalProductDetialsAsync(item);
Task<PartNumberCollection> partNumberCollection = ebayPartNumbers.ProcessPartNumbersAsync(item);
await Task.WhenAll(partNumberCollection, additionalProductDetials);
How do I get hold of the returned types so I can use them? I have tried just using partNumberCollection but it only has the await properties available.
Use Result property on Task class:
await Task.WhenAll(partNumberCollection, additionalProductDetials);
var partNumberCollectionResult = partNumberCollection.Result;
var additionalProductDetialsResult = additionalProductDetials.Result;
If the task returned by Task.WhenAll has completed, that means all of the tasks that you passed to it have completed too. That in turn means that you can use the Result property of each task, with no risk of it blocking.
string details = additionalProductDetials.Result;
Alternatively, you could await the tasks, for consistency with other async code:
string details = await additionalProductDetials;
Again, this is guaranteed not to block - and if you later remove the Task.WhenAll for some reason (e.g. you're happy to use the details to kick off another task before you've got the part number collection) then you don't need to change the code.
Your async method lacks of await operators and will run synchronously. while you are calling non blocking API you could use Task.Run() to do cpu-bound work on background thread.
public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem)
{
return await Task.Run(() =>
{
String additionalProductDetails = string.Empty;
if (oItem.ItemSpecifics.Count > 0)
{
foreach (NameValueListType nvl in oItem.ItemSpecifics)
{
if (nvl.Value.Count > 0)
{
foreach (string s in nvl.Value)
{
additionalProductDetails += "<li><strong>" + nvl.Name + ":</strong> " + s + "</li>";
}
}
}
}
return additionalProductDetails;
});
}
and get result
var detail = await ProcessAdditionalProductDetialsAsync(itemType);
var result = ProcessAdditionalProductDetialsAsync(itemType).Result;
Try this code:
public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem) {
String additionalProductDetails = await Task.Run(() => {
if (oItem.ItemSpecifics.Count > 0) {
foreach (NameValueListType nvl in oItem.ItemSpecifics) {
if (nvl.Value.Count > 0) {
string retval = String.Empty;
foreach (string s in nvl.Value) {
retval += "<li><strong>"
+ nvl.Name + ":</strong> " + s + "</li>";
}
}
}
}
return retval;
}
return additionalProductDetails;
}
Usage:
private async void GetAdditionalProductDetailsAsync(Action<string> callback) {
string apd = await ProcessAdditionalProductDetialsAsync();
callback(apd);
}
private void AdditionalProductDetailsRetrieved(string apd) {
// do anything with apd
}

Web Service Call Loop/Not Finishing

For my app I make calls to a web service to get customer data. The problem I am encountering is when I make this particular call it gets the the asynchronous await call and loops back without finishing the call and then storing the results.
private void DatabaseTest()
{
cNum = Convert.ToString(db.selectCustomerNumber());
callC = "SELECT * FROM dashboardCustomer WHERE period = 'C' AND customerNumber = " + cNum;
callB = "SELECT * FROM dashboardCustomer WHERE period = 'B' AND customerNumber = " + cNum;
callF = "SELECT * FROM dashboardCustomer WHERE period = 'F' AND customerNumber = " + cNum;
if (db.selectDashboard(callC).Count == 0)
{
GetDataSummary(passC);
}
if (db.selectDashboard(callB).Count == 0)
{
GetDataSummary(passB);
}
if (db.selectDashboard(callF).Count == 0)
{
GetDataSummary(passF);
}
}
private async void GetDataSummary(string r)
{
long customerNum = db.selectCustomerNumber();
pin = db.selectPinByCustomerNumber(customerNum);
string cType = r;
try
{
Windows.Security.Credentials.PasswordVault vault = new Windows.Security.Credentials.PasswordVault();
IReadOnlyList<PasswordCredential> userCredential = vault.FindAllByResource(pin);
userCredential[0].RetrievePassword();
try
{
getCustomerBillSummaryResponse billSum = await
UBPclient.getCustomerBillSummaryAsync(userCredential[0].UserName, userCredential[0].Password, customerNum, cType);
invoiceSummaryBean[] summaryList = billSum.#return;
rh.DashboardHandler(summaryList, customerNum);
}
catch
{
}
}
catch
{
}
}
it runs to the following part
getCustomerBillSummaryResponse billSum = await
UBPclient.getCustomerBillSummaryAsync(userCredential[0].UserName, userCredential[0].Password, customerNum, cType);
and then loops back to the try and runs again until it has ran three times.
How do I make it return the data it is suppose to for each call and store it in my database?
Also I have tested the web service in SoapUI and the call is returning results, so the problem is not with the web service.
You need to do this:
private async Task GetDataSummary(string r)
You need to return Task instead of void because your caller needs to have something to wait for. When you return void, the caller must treat method as "fire-and-forget". When you return Task, the caller can create the necessary code to await for async method to finish.
And don't forget to add the await keyword when you call it: await GetDataSummaryAsync(...);
You should avoid async void. Change GetDataSummary to return Task and then await it from DatabaseTest:
private async Task DatabaseTestAsync()
{
...
if (db.selectDashboard(callC).Count == 0)
{
await GetDataSummaryAsync(passC);
}
if (db.selectDashboard(callB).Count == 0)
{
await GetDataSummaryAsync(passB);
}
if (db.selectDashboard(callF).Count == 0)
{
await GetDataSummaryAsync(passF);
}
}
private async Task GetDataSummaryAsync(string r)

Categories