Dreamfactory - MVC PartialView Issue - asp.net-mvc

I got to open a pop-up which will display the list of Customers. I'm Using DreamFactory for all CRUD operations. But DreamFactory has got all operation as async operation and while loading partial view it gives error:
HttpServerUtility.Execute blocked while waiting for an asynchronous operation to complete.
I'm using below code to load the partial view -
#Html.Action("GetAddressListForPartial", "Customer", new { CustomerID = Model.CustomerID })
This is my controller method
public async Task ActionResult CustomerList()
{
Models.Customers oCustomers = await new DataAccessLayer.DataAccess().GetCustomerList(databaseApi);
return View("CustomerList", oCustomers);
}
Please let me know if there any workaround to handle this situation.
Thanks

Your issue is not just related to DreamFactory. With ASP.Net MVC 5 and earlier, child actions can't be executed when your action method use async.
Child action must run synchronously. If you want your code to work you must remove async keywork hence removing Task. At the end you must have this :
public ActionResult CustomerList()
{
Models.Customers oCustomers = new DataAccessLayer.DataAccess().GetCustomerList(databaseApi).Result;
return View("CustomerList", oCustomers);
}
With ASP.Net MVC 6, ViewComponent will allow child action to be executed asynchronously.

Related

Run method on a separate thread inside Action

Suppose I have an Action like below that I want to return the View asap and continue doing some work in the background thread.
public async Task<ActionResult> Index()
{
Debug.WriteLine("Inside Index");
var newCustomer = new Customer
{
Name = "Ibrahim"
};
Task.Run(() => SaveCustomer(newCustomer));
Debug.WriteLine("Exiting Index");
return View();
}
private async Task SaveCustomer(Customer NewCustomer)
{
Debug.WriteLine("Started Saving Customer");
await Task.Delay(2000);
Debug.WriteLine("Completed Saving Customer");
}
I do get the output as intended which is:
Inside Index
Exiting Index
Started Saving Customer
Completed Saving Customer
But what bothers me is that I get a warning that my Index action will run synchronously regardless and I should put an await but then the view is returned after SaveCustomer is completed and the purpose is defeated.
How am I doing this wrong? Any suggestion is appreciated.
But what bothers me is that I get a warning that my Index action will run synchronously
How am I doing this wrong?
Don't force asynchrony from the top down. Instead, start with naturally-asynchronous operations at the lowest level (e.g., EF6 database access), and allow the asynchrony grow from the lowest-level code upward.
Also, on ASP.NET, you should strongly avoid Task.Run.
Applying these two principles results in an Index method like this:
public async Task<ActionResult> Index()
{
Debug.WriteLine("Inside Index");
var newCustomer = new Customer
{
Name = "Ibrahim"
};
await SaveCustomer(newCustomer);
Debug.WriteLine("Exiting Index");
return View();
}
but then the view is returned after SaveCustomer is completed and the purpose is defeated.
Not at all. The purpose of asynchronous ASP.NET code is not to return early to the client. async and await do not change the HTTP protocol. await on the server side yields to the thread pool, not the client.
If you need to return early (and most people don't - they only think they "need" to), then you should use one of the established patterns for returning early (as I describe on my blog). Note that the only proper (i.e., fully reliable) solution entails setting up a reliable queue with an independent background process.
Your Index does not make use of any async feature at all. Why did you mark it async? You must be misunderstanding something, not sure what. Remove the async Task specification.
You get that compiler warning because there is nothing asynchronous in your Index() method. Your Task.Run(() => SaveCustomer(newCustomer)); line means Fire And Forget (non awaited task) - this is very different than asynchronous code. Index() is completely synchronous, while creating a "side Task" to execute sometime in the future. As the other answer mentioned - you could just as well remove the async mark from your method - it's not async.

how do i call webservice from MVC3 Razor Controller?

In my project I need to call a web service from a controller. I have already done the following, and it works.
Add the web reference for the web service to the project.
Call the service as follows:
Service Wservice=new Service();
Wservice.loginCompleted+=new Wservice_login_Completed;
WService.login_Async("username","Password");
Note: Whenever i call this service it throws an error that is
"An asynchronous operation cannot be started at this time.
Asynchronous operations may only be started within an asynchronous handler
or module or during certain events in the Page lifecycle. If this
exception occurred while executing a Page, ensure that the Page is marked
<%# Page Async="true" %>."
To overcome this issue I use
[Httppost]
public ActionResult login(logmodel model)
{
Task.Factory.StartNew(() =>
{
Wservice.loginCompleted+=new Wservice_login_Completed;
WService.login_Async("username","Password");
});
if(finalresult==true)
{
*** return View();
}
}
void Wservice_login_completed()
{
Here i got the output.
}
But the calling of Wservice_login_completed() function was after the View*** was returned,, so I'm not getting the result. How do I achieve "calling webservice from Controller".. Any ideas?
Finally i called the webservice from MVC Controller Successfully.
Note: Add ServiceReference instead of WebReference and avoid
"Task.Factory.StartNew(()=>);" Process.
[Httppost]
public ActionResult login(logmodel model)
{
Wservice.ServiceSoapClient _host = new Wservice.ServiceSoapClient("ServiceSoap");
var result_out = _host.login(uname, pwd, "test1", "test2", "test3", "test4");
}
Here "ServiceSoap" is an endpoint for our service.. you may got the endpoint to be presented in app.confiq or web.config files.
Happy Coding...!
get the following NuGet:
microsoft http client
(id = Microsoft.Net.Http)
Create a Web API Controller (webapi_Controller_Name)
Your Post function should be similar to the following function
Put this function in your Web Api Controller
[HttpPost]
public void PostForm(objUser ws_Obj)
{
// put you code here
}
Call your Web Service from you regular Controller as follows.
This is an Async call and will Web Service will return immediately.
//call the web service, Asynch
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("52323/");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.PostAsJsonAsync("//52323/api/webapi_Controller_Name/PostForm", objContact);
First, create a service reference by right clicking on the project name in the solution explorer, then hover over the "Add" option and click on "Service Reference..."
Second, paste your web service address in the "Address" field of the "Add Service Reference" page, be sure to add "?wsdl" to the end of your web service address or it won't work, and then press "Go". You will see the web service appear in the "Services" area. Click on the service to see the available services which will appear in the "Operations" section. Rename the service if you want, then press OK to create the service.
Finally, put the following code in your MVC Controller. Place the code in a Get or Post controller, it doesn't matter.
// Declare the Request object.
ServiceReference1.GetSurveyRequest myGSRq = new ServiceReference1.GetSurveyRequest();
// You can set the webservice parameters here like...
myGSRq.Address = getUserData[0].address;
myGSRq.City = getUserData[0].city;
myGSRq.State = getUserData[0].state;
// Now declare the Response object.
ServiceReference1.GetSurveyResponse myGSR = new ServiceReference1.GetSurveyResponse();
//And then use the following to process the request and response.
ServiceReference1.EMPortTypeClient emptc = new ServiceReference1.EMPortTypeClient();
myGSR = emptc.GetSurvey(myGSRq);
// In this example the response Object comes back with a URL used to redirect the user
//after the webservice has been processed.
if (myGSR.Url != null)
Response.Redirect(myGSR.Url.ToString());
else
Response.Write("Error");
return null;
Pretty simple, hope this helps!
If you are creating a new service and have the option of using a webservice or a Web API, I suggest using Web API.
Build RESTful API's with ASP.NET Web API

WebClient async callback not called in ASP.NET MVC

On GET request I run (something like):
public ActionResult Index(void) {
webClient.DownloadStringComplete += onComplete;
webClient.DownloadStringAsync(...);
return null;
}
I see that onComplete isn't get invoked until after Index() has finished execution.
I can see that onComplete is invoked on a different thread from one Index was executed on.
Question: why is this happening? why is webClient's async thread is apparently blocked until request handling thread is finished?
Is there a way to fix this without starting new thread from ThreadPool (I tried this, and using thread pool does work as expected. Also webClient's callback does happen as expected if DownloadStringAsync is called from a ThreadPool's thread).
ASP.NET MVC 3.0, .NET 4.0, MS Cassini dev web server (VS 2010)
EDIT: Here is a full code:
public class HomeController : Controller {
private static ManualResetEvent done;
public ActionResult Index() {
return Content(DownloadString() ? "success" : "failure");
}
private static bool DownloadString() {
try {
done = new ManualResetEvent(false);
var wc = new WebClient();
wc.DownloadStringCompleted += (sender, args) => {
// this breakpoint is not hit until after Index() returns.
// It is weird though, because response isn't returned to the client (browser) until this callback finishes.
// Note: This thread is different from one Index() was running on.
done.Set();
};
var uri = new Uri(#"http://us.battle.net/wow/en/character/blackrock/hunt/simple");
wc.DownloadStringAsync(uri);
var timedout = !done.WaitOne(3000);
if (timedout) {
wc.CancelAsync();
// if this would be .WaitOne() instead then deadlock occurs.
var timedout2 = !done.WaitOne(3000);
Console.WriteLine(timedout2);
return !timedout2;
}
return true;
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
return false;
}
}
I was curious about this so I asked on the Microsoft internal ASP.NET discussion alias, and got this response from Levi Broderick:
ASP.NET internally uses the
SynchronizationContext for
synchronization, and only one thread
at a time is ever allowed to have
control of that lock. In your
particular example, the thread running
HomeController::DownloadString holds
the lock, but it’s waiting for the
ManualResetEvent to be fired. The
ManualResetEvent won’t be fired until
the DownloadStringCompleted method
runs, but that method runs on a
different thread that can’t ever take
the synchronization lock because the
first thread still holds it. You’re
now deadlocked.
I’m surprised that this ever worked in
MVC 2, but if it did it was only by
happy accident. This was never
supported.
This is the point of using asynchronous processing. Your main thread starts the call, then goes on to do other useful things. When the call is complete, it picks a thread from the IO completion thread pool and calls your registered callback method on it (in this case your onComplete method). That way you don't need to have an expensive thread waiting around for a long-running web call to complete.
Anyway, the methods you're using follow the Event-based Asynchronous Pattern. You can read more about it here: http://msdn.microsoft.com/en-us/library/wewwczdw.aspx
(edit) Note: Disregard this answer as it does not help answer the clarified question. Leaving it up for the discussion that happened under it.
In addition to the chosen answer, see this article for further details on why the WebClient captures the SynchronizationContext.
http://msdn.microsoft.com/en-gb/magazine/gg598924.aspx

ASP.NET MVC How to output FileContent from within a controller action and continue

I am fairly new to MVC and want to know what the correct approach is - when a form is submitted the Edit ActionResult is executed, once the data is saved, I want to generate a file and send to the browser for download but also continue to another action.
The file is sent to the browser but no further processing occurs in the controller, because I use return RedirectToActions. Thanks in advance for any pointers.
public ActionResult Edit(int id, InvoiceFormData formData)
{
...
return base.RedirectToAction("ReturnPdf", new { id = 99 });
// More processing...ideally...then
return base.RedirectToAction("Action", "Controller");
}
public FileResult ReturnPdf(int? id)
{
...
return output; // writes file output and prompts user to download
}
You cannot use two return statements in the same action result and expect them to both run. When you "return" it means you're returning the output and then quiting out of the action result. Therefore, you could kind of chain your actions, so rather than doing the further processing inside the Edit action result, you could move that logic into the ReturnPdf AR(since that's what's I could see in your code), then finally return the final output in whatever action result you landed on. I hope that was clear enough...

Shared session state access between Controllers invoked via AJAX

I am trying to provide a progress monitoring mechanism for a longish-running request implemented by an AsyncController. A web page invokes (via JQuery $.post) the asynchronous StartTask action on the following controller...
[NoAsyncTimeout]
public class TaskController: AsyncController
{
[HttpPost]
public void StartTaskAsync()
{
AsyncManager.OutstandingOperations.Increment();
Session["progress"] = "in progress";
Task.Factory.StartNew(DoIt);
}
public ActionResult StartTaskCompleted()
{
return Json(new {redirectUrl = Url.Action("TaskComplete", "First")});
}
private void DoIt()
{
try
{
// Long-running stuff takes place here, including updating
// Session["progress"].
}
finally
{
AsyncManager.OutstandingOperations.Decrement();
}
}
}
The same web page sets up a 2-second timer (via window.setInterval) to call the following controller (via JQuery $.getJSON) that has read-only access to the session...
[SessionState(SessionStateBehavior.ReadOnly)]
public class ProgressController: Controller
{
[HttpGet]
public ActionResult Current()
{
var data = Session["progress"];
return Json(data, JsonRequestBehavior.AllowGet);
}
}
The function invoked after getJSON returns updates a DIV to show the current progress. Ultimately the progress will be updated in the session by the 'long-running stuff takes place here' code, but as it is the call to ProgressController.Current() does not find any data in the session and always returns null.
I had assumed that JQuery AJAX requests sent from the same browser to the same IIS server would end up with the same session, but it seems not. Do I need to explicitly set the ASP.NET session key on these $.post and $.getJSON calls? Or is it just not possible to share session state between Controllers (even if one has R/O access) in this way (I can fall back to a slightly hacky solution with Application state and GUIDs).
That's normal behavior. Your StartTask action blocks until it completes. It doesn't return any response until the DoIt method has finished executing. I suppose that's why you are calling it with AJAX $.post. The problem is that while this method runs and writes to the session and all other requests from the same session will be queued by the ASP.NET engine. You cannot write and read from the session at the same time. You will have to find another thread-safe storage for the progress data other than the session.

Resources