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
Related
I am trying to put my asp.net app to production. But when I run the application in Production, a certain route doesnt work that well. It says that post.Author == null. When I run the application in debug, it runs well, even without breakpoints.
I tried the application in a release build or just with the start button in rider, both doesnt work.
Thats the route I am trying to debug. I have the problem with some other routes, too.
[HttpGet("public/{orgId}")]
public async Task<ActionResult<List<PostModel>>> GetAllPublicPostsByOrgId(string orgId)
{
List<PostModel> posts = await _postRepository.GetAllPostsByOrgId(orgId);
posts.ForEach(async post =>
{
UserModel author = await _userRepository.GetUserById(post.AuthorId);
UserModel saveAuthor = new UserModel();
saveAuthor.FirstName = author.FirstName;
saveAuthor.LastName = author.LastName;
post.Author = saveAuthor;
});
return Ok(from post in posts where post.Published select post);
}
The author should be null, it should be an object with the attributes.
Edit: I tried to use [MethodImpl(MethodImplOptions.NoOptimization)] on that router. That didnt work, too.
The problem is that the lambda you use in the ForEach is basically a async void method which means it's fire and forget. So your code is going to get to the return before it finishes setting all the Author properties. Instead you should use a normal foreach(var post in posts) so the method will wait for all the Author properties to be set. Note the reason this likely only fails in release is because this is a race condition and debug probably slows stuff down just enough for it to not happen.
Alternatively you could make the code into a method and instead execute it in parallel and then wait for all the tasks to complete before returning.
[HttpGet("public/{orgId}")]
public async Task<ActionResult<List<PostModel>>> GetAllPublicPostsByOrgId(string orgId)
{
List<PostModel> posts = await _postRepository.GetAllPostsByOrgId(orgId);
var authorSetTasks = new List<Task>();
foreach(var post in posts)
{
authorSetTasks.Add(SetAuthor(post));
}
await Task.WhenAll(authorSetTasks);
return Ok(from post in posts where post.Published select post);
}
private async Task SetAuthor(PostModel post)
{
UserModel author = await _userRepository.GetUserById(post.AuthorId);
UserModel saveAuthor = new UserModel();
saveAuthor.FirstName = author.FirstName;
saveAuthor.LastName = author.LastName;
post.Author = saveAuthor;
}
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.
from what I understand the code below should eventually retrieve the string classification while running other code.
[HttpPost]
public async Task<ActionResult> CreatePropertyAsync(Property property)
{
string classification = GetClassification(property);
// GetClassification() runs a complex calculation but we don't need
// the result right away so the code can do other things here related to property
// ... code removed for brevity
property.ClassificationCode = await classification;
// all other code has been completed and we now need the classification
db.Properties.Add(property);
db.SaveChanges();
return RedirectToAction("Details", new { id = property.UPRN });
}
public string GetClassification(Property property)
{
// do complex calculation
return classification;
}
This should work the same way as in the below code from Matthew Jones' article
public async Task<string> GetNameAndContent()
{
var nameTask = GetLongRunningName(); //This method is asynchronous
var content = GetContent(); //This method is synchronous
var name = await nameTask;
return name + ": " + content;
}
However I get an error on await classification: 'string' does not contain a definition for 'GetAwaiter'
I'm unsure why this is happening.
Additionally, according to MSDN docs for expensive calculations I should instead be using:
property.ClassificationCode = await Task.Run(() => GetClassification(property));
Is this actually achieving what I want or is this just running synchronously anyway?
Thanks in advance for help.
string classification = GetClassification(property);
this is regular synchronous code; it will do nothing until classification is assigned. It sounds like what you want is:
Task<string> classification = GetClassificationAsync(property);
where GetClassificationAsync does something genuinely async in the middle and eventually populates a Task<string>. Note that if GetClassificationAsync still works synchronously, the code will all continue to be synchronous. In particular, if you find yourself using Task.FromResult : you probably aren't doing anything async.
To have the same as in the code from Matthew Jones you have to change your code to
[HttpPost]
public async Task<ActionResult> CreatePropertyAsync(Property property)
{
Task<string> classificationTask = Task.Run( () => GetClassification(property) );
// GetClassification() runs a complex calculation but we don't need
// the result right away so the code can do other things here related to property
// ... code removed for brevity
property.ClassificationCode = await classificationTask;
// all other code has been completed and we now need the classification
db.Properties.Add(property);
db.SaveChanges();
return RedirectToAction("Details", new { id = property.UPRN });
}
public string GetClassification(Property property)
{
// do complex calculation
return classification;
}
But read https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html why not with ASP.NET
Async .net web api sometime does not return any result with angularjs call.
May be due to some problem with my asynchronous code handling at UI end.Can anyone help to fix this up?
Below is my C# web api code :-
[HttpGet]
[Route("GetTotalUsersData")]
public async Task<IHttpActionResult> GetTotalUsersData(int schoolID)
{
var result = await _analytics.GetTotalUsersData(schoolID);
return Ok(result);
}
It's part of _analytics
public async Task<RegisteredUsers> GetTotalUsersData(int schoolID)
{
try
{
var users = await _unitOfWork.Repository<User>().GetAllAsync(s => s.School_ID == schoolID);
return new RegisteredUsers
{
TotalRegisteredUser = users.Where(s => s.UserRole_ID != (byte?)StaticValues.RoleType.SuperAdmin).Count(),
TotalStudents = users.Where(s => s.UserRole_ID == (byte?)StaticValues.RoleType.STUDENT).Count(),
TotalGuardian = users.Where(s => s.UserRole_ID == (byte?)StaticValues.RoleType.GUARDIAN).Count(),
TotalStaff = users.Where(s => s.UserRole_ID == (byte?)StaticValues.RoleType.STAFF|| s.UserRole_ID == (byte?)StaticValues.RoleType.Account || s.UserRole_ID == (byte?)StaticValues.RoleType.Admin).Count(),
};
}
catch (Exception ex) { logger.Log(ex); }
return null;
}
Angular Code to call above api
var _totalUsers = function () {
var deferred = $q.defer();
$http.get(serviceBase + 'api/Dashbord/GetTotalUsersData', { params: { schoolId: authData().schoolId } }).success(function (response) {
deferred.resolve(response);
}).error(function (err, status) {
deferred.reject(err);
});
return deferred.promise;
};
dashboardServiceFactory.totalUsers = _totalUsers;
return dashboardServiceFactory;
}]);
Async method returns back to it's caller and doesn't come again to get back awaitable results.
sometime it's works fine but in some cases it skips my c# code without saying anything.
Logs have the following error
{"A second operation started on this context before a previous
asynchronous operation completed. Use 'await' to ensure that any
asynchronous operations have completed before calling another method
on this context. Any instance members are not guaranteed to be thread
safe."}
your problem should be the return null in c#, there should be an exception in the database check your log file. Also you could try a rest plugin for your browser and use that plugin to test the back end (one of many Restlet Client - DHC)
Try defensive coding. if no result then the action should return not found.
[HttpGet]
[Route("GetTotalUsersData")]
public async Task<IHttpActionResult> GetTotalUsersData(int schoolID) {
var result = await _analytics.GetTotalUsersData(schoolID);
if(result != null)
return Ok(result);
return NotFound();
}
The exception message you posted is one that EF gives if you query the same context more than once concurrently.
So, it sounds like _unitOfWork.Repository<User>() is returning a context that is shared between multiple controller instances, which is a no-no. EF contexts cannot be singletons.
On a side note, you might want to move your Count operations into the EF query itself. As it currently stands, the EF query is retrieving everything about all the users in a school - loading all of that data from the DB into memory - and then just returning some counts.
I have an online database from Parse.com. There's a table "Vakantie", that contains 3 objects, so the table data isn't big.
I'm trying to get all the objects from that table so I can display them through my VakantieController in a View.
Parse has an own documentation where sample code is provided. I copied their sample code and edited it so that it fits for my website.
The сode:
VakantieController:
public ActionResult Index()
{
var vakantiesTask = vakantieRepository.FindAll();
IEnumerable<Vakantie> vakanties = vakantiesTask.Result;
return View(vakanties);
}
VakantieRepository (class that contains code to retrieve from en write to the database):
public async Task<IList<Vakantie>> FindAll()
{
var query = from v in ParseObject.GetQuery("Vakantie")
orderby v.Get<string>("titel") ascending
select v;
IEnumerable<ParseObject> objects = await query.FindAsync();
IList<Vakantie> vakanties = new Vakantie[] { };
foreach (ParseObject vakantieObject in objects)
{
Vakantie vakantie = GetVakantie(vakantieObject);
vakanties.Add(vakantie);
}
return vakanties;
}
The method `GetVakantie(vakantieObject() is a method I wrote that converts the ParseObject I get from the query result to a Vakantie object from my domain.
When I run this code, I get until the line:
IEnumerable<ParseObject> objects = await query.FindAsync();
and when Visual Studio actually performs this command, my website just keeps loading and loading. I never get over this line to the next one. It is stuck right there.
Does anyone has a solution for this?
You're running into a classic deadlock scenario that I describe in full on my blog and an MSDN article. In summary, await will capture the current "context" and use that to resume the async method. Furthermore, the ASP.NET context will only allow one thread at a time. So when a request thread is blocked (on Task<T>.Result), the await inside of FindAll cannot resume the async method on that context, and you end up with a deadlock.
To correct it, use async "all the way"; i.e., don't use Task<T>.Result:
public async Task<ActionResult> Index()
{
var vakantiesTask = vakantieRepository.FindAll();
IEnumerable vakanties = await vakantiesTask;
return View(vakanties);
}