(I'm using .Net 4.0)
I want to call a WCF service asynchronously, from my service layer. This service layer is used by and MVC.Net controller. I've read that it's good practice to call a WCF service asynchronously. So I'm using begin/end (apm). I want to double check if I'm doing it richt:
public byte[] GetSomeData()
{
IAsyncResult result = myServiceClient.BeginDoSomething(someInputValue, null, null);
var data = _pdfCreatieService.EndCreateForPreview(result);
return data;
}
I'm not totally sure about the code above, because I've seen constructions like the code below, which seem a bit more complex and unnecessary in my case:
public byte[] GetSomeData()
{
var myState = new MyState();
IAsyncResult result = _myServiceClient.BeginDoSomething(someInputValue, CreateForPreviewCallback, myState);
result.AsyncWaitHandle.WaitOne();
return myState.Bytes;
}
private void DoSomethingCallback(IAsyncResult result)
{
var myState = (MyState)result.AsyncState;
myState.Bytes = _myServiceClient.EndDoSomething(result);
}
Thanks Avner Shahar-Kashtan, Ned Stoyanov and Noseratio. Your answers are really insightfull!
What your code will do is, in effect, take an asynchronous method and call it synchronously. When you call the EndDoSomething method, you are effectively blocking your thread until the asynchronous method has completed, which is exactly the opposite of an async call.
Of course, your second code block also calls the code synchronously, by blocking executing explicitly, using the waithandle.
What you want to do is, instead of returning the byte[] from your initial method, have your DoSomethingCallback do something active with the bytes - either store them in some class member that can be checked by the controller, raise an event, or do something else. If you're waiting for your async call, you're not getting any benefit.
What you can also do if you're using .NET 4.5 or higher (or .NET 4.0 in VS2012, using the BCL Async Package) is to use async/await, which is a nice wrapper which will allow you to consolidate the calling method and the callback method into a single, more coherent method.
But regardless of the syntax or libraries you choose, your first step is to understand that async programming necessarily breaks your code's control flow into the invocation and the result callback, or continuation of the asynchronous operation.
In ASP.NET MVC, you only benefit from asynchronous calls if your controller is asynchronous too. Apparently, this is not the case with your code, because you're blocking with WaitOne inside your controller's method.
Implementing asynchronous controllers is really easy with .NET 4.5, check "Using Asynchronous Methods in ASP.NET MVC 4" for more info.
With .NET 4.0, it's a bit more tedious, check "Using an Asynchronous Controller in ASP.NET MVC". Your controller should derive from AsyncController and use AsyncManager to notify the ASP.NET stack about the pending asynchronous operations.
Here's an example from there for .NET 4. 0, adapted for your case(untested). Note the use of Task.Factory.FromAsync and Task.ContinueWith:
public static class WcfExt
{
public static Task<byte[]> DoSomethingAsync(
this IMyService service,
string someInputValue)
{
return Task.Factory.FromAsync(
(asyncCallback, asyncState) =>
service.BeginDoSomething(someInputValue, asyncCallback, asyncState),
(asyncResult) =>
service.EndDoSomething(asyncResult);
}
}
public class PortalController : AsyncController
{
public void NewsAsync(string someInputValue) {
AsyncManager.OutstandingOperations.Increment();
var myService = new MyService();
myService.DoSomethingAsync(someInputValue).ContinueWith((task) =>
{
AsyncManager.Parameters["data"] = task.Result;
AsyncManager.OutstandingOperations.Decrement();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
public ActionResult NewsCompleted(byte[] data)
{
return View("News", new ViewStringModel
{
NewsData = data
});
}
}
Both of your approaches are doing what is called sync over async. That is executing an asynchronous method in synchronous fashion. A better approach would be to build your own asynchronous method to rerieve the data with TaskCompletionSource. I haven't tested this, but you should be able to do something like this:
public Task<byte[]> GetSomeDataAsync()
{
var tcs = new TaskCompletionSource();
IAsyncResult result = myServiceClient.BeginDoSomething(someInputValue, x =>
{
try
{
var data = _pdfCreatieService.EndCreateForPreview(result);
tcs.SetResult(data);
}
catch(Exception ex)
{
tcs.SetException(ex);
}
}, null);
return tcs.Task;
}
Then to use it simply do this
GetSomeDataAsync().ContinueWith(t => /*<Use retrieved data from t.Result>*/);
This code will return straight away and once the asynchronous operation is complete the ContinueWith part will execute.
Related
I have 30 sub companies and every one has implemented their web service (with different technologies).
I need to implement a web service to aggregate them, for example, all the sub company web services have a web method with name GetUserPoint(int nationalCode) and I need to implement my web service that will call all of them and collect all of the responses (for example sum of points).
This is my base class:
public abstract class BaseClass
{ // all same attributes and methods
public long GetPoint(int nationalCode);
}
For each of sub companies web services, I implement a class that inherits this base class and define its own GetPoint method.
public class Company1
{
//implement own GetPoint method (call a web service).
}
to
public class CompanyN
{
//implement own GetPoint method (call a web service).
}
so, this is my web method:
[WebMethod]
public long MyCollector(string nationalCode)
{
BaseClass[] Clients = new BaseClass[] { new Company1(),//... ,new Company1()}
long Result = 0;
foreach (var item in Clients)
{
long ResultTemp = item.GetPoint(nationalCode);
Result += ResultTemp;
}
return Result;
}
OK, it works but it's so slow, because every sub companys web service is hosted on different servers (on the internet).
I can use parallel programing like this:(is this called parallel programing!?)
foreach (var item in Clients)
{
Tasks.Add(Task.Run(() =>
{
Result.AddRange(item.GetPoint(MasterLogId, mobileNumber));
}
}
I think parallel programing (and threading) isn't good for this solution, because my solution is IO bound (not CPU intensive)!
Call every external web service is so slow, am i right? Many thread that are pending to get response!
I think async programming is the best way but I am new to async programming and parallel programing.
What is the best way? (parallel.foreach - async TAP - async APM - async EAP -threading)
Please write for me an example.
It's refreshing to see someone who has done their homework.
First things first, as of .NET 4 (and this is still very much the case today) TAP is the preferred technology for async workflow in .NET. Tasks are easily composable, and for you to parallelise your web service calls is a breeze if they provide true Task<T>-returning APIs. For now you have "faked" it with Task.Run, and for the time being this may very well suffice for your purposes. Sure, your thread pool threads will spend a lot of time blocking, but if the server load isn't very high you could very well get away with it even if it's not the ideal thing to do.
You just need to fix a potential race condition in your code (more on that towards the end).
If you want to follow the best practices though, you go with true TAP. If your APIs provide Task-returning methods out of the box, that's easy. If not, it's not game over as APM and EAP can easily be converted to TAP. MSDN reference: https://msdn.microsoft.com/en-us/library/hh873178(v=vs.110).aspx
I'll also include some conversion examples here.
APM (taken from another SO question):
MessageQueue does not provide a ReceiveAsync method, but we can get it to play ball via Task.Factory.FromAsync:
public static Task<Message> ReceiveAsync(this MessageQueue messageQueue)
{
return Task.Factory.FromAsync(messageQueue.BeginReceive(), messageQueue.EndPeek);
}
...
Message message = await messageQueue.ReceiveAsync().ConfigureAwait(false);
If your web service proxies have BeginXXX/EndXXX methods, this is the way to go.
EAP
Assume you have an old web service proxy derived from SoapHttpClientProtocol, with only event-based async methods. You can convert them to TAP as follows:
public Task<long> GetPointAsyncTask(this PointWebService webService, int nationalCode)
{
TaskCompletionSource<long> tcs = new TaskCompletionSource<long>();
webService.GetPointAsyncCompleted += (s, e) =>
{
if (e.Cancelled)
{
tcs.SetCanceled();
}
else if (e.Error != null)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(e.Result);
}
};
webService.GetPointAsync(nationalCode);
return tcs.Task;
}
...
using (PointWebService service = new PointWebService())
{
long point = await service.GetPointAsyncTask(123).ConfigureAwait(false);
}
Avoiding races when aggregating results
With regards to aggregating parallel results, your TAP loop code is almost right, but you need to avoid mutating shared state inside your Task bodies as they will likely execute in parallel. Shared state being Result in your case - which is some kind of collection. If this collection is not thread-safe (i.e. if it's a simple List<long>), then you have a race condition and you may get exceptions and/or dropped results on Add (I'm assuming AddRange in your code was a typo, but if not - the above still applies).
A simple async-friendly rewrite that fixes your race would look like this:
List<Task<long>> tasks = new List<Task<long>>();
foreach (BaseClass item in Clients) {
tasks.Add(item.GetPointAsync(MasterLogId, mobileNumber));
}
long[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
If you decide to be lazy and stick with the Task.Run solution for now, the corrected version will look like this:
List<Task<long>> tasks = new List<Task<long>>();
foreach (BaseClass item in Clients)
{
Task<long> dodgyThreadPoolTask = Task.Run(
() => item.GetPoint(MasterLogId, mobileNumber)
);
tasks.Add(dodgyThreadPoolTask);
}
long[] results = await Task.WhenAll(tasks).ConfigureAwait(false);
You can create an async version of the GetPoint:
public abstract class BaseClass
{ // all same attributes and methods
public abstract long GetPoint(int nationalCode);
public async Task<long> GetPointAsync(int nationalCode)
{
return await GetPoint(nationalCode);
}
}
Then, collect the tasks for each client call. After that, execute all tasks using Task.WhenAll. This will execute them all in parallell. Also, as pointed out by Kirill, you can await the results of each task:
var tasks = Clients.Select(x => x.GetPointAsync(nationalCode));
long[] results = await Task.WhenAll(tasks);
If you do not want to make the aggregating method async, you can collect the results by calling .Result instead of awaiting, like so:
long[] results = Task.WhenAll(tasks).Result;
I am trying to use async, await and task to implement one of an asynchronous requirement in my web application. I have below code in my controller class. What I want is that after the flow reaches to printing "controller 1", the system starts the business method on a separate thread and without waiting for the response system should reach to print statement in controller and print "controller 2". But when I am executing the below code I am getting output pattern as this-
controller 1
PlandesignBS
controller 2
Whereas I am expecting this-
controller 1
controller 2 (Flow should reach here immediately rather than waiting
for business methods to get executed First)
Contoller Class Code-
public class PlanDetailsController : Controller
{
[HttpPost]
public async Task<ActionResult> Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
//calls business method to generate
quoteId = await Task.Run(() => _planDesignBS.GenerateBS(planDetailsVM));
System.Diagnostics.Debug.WriteLine("controller 2");
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
}
Business Method Code-
public int GenerateBS(PandetailsDTO plandetails)
{
System.Diagnostics.Debug.WriteLine("PlandesignBS");
//STEP 1-> call to dataLogic Layer to use Entity Framework
// STEP 2-> call to a method (this method is part of dll used
//in our project and we don't have any control on it)
return quoteId
}
EDIT: The reason I am trying to do this is that I want to use few http Posts requests from my client side. Suppose I call the Generate action method first from my client side and then don't want to wait for the response of it and at the same time want to invoke another http post.
EDIT: Including EF code where I am getting execption when I am trying to follow few solutions.This method will be called from my GenerateBS method. I am getting exception on this line inside getSICCode method-
DbContext.Database.ExecuteSqlCommand("spGET_SICCode #industryClasifID,#industrySubClasifID,#SICCode OUTPUT", industryClasifID, industrySubClasifID, SICCode);
EF Code-
public class PlanDesignRepository : Repository<myobject>, IPlanDesignRepository
{
private IDbSet<myobject> _dbSet;
private DbContext _dbContext;
private IDbSet<myobject> DbSet
{
get
{
if (_dbSet == null)
{
_dbSet = base.UnitOfWork.Context.Set<myobject>();
}
return _dbSet;
}
}
private DbContext DbContext
{
get
{
if (_dbContext == null)
{
_dbContext = base.UnitOfWork.Context;
}
return _dbContext;
}
}
public string GetSICCode(IndustryClassficDO industryClassficDO)
{
SqlParameter industryClasifID = new SqlParameter("industryClasifID", SqlDbType.Int);
industryClasifID.Value = industryClassficDO.IndustryClassificationId;
SqlParameter industrySubClasifID = new SqlParameter("industrySubClasifID", SqlDbType.Int);
industrySubClasifID.Value = industryClassficDO.IndustrySubClassificationId;
SqlParameter SICCode = new SqlParameter("SICCode", SqlDbType.VarChar, 10);
SICCode.Direction = ParameterDirection.Output;
DbContext.Database.ExecuteSqlCommand("spGET_SICCode #industryClasifID,#industrySubClasifID,#SICCode OUTPUT", industryClasifID, industrySubClasifID, SICCode);
return (string)(SICCode.Value);
}
}
EDIT: I have few http Post calls as shown below-
AngularJS code for AJAX calls:
$http({
url: key_Url_Generate,
method: Post,
params: $scope.PlanDetails
}).then(function (result) {
//Notify user for success or failure
}
The usage of await means that you are waiting for the task to complete before continuing the code. If you want it to execute simultaneously with the other code you should change it like this
public class PlanDetailsController : Controller
{
[HttpPost]
public async Task<ActionResult> Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
//calls business method to generate
var task = Task.Run(() => _planDesignBS.GenerateBS(planDetailsVM));
System.Diagnostics.Debug.WriteLine("controller 2");
var quoteId = await task;
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
}
However I wouldn't recommend this as it serves no purpose and can degrade performance via starving the ASP.NET thread pool of threads. Why do you want to do this anyway?
This line:
quoteId = await Task.Run(() => _planDesignBS.GenerateBS(planDetailsVM));
asynchronously waits for the call inside Task.Run to complete. That's why you're seeing "PlandesignBS" printed and only after that you see the call to controller 2.
If you want to issue a "fire and forget" style of execution, you actually don't want to wait at all.
You should definitely not use Task.Run inside ASP.NET at all, as it's dangerous. Instead, if you're on .NET 4.5.2 and above, you can use HostingEnvironment.QueueBackgroundWorkItem or if not, you can use BackgroundTaskManager by Stephan Cleary, which safely registers the background thread with the application pool, so your thread doesn't get terminated once a re-cycle is invoked:
[HttpPost]
public ActionResult Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
HostingEnvironment.QueueBackgroundWorkItem(ct => _planDesignBS.GenerateBS(planDetailsVM));
System.Diagnostics.Debug.WriteLine("controller 2");
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
As a side note - If you're calling Entity Framework, there's usually no need to involve extra threads. Version 6 and above exposes TAP async based API's which are Task returning which you can use at your disposal for doing these kind of IO based queries.
The problem is, that you simply cannot dispatch asynchronous code that fall out of the asp.net request pipeline per se.
The async feature in asp.net MVC only improves the internal handling of threads inside the IIS process. It does NOT enable you to finish and close the response to the client, before all execution is completed.
If you want to do a real "fire-and-forget" solution, you need more than that.
I recently had the requirement that mails be sent asynchronously after a form in a web application has been submit.
The only way I found to solve this problem was to use hangfire:
http://hangfire.io/
Try this:
public class PlanDetailsController : Controller
{
[HttpPost]
public async Task<ActionResult> Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
//calls business method to generate
var quoteIdTask = GenerateAsyncBs();
System.Diagnostics.Debug.WriteLine("controller 2");
int id = await quoteIdTask;
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
}
private async Task<int> GenerateBsAsync()
{
//do your planDetails logic here.
}
I have an ASP.NET MVC 4 program and I wrote the following code where I wanted to make the Results() method async:
public async Task<ActionResult> Results()
{
var result1 = SomeMethodAsync(1);
var result2 = SomeMethodAsync(2);
var result3 = SomeMethodAsync(3);
await Task.WhenAll(result1, result2, result3);
ViewBag.Result1 = result1;
ViewBag.Result2 = result2;
ViewBag.Result3 = result3;
return View()
}
public async Task<int> SomeMethodAsync(int i)
{
//do some logic
//make db call
return await Task.Run( () => DbCall(i));
}
public int DbCall(i)
{
//make db call
return valueFromDb;
}
Since I am not using Entityframework 6 I cannot make the DbCall() async. I was reading that its not a good idea to use Task.Run in ASP.NET projects since Task.Run will borrow a thread from the ASP.Net thread pool and therefore can cause queuing issues with large number of requests (as there will be lower number of available threads for processing incoming requests).
1) How can I make my method async without using Task.Run?
2) Is it better to make the method synchronous than using Task.Run ?
2) Is it better to make the method synchronous than using Task.Run ?
Yes.
In this case, since you don't have naturally-asynchronous APIs available from EF6, the next best solution is to just be synchronous.
Note that even if you did have asynchronous APIs, a single DbContext can only handle one operation at a time anyway. You'd have to create multiple contexts in order to run multiple simultaneous queries, and that can get complex.
In my data access layer I'm attempting to create methods with return types of Task.
I cannot get the return type from the entity framework to return Task<List<MYtype>>
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
}
Is the only way to make this run correctly is to format the code like so:
public async static Task<List<ILeaf>> GetLeafs(int doorID)
{
return await Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
The reason I was asking is because I would like to give the option to run async, or am I not understanding this correctly?
If I can just return a Task then on the calling end I could give the option to await if I wanted to run async, but if i wanted to run synchronously I would just call the method as normal.
If I'm returning a Task do I always have to include the async keyword in the method signature?
Am I thinking about this the wrong way? If I've got a return type of Task then the method has the option of being called async or synchronously?
But, if I have async and Task in the method signature then the method runs async no matter what?
Thanks!
So to answer the literal question asked, you can just do this:
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
return Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
That said, note that this isn't a particularly useful method. The idea of leveraging asynchronous programming is that you don't want to have a thread pool thread sitting there doing nothing but waiting on this IO operation. Ideally you'd leverage IO that is inherently asynchronous in nature; a method that itself naturally returns a task.
You aren't really providing value to consumers of your code by wrapping the blocking IO in a call to Task.Run. If they need that operation to be run in a background thread they can do so on their own, and then they'll know more precisely that it's not a naively asynchronous operation.
See Should I expose asynchronous wrappers for synchronous methods? for more information on the subject.
public static async Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
var result = db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
return await Task.FromResult(result);
}
}
lets assume that we have two operation contracts defined on wcf service, sync and async one. There are two samples:
public void SubscribeSingle(int userId)
{
var clientId = this.OperationContext.GetClientId();
var session = this.OperationContext.GetPollingDuplexSession();
if (string.IsNullOrEmpty(clientId) || session == null || userId == 0)
{
return;
}
this.InternalSubscribeSingle(userId, clientId, session.SessionId);
}
and
public IAsyncResult BeginUnsubscribeSingle(int userId, AsyncCallback callback, object state)
{
var clientId = this.OperationContext.GetClientId();
var session = this.OperationContext.GetPollingDuplexSession();
if (string.IsNullOrEmpty(clientId) || session == null)
{
return null;
}
var asyncResult = new VoidAsyncResult(callback, state);
Task.Factory.StartNew(() =>
{
try
{
this.InternalUnsubscribeSingle(userId, clientId);
asyncResult.SetAsCompleted(false);
}
catch (Exception ex)
{
asyncResult.SetAsCompleted(ex, false);
}
});
return asyncResult;
}
public void EndUnsubscribeSingle(IAsyncResult result)
{
var response = result as VoidAsyncResult;
if (response != null)
{
response.EndInvoke();
}
}
As I understand WCF service also has a thread pool inside, so each I/O operation may be finished on another thread. As well as starting new thread using Task.Factory.StartNew
Is there any difference between sync and async server calls from performance point of view, if database access is made through EntityFramework and though blocking?
There's no value to the async method here, since you're still calling a sync method that will block a thread at some point. The async only earns something when it goes all the way down to a non-blocking operation like disk/network IO. Just write the simple sync version and let WCF do its thing.
This two versions are the same. But in general asynchronous version could be much more efficient than calling synchronous version asynchronously.
For example, if we're using FileStream or TcpListerner, than calling asynchronous version of BeginRead and BeginAcceptSocket whould be much more efficient than calling appropriate synchronous versions like Read and AcceptSocket. Thats because those asynchronous functions using underlying asyncrhonous API provided by operating system.
For example, TcpListener could use IO completion ports for interacting with another tcp client and with this approach you can easily interact with 10K of clients asyncrhnously without delays . FileSteam could use Overlapped structure for underlying asynchronous operations that would consume less resources than synchronous version.
So if your services asynchronous method could as well use some asynchronous underlying API your async version could be much more efficient than simple async version that calls sync version in different thread.