I am having web api, which is non async.
From that web api, i am calling method
SmtpClient.SendMailAsync(email);
This email get sent to respective person, but the next web api request get fails.
public class TestController : ApiController
{
public TestController(TestService testService)
{
_testService = testService;
}
public IHttpActionResult Post(data)
{
_testService.SendEmail(data);
}
}
public class TestService
{
public async Task SendEmail(MailMessage email)
{
SmtpClient client = new SmtpClient();
client.SendMailAsync(email)
}
}
From the days before the async/await pattern was introduced, there are still many non-asychronous functions around in Framework classes.
SmtpClient client is one of the classes old enough for this. The SendFunction are the droids you are look for:
https://learn.microsoft.com/en-us/dotnet/api/system.net.mail.smtpclient.send
While the naming is a bit off and they return void, those seems to be the pre-async functions. Failure should be communicated via Exceptions in both cases.
Given your comment that you want to have SendEmail behave like fire & forget, I would propose using
Task.Run(() => _testService.SendEmail(data));
This will give the unit of work to the threadpool and free your request from the duty of waiting for this task. Generelly this is advised for fire & forget.
As a rule of thumb otherwise, it's generally a bad idea to call asynchronous things from a synchronous context. Do async all the way, or be prepared for deadlocking. For example, you could simply make your controller actions asynchronous as well.
If you will need use some result of sending:
public async IHttpActionResult Post(data)
{
var t = Task.Run(() =>_testService.SendEmail(data));
var result = await t;
// do something with result
}
- but of course your SendEmail function should return Task<> instead of Task ...
Related
We have an ASP.Net MVC application for our online store. User has to choose from multiple payment methods in order to buy something. For this we have implemented an abstract factory pattern:
public interface IPaymentServiceFactory
{
IPaymentService GetPaymentService(PaymentServiceEnum paymentServiceType);
}
public interface IPaymentService
{
PaymentSettingsModel GetPaymentSettingsModel();
}
It is used in our Action:
public ActionResult ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = paymentService.GetPaymentSettingsModel();
}
The problem occurs when we understand that some payment methods require async calls inside. For example 3rd party online payment service method must be asynchronously called through http for creating payment object on their side. The implemetation:
public class OnlinePaymentService : IPaymentService
{
private readonly IOnlinePaymentServiceApiClient _client;
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
var result = await _client.CreatePaymentAsync();
return result;
}
}
So we come up with a question: How to handle async and sync scenario for different payment methods. We`v decided to make everything async. Updated code:
public interface IPaymentService
{
Task<PaymentSettingsModel> GetPaymentSettings();
}
public async Task<ActionResult> ProcessCart(PaymentDataModel paymentData)
{
var paymentService = _paymentServiceFactory.GetPaymentService(paymentData.PaymentServiceType);
var paymentSettings = await paymentService.GetPaymentSettingsModel();
}
So far so good, but for implementing this for all other payment methods we were forced to use Task.Run:
public class CashPaymentService : IPaymentService
{
public async Task<PaymentSettingsModel> GetPaymentSettings()
{
return await Task.Run(() => new PaymentSettingsModel());;
}
}
As i can understand this creates two different threads for processing Action, which can cause performance issue.
Is there way to avoid such consequences? Is it really so bad to use Task.Run in particular case?
Is it really so bad to use Task.Run in particular case?
Yes, mainly because it's unnecessarily complicating things.
You can return a completed task whose result is a given value using Task.FromResult.
This is completely synchronous:
public class CashPaymentService : IPaymentService
{
public Task<PaymentSettingsModel> GetPaymentSettings()
{
return Task.FromResult( new PaymentSettingsModel() );
}
}
Note that async is missing here - that's possible because it is an implementation detail and not part of the definition of IPaymentService.
I have an API which is responsible for inserting text message details in database.
It does by making synchronous call to repository which I think could be implemented asynchronous way.How can I achieve this? Or what could be the best way to handle this scenario.Code snippet example is highly appreciated as I am still getting my ahead wrapping around .NET.
api:
public IHttpActionResult SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_service.SendSMS(smsNotification);
return Ok();
}
Service:
internal void SendSMS(SMSNotification smsNotification)
{
_repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
repo:
public virtual bool Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
sql.Execute();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
sql here is a custom thing and it has following methods:
public static int Execute(this IDataCommand #this);
[AsyncStateMachine(typeof(<ExecuteAsync>d__1))]
public static Task<int> ExecuteAsync(this IDataCommand #this);
Changing a blocking, typically IO-bound call (such as database, network or file system work) to async can make your app scale better.
This does have a flow-on affect through your API. That is, you need to be awaiting on asynchronous calls all the way up to the top-most call, otherwise, somewhere is going to block and you're just lost the benefit of calling an async API.
To demonstrate that, let's start from the bottom at the repository call, as that's the possibly expensive blocking operation can be made async. We alter sql.Execute to use the asynchronous version ExecutAsync version instead:
repo:
public virtual async Task<bool> Notify(SMSNotification request)
{
using (var sql = _sqlMapper.CreateCommand('Database', 'Stored proc'))
{
sql.AddParam("#fMessage", request.Message);
//..............
//.............. more params
var retvalParamOutput = sql.AddOutputParam("#fRetVal", System.Data.SqlDbType.Int);
await sql.ExecuteAsync();
return retvalParamOutput.GetSafeValue<int>() == 1;
}
}
Now here we have to change the signature of the method to return a Task wrapping a result of bool.
We also mark the method as async, so then we can use the "await" operator further down. Without doing this, we'd have to do more refactoring to manipulate and return the Task result ourselves, but the "async" modifier and "await" keyword let the compiler do that magic for us, and the rest of our code mostly looks like normal.
The mapper call doesn't really need to change:
mapper:
public SMSNotification GetSMSNotification(SMSNotification message)
{
return AutoMapper.Mapper.Map<SMSNotification>(message);
}
The service call is now making a call to an async method, so because we want to await and not block on that async call, we have to also change this previously void method to an async method. Note we change it from "void" to "async Task"; you CAN mark a void method as "async void", but that's intended as a workaround for event handlers in Windows Forms and WPF apps; in every other case you want to change a "void" method to "async Task" when making it async.
Service:
internal async Task SendSMS(SMSNotification smsNotification)
{
await _repository.Notify(_mapperService.GetSMSNotification(smsNotification));
}
Then finally, our API call can be made async, and await our service call:
api:
public async Task<IHttpActionResult> SendSMSNotification([FromBody] SMSNotification smsNotification)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _service.SendSMS(smsNotification);
return Ok();
}
It's sometimes recommended that after you do a refactor like this, to rename the methods to end in "Async" by convention; however I don't think this is really compulsory, as so much of the .NET API surface is becoming async, it's almost redundant now.
It's worth getting your head around the async / await stuff though; I've tried to keep the example relatively brief. But I hope this at least gets you started.
While i call the web api, asyn method start process. After completed API process then asyn process also stopped. Here is my sample code snippet. Please give any solution for this.
private readonly ITestService testservice;
public TestController(ITestService test)
{
this.testservice=test;
}
[Route("Sample/SaveMyData")]
[HttpPost]
public IHttpActionResult SaveMyData(MyInfo info)
{
MyInfo inf = new MyInfo ();
inf = testservice.SaveMyInformation(info);
SendMailProcess(inf)
return Ok<MyInfo>(inf);
}
private async Task<bool> SendMailProcess(MyInfo emailInfo)
{
await Task.Run(()=> this.testservice.SendMail(emailInfo));
return true;
}
#Eraiarasu, you are creating a separate Thread in your SendMailProcess and thats why your API call completes before the SendMailProcess completes.
Also, If you are trying to create async methods then please try to put await on SendMailProcess method invocation in SaveMyData as well. Also make SaveMyData as async too. Note that, you have SendAsync method in smtp api in .NET. So you don't have to use Task.Run as you did in SendMailProcess
This question already has answers here:
Anonymous interface implementation
(2 answers)
Closed 7 years ago.
I'm making a videogame and I need clients and server to communicate (in Unity).
The message from the server needs to be converted to a specific type based on the request: for example, the registration process will return just a bool in case of success or not; the login process must return a lot of information in a dictionary for the user who logged in (level, experience, game progress, etc.)
In java I used to do something like this:
net().post(url.toString(), safeUrl, new Callback<String>()
{
public void onFailure(Throwable t)
{
// do something to handle the failure...
}
public void onSuccess(String json)
{
// do something...
}
});
Basically the net().post was sending a post http request to the server, and once it was done the server was calling the correct method.
I read that C# can't do this, but that delegates can achieve something similar, do you know how? so basically I just send to the post request a method as parameter and handle it? Also is it possible to use generic types to handle the different types of requests?
Or Is there a better way to do this?
You have two alternatives here.
You can use Action<string> to pass in anonymous callbacks to your method.
Or...
you dive into the async/await world, which is the recommended approach.
Using anonymous delegates
Your Post signature would look like this:
public void Post(string url, string safeUrl, Action<string> onSuccess, Action<Exception> onFailure);
Notice that you must have an argument for each callback result.
Inside your Post method, you should call the callbacks when done.
From the client (or caller), you would call it like this:
Post(url, safeUrl, response =>
{
// Success callback body
}, exception =>
{
// Failure callback body
});
Using async/await (I don't know if this approach is supported in Unity)
Your Post signature would look like this:
public async Task<string> Post(string url, string safeUrl);
Inside your Post method, when sending the request you should use a method that support async/await, such as HttpClient.PostAsync():
// This is just an example
public async Task<string> Post(string url, string safeUrl)
{
HttpResponseMessage response = await httpClient.PostAsync(url, null);
string content = await response.Content.ReadAsStringAsync();
return content;
}
You would call it like this:
Task<string> fetchingResponse = Post(url, safeUrl);
// You can keep doing things while you wait for the response ...
try
{
string response = await fetchingResponse;
// Success logic here
}
catch(Exception ex)
{
// Failure logic here
}
Notice that there are no callbacks.
Also, keep in mind that your caller method (i.e. the method that is executing Post) should also be anotated with async and should also return a Task or Task<T> instance.
No, there is no direct equivalent to that in c#, however you may use delegates, e.g. as follows:
class Callback {
private readonly Action<Exception> onFailure;
private readonly Action<string> onSuccess;
public CallBack(Action<Exception> onFailure, Action<string> onSuccess) {
this.onFailure = onFailure;
this.onSuccess = onSuccess;
}
public void FireFailure(Exception e) {this.OnFailure(e);}
public void FireSuccess(string json) {this.OnSuccess(json);}
}
Now it is up to your net().post-method to fire the approriate events.
I have a Web API controller. It calls a method that returns an IAsyncResult. When I call the controller, I get the error
An asynchronous module or handler completed while an asynchronous operation was still pending.
How do I get the controller to wait for the asyncresult?
I was planning to use await, but I may just not have figured out the syntax for this use case.
I haven't found an existing answer on SO.
I'm using c# 4.5
[HttpGet]
[Route("GetGridDataAsync")]
public string GetGridDataAsync()
{
var proxy = new Proxy();
return proxy.BeginGetDataAsync("test", ar => proxy.EndGetDataAsync(ar));
}
public IAsyncResult BeginGetDataAsync(string r, AsyncCallback callback){}
public DataResponse[] EndGetDataAsync(IAsyncResult asyncResult){}
You can make your method an async Task<string>, create a Task based on the Async methods in the Proxy class and await that
Example:
public async Task<string> GetGridDataAsync()
{
var proxy = new Proxy();
return await Task.Factory.FromAsync(proxy.BeginGetDataAsync, proxy.EndGetDataAsync, "test", null);
}