C# Tasks Calling same instance - c#

I'm fairly new to tasks and want to implement them on my application. What I want is to do an ajax request on my client side when the page loads, to a function that calls all the catalogs that I need and returns a JSON of all the objects to my client. This function on the server side is the one I created to have multiple tasks. So I have the following questions regarding this:
Is it a good practice to load all catalogs needed for that page and return a JSON object?
Does it actually work as multi thread if the tasks call the same instance of a class? Or is it better to create the instance inside each task?
public JsonResult GetCatalogs()
{
JsonResult jSonResult = new JsonResult();
try
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
Task<IList<CustomObject1>> task1 = Task.Factory.StartNew(() =>
{
IList<CustomObject1> resultList1 = catalogsRepository.getFirstCatalog();
return resultList1;
});
Task<IList<CustomObject2>> task2 = Task.Factory.StartNew(() =>
{
IList<CustomObject2> resultList2 = catalogsRepository.getSecondCatalog();
return resultList2;
});
Task<IList<CustomObject3>> task3 = Task.Factory.StartNew(() =>
{
IList<CustomObject3> resultList3 = catalogsRepository.getThirdCatalog();
return resultList3;
});
jSonResult = Json(new
{
result1 = task1.Result,
learningMaterialTypeList = task2.Result,
contentAssociatedList = task13.Result
});
jSonResult.MaxJsonLength = int.MaxValue;
jSonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
catch (Exception ex)
{
log.Error(ex);
return Json(new Error { messageCode = 1, message = ex.Message });
}
return jSonResult;
}
Or is it better to create the instance inside each task?
public JsonResult GetCatalogs()
{
JsonResult jSonResult = new JsonResult();
try
{
Task<IList<CustomObject1>> task1 = Task.Factory.StartNew(() =>
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
IList<CustomObject1> resultList1 = catalogsRepository.getFirstCatalog();
return resultList1;
});
Task<IList<CustomObject2>> task2 = Task.Factory.StartNew(() =>
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
IList<CustomObject2> resultList2 = catalogsRepository.getSecondCatalog();
return resultList2;
});
Task<IList<CustomObject3>> task3 = Task.Factory.StartNew(() =>
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
IList<CustomObject3> resultList3 = catalogsRepository.getThirdCatalog();
return resultList3;
});
jSonResult = Json(new
{
result1 = task1.Result,
learningMaterialTypeList = task2.Result,
contentAssociatedList = task13.Result
});
jSonResult.MaxJsonLength = int.MaxValue;
jSonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
catch (Exception ex)
{
log.Error(ex);
return Json(new Error { messageCode = 1, message = ex.Message });
}
return jSonResult;
}
I'm using MVC .NET 4.0 with jQuery, Thank you in advance.

Your action method should be async:
public async Task<JsonResult> GetCatalogs()
Once your method is async, everything else is much easier. You can do away with those Task.Run() calls and just call the methods normally (as long as they as async) and await them. It may make sense to make those lambdas into separate, async methods (or even C#7 local methods):
protected async Task<IList<CustomObject1>> GetResults1()
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
var resultList1 = catalogsRepository.getFirstCatalog();
return await resultList1.ToListAsync();
});
Important: To get results you should use await. Never use Result in an async ASP.NET environment because it will deadlock.
var jsonResult = Json(new
{
result1 = await task1,
learningMaterialTypeList = await task2,
contentAssociatedList = await task3
});
As for your questions:
Is it a good practice to load all catalogs needed for that page and return a JSON object?
There is no rule against it. It's a design decision for you to make. The pro is fewer round trips, the con is coupling all those things together in a public interface makes the architecture a bit more brittle.
Does it actually work as multi thread if the tasks call the same instance of a class? Or is it better to create the instance inside each task?
In true multithreading, it is better in general to work on separate instances so that each thread can have its own independent memory cache. That being said, async is not the same as multithreading, and in fact in ASP.NET you're guaranteed that no two of your tasks will be executing simultaneously (unless you do something special to make that happen). Instead you get one thread at a time. The thread might change, and your async code will jump around await points, but only one piece of code gets to run at once, by design.

1.I think that by returning a JSON object you mean an action which returns a JsonObject and is called by ajax from the client side. You can do this in most places of your app but keep in mind that you can lose a lot of benefits from pure MVC. The second thing is jQuery and Ajax are a bit hard to maintain and in case of complex views you will have to write a lot of code, very often hard to test.
A very common concept in asp.net MVC is returning ViewModels/Models via GET methods and then sending data from forms with the use of asp.net helpers back to the controllers. If you use data annotation attributes and jQuery unobtrusive library you can build really nice validation, very easy to maintain on the backend and on the client side. The client-side validation will be generated just for FREE based on the .net attributes which shorten your time in development. With Ajax calls, you can do similar but the code will be more clunky.
2 and 3.Your controller should contain as less business logic as possible and all the logic should be moved to other layers, services etc. Your actual code is over too complicated.
Try to use interfaces and IOC. Avoid creating instances of objects like you do now in the controller. It’s hard to write tests for such a class.
I think something like this would be better:
private readonly ICatalogService _catalogService;
// Dependency injection thanks to Inversion of Control
public BlahController(ICatalogService catalogService){
_catalogService=catalogService;
}
public async JsonResult GetCatalogs(params..){
return await catalogService.getCatalogs(params..); //or catalogRepository
}
So you can move all the business logic out of the controller to some separate class.

Related

Return partial result from async method

I have a class that calls a web service to retrieve data asynchronously. To improve performance I implemented a client-side cache which checks if the requested data is available locally. The class returns all data that is stored in the cache and calls the web service to fetch the remaining data.
Can I return the cached data to the caller and then proceed with the web call, or do I have to make the call and return the complete set of data?
In a synchronous environment, I could use yield return, by with Tasks and async/await yield is not possible.
How can I solve this problem?
You can use Observable
// in your UI
var result = new ObservableCollection<Data>(); // this is your list to bind to UI
IsBusy = true; // indicate that work is done
yourDataSource.GetData(2000).Subscribe(batch =>
{
foreach (var d in batch)
{
result.Add(d);
}
},
exception =>
{
Log.Error(exception);
IsBusy = false;
},
() =>
{
// this means done
IsBusy = false;
}
)
// or you can await the whole thing
try
{
IsBusy = true;
await yourDataSource.GetData(5).Do(batch =>
{
foreach (var d in batch)
{
result.Add(d);
}
});
}
finally
{
IsBusy = false;
}
Your data source:
IObservable<IList<Data>> GetData(int args)
{
var result = new Subject<IList<Data>>();
Task.Run(async () =>
{
try
{
var formCache = await GetFromCache(args);
result.OnNext(fromCache);
while (moreBatches)
{
result.OnNext(GetNextBatch(args));
}
result.OnCompleted();
}
catch (Exception e)
{
result.OnError(e);
}
});
return result;
}
If you are using WPF, Xamarin.Forms or UWP, I strongly recommend ReactiveCommand which can return observable and do the whole IsBusy thing for you.
None of the suggestions fit my problem perfectly, but a combination of them did.
At first, I created a pipeline with the TPL DataFlow library to fetch the data from my sources. The results were then posted into a BufferBlock<T> at the end, that was exposed to the end user as an IObservable<T>. This had the added benefit that I now can easily query related data via additional blocks.

Asynchrony on ASP MVC

I would want to increase the performance of my web application for future scalability issues,
One scenario that i think of is that, if i need a list that needs to be filtered from the database.
Here is the rough draft that i made:
public IEnumerable<test> getL(IEnumerable<test> filter)
{
//do some filtering from the list then return it
return filter;
}
public async Task<ActionResult> Index()
{
context con = new context();
//do more stuff of stuff
IEnumerable<test> get = await Task.Run(() => { return getL(con.dep.ToList()); });
return View(get);
}
I am kinda new with C#'s asynchrony so i am kinda wondering if i am doing this correct. Did i start the asynchronous call properly?
On ASP.NET, you should avoid Task.Run. This is because Task.Run will free up the current thread by using another thread. So you incur the penalty of an additional context switch for no reason. This code will decrease scalability and performance, not increase it.
Instead, use await for I/O-based tasks. For example, getting the data from the database:
public async Task<ActionResult> Index()
{
context con = new context();
var list = await con.dep.ToListAsync();
IEnumerable<test> get = getL(list);
return View(get);
}

Async calls never returns in Asp.Net MVC

I am return a list which basically calls the two async operations:
[HttpPost]
public ActionResult List(DataSourceRequest command, ProductListModel model)
{
var categories = _productService.GetAllProducts(model.SearchProductName,
command.Page - 1, command.PageSize);
var gridModel = new DataSourceResult
{
Data = categories.Select(async x =>
{
var productModel = x.ToModel();
var manufacturer = await _manufacturerService.GetManufacturerById(x.ManufacturerId);
var category = await _categoryService.GetCategoryById(x.CategoryId);
productModel.Category = category.Name;
productModel.Manufacturer = manufacturer.Name;
return productModel;
}),
Total = categories.TotalCount
};
return Json(gridModel);
}
It is an ajax request (from client side) but on front-end it never returns. Is there any a deadlock ?
Building up my answer from several comments and #usr's answer:
Data in the code above is actually IEnumerable<Task<ProductModel>>, not IEnumerable<ProductModel>. This is because the lambda passed to Select is async.
Most likely, the JSON serializer is going over this structure and enumerating the properties on the Task<ProductModel> instances, including Result.
I explain on my blog why accessing Result will cause a deadlock in this case. In a nutshell, it's because the async lambda will attempt to resume execution on the ASP.NET request context after its await. However, the ASP.NET request context is blocked on the call to Result, locking a thread inside that request context until the Task<T> completes. Since the async lambda cannot resume, it cannot complete that task. So both things are waiting for each other, and you get a classic deadlock.
There are some suggestions to use await Task.WhenAll, which I would normally agree with. However, in this case you're using Entity Framework and got this error:
A second operation started on this context before a previous asynchronous operation completed.
This is because EF cannot perform multiple asynchronous calls concurrently within the same db context. There are a couple ways around this; one is to use multiple db contexts (essentially multiple connections) to do the calls concurrently. IMO a simpler way is to make the asynchronous calls sequentially instead of concurrently:
[HttpPost]
public async Task<ActionResult> List(DataSourceRequest command, ProductListModel model)
{
var categories = _productService.GetAllProducts(model.SearchProductName,
command.Page - 1, command.PageSize);
var data = new List<ProductModel>();
foreach (var x in categories)
{
var productModel = x.ToModel();
var manufacturer = await _manufacturerService.GetManufacturerById(x.ManufacturerId);
var category = await _categoryService.GetCategoryById(x.CategoryId);
productModel.Category = category.Name;
productModel.Manufacturer = manufacturer.Name;
data.Add(productModel);
}
var gridModel = new DataSourceResult
{
Data = data,
Total = categories.TotalCount
};
return Json(gridModel);
}
The way to debug is is to pause the debugger during the hang. There you will find that some serializer is blocking on Task.Result or similar.
You fill the Data property with a IEnumerable<Task>. The serializer probably calls Result at some point and that's the classic ASP.NET deadlock. You probably should wrap the Select call with await Task.WhenAll(x.Select(...)).
And even then it might be unsafe to concurrently run those lambdas.

Deadlock using TryUpdateModelAsync() in MVC 6 ASP.NET 5 beta 4

After upgrading from Beta3 to Beta4, I'm now getting what looks like a deadlock(site hanges indefinitely) when calling TryUpdateModelAsync
public ActionResult Edit(ContactModel contactModel)
{
var contact = db.Contact.Find(contactModel.ContactId);
if (ModelState.IsValid)
{
TryUpdateModelAsync(contact);
var result = db.SaveChanges(() => { });
if (result.Success)
return RedirectToAction("Details", "Client", new { id = contact.ClientId });
}
return View(contactModel);
}
original code above was ported from MVC 5 so I was just trying to run synchronously. I get the same result after converting the controller method to Async like this
public async System.Threading.Tasks.Task<ActionResult> Edit(ContactModel contactModel)
{
var contact = db.Contact.Find(contactModel.ContactId);
if (ModelState.IsValid)
{
var updateResult = await TryUpdateModelAsync(contact);
var result = db.SaveChanges(() => { });
if (result.Success)
return RedirectToAction("Details", "Client", new { id = contact.ClientId });
}
return View(contactModel);
}
I took a quick look through the sample projects and I couldn't find any usage of this method, anyone have a working example? or know why this is happening?
Here is a sample of usage of try update model async (in MVC test code), Note this is from the dev branch. You might have to switch to whatever branch you are on.
https://github.com/aspnet/Mvc/blob/dev/test/WebSites/ModelBindingWebSite/Controllers/TryUpdateModelController.cs
Your first sample is bad because updating the model async without an await will create a task, but continue over it to the next method.
To figure out why you have a deadlock you want to break into the deadlock and see where is the stack at, does it have to do with tryupdatemodel at all?
If you can create a simple repro in a small project please file a bug in https://github.com/aspnet/mvc/issues

Using asynchronous tasks to call synchronous WCF service

I have a WCF service, called by a service client. I'd like to use the async / await constructs to wrap the call to this; however, the service and service client are .NET3.5. My solution to this is as follows:
private async Task<ObservableCollection<MyEntity>> LoadData(ParamData param)
{
ServiceClient svc = new ServiceClient();
int results = 0;
// Set-up parameters
myParams = BuildParams(param);
// Call a count function to see how much data we're talking about
// This call should be relatively quick
var counter = Task.Factory.StartNew(() =>
{
results = svc.GetResultCount(myParams);
}).ContinueWith((task) =>
{
if (results <= 10000 ||
(MessageBox.Show("More than 10000 results, still retrieve data?"), MessageBoxButton.YesNo) == MessageBoxResult .Yes))
{
return svc.Search(myParams);
}
});
}
I get the compile error:
Since 'System.Action<System.Threading.Tasks.Task>' returns void, a return keyword must not be followed by an object expression
So, my question is, is it possible to run a synchronous method in this fashion and, if so, what am I doing wrong? My objective is that the method can be called like so:
var data = await LoadData(params);
When you add the Service Reference there is an option to generate async versions of the operations.
This is the (older) APM pattern (IAsyncResult, BeginMethod, EndMethod). You can hook this into async/wait with FromAsync :
var task = Task.Factory.FromAsync(BeginGetResultCount, EndGetResultCount, myParams);
When you have many calls this is better, it doesn't waste so many threads to wait for I/O.
In your question, you first state that your client is on .NET 3.5, but then you proceed with an async method and tagged your question .NET 4.5. So I'm assuming that you are actually running on .NET 4.5.
In that case, you can just tell svcutil to create task-based asynchronous APIs (in VS2012, it should do this by default), and then call them like this:
private async Task<ObservableCollection<MyEntity>> LoadData(ParamData param)
{
ServiceClient svc = new ServiceClient();
// Set-up parameters
myParams = BuildParams(param);
// Call a count function to see how much data we're talking about
// This call should be relatively quick
var results = await svc.GetResultCountAsync(myParams);
if (results <= 10000 ||
(MessageBox.Show("More than 10000 results, still retrieve data?"), MessageBoxButton.YesNo) == MessageBoxResult .Yes))
return await svc.Search(myParams);
}
If you are actually on .NET 4.0, then Henk has the correct answer. In that case, you may find my async WCF blog post helpful.
Okay - I've solved this. The return statement returns from the task, not the function; which is why it was complaining.
The correct code looks like this:
private async Task<ObservableCollection<MyEntity>> LoadData(ParamData param)
{
ServiceClient svc = new ServiceClient();
int results = 0;
// Set-up parameters
myParams = BuildParams(param);
// Call a count function to see how much data we're talking about
// This call should be relatively quick
var counter = Task.Factory.StartNew(() =>
{
results = svc.GetResultCount(myParams);
});
var returnTask = counter.ContinueWith((task) =>
{
if (results <= 10000 ||
(MessageBox.Show("More than 10000 results, still retrieve data?"), MessageBoxButton.YesNo) == MessageBoxResult .Yes))
{
return svc.Search(myParams);
}
});
return returnTask.Result;
}

Categories