Change page before AJAX async request ends - ajax

View
$("#button").click(function () {
$('#result').html("Processing...");
$.ajax({
url: '#Url.Action("GetData", "Json")',
async: true,
dataType: "json",
type: "GET",
success: function (data) {
$('#result').html(data);
},
});
return false;
});
Controller
public class JsonController : AsyncController
{
[HttpGet]
public async Task<JsonResult> GetData()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:8000/myservice.svc/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("GetData");
var result = await response.Content.ReadAsAsync<JSONResponse>();
return Json(result, JsonRequestBehavior.AllowGet);
}
}
}
Model
class JSONResponse{
public int Value { get; set; }
public string Text { get; set; }
}
I'm calling an wcf restful service asynchronously from an asp.net mvc application and displaying the result in a div.
When I click the button and the service starts processing and I try to change page meanwhile, I can't... and the page only changes after I get the result from the service.
How can I make it so I can keep changing while the service is executing and when is finished I just display the data in the div?
EDIT: Changing page meaning render different partial views below the div.

As I describe on my blog, async doesn't change the HTTP protocol.
You'll need to use a technology designed for this, such as SignalR.

Related

How to make an ajax call to controller action

This is my first Ajax call, and I am really confused about what to do.
I am using ASP.NET MVC, Identity to register users in my website. Once the user is registered, I send him an email to confirm their email address.
Here is my register Action Method:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
Email email = _emailBuilder.BuildConfirmationEmail(new MailAddress(model.Email.Trim(), model.FirstName.Trim() + " " + model.LastName.Trim()), callbackUrl, model.FirstName.Trim());
Session[SessionKeys.NewAccountConfirmationEmail.ToString()] = email;
await _emailService.SendEmailAsync(email);
return RedirectToAction("NewAccountCheckYourEmail");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay the form
return View(model);
}
The register method sends the confirmation email and redirects to NewAccountCheckYourEmail View and the user sees this page:
and here is the Action method to redirect users to confirm your email page
[AllowAnonymous]
public ViewResult NewAccountCheckYourEmail()
{
return View();
}
What I want to do is to store the email in the user session, so if the user clicks on resending the email, I resend the email.
I want to make an ajax call, so when the user clicks on resend link, it posts back to the controller, gets the email from the user session, resends it and redisplays the same view.
And I am not sure how to do this
What I have tried is to make this AJAX call:
$("#ResendEmailLink").click(function () {
$.ajax({
url: "/Account/NewAccountCheckYouEmail",
datatype: "text",
type: "POST",
success: function (data) {
$('#testarea').html("All OK");
},
error: function () {
$("#testarea").html("ERROR");
}
});
});
And I want it to hit this Action Method:
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> NewAccountCheckYourEmail()
{
Email email = Session[SessionKeys.NewAccountConfirmationEmail.ToString()] as Email;
await _emailService.SendEmailAsync(email);
return View();
}
But since I already have another Action method with the same name, I cannot add it... I guess what I am trying to do does not make much sense, any suggestion on a reasonable approach to achieve this?
As #Stephen Muecke pointed out to return Json data, so this basic change should work.
Resend Email Script:
$("#ResendEmailLink").click(function () {
$.ajax({
url: "/Account/ResendEmailToUser",
datatype:'json',
type: "POST",
success: function (data) {
if(data) { $('#testarea').html(data.Message) };
},
error: function () {
$("#testarea").html("ERROR");
}
});
});
Resend Email Action Method:
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> ResendEmailToUser()
{
Email email = Session[SessionKeys.NewAccountConfirmationEmail.ToString()] as Email;
await _emailService.SendEmailAsync(email);
var jsonData = new { Message = "Done!, We have Resend the Email" };
return Json(jsonData);
}

How to use ajax in asp.net MVC

How can I return a class object from Ajax in asp.net MVC....???
Example:
Ajax call from html:
$.ajax({
type: 'POST',
url: '/Tutorial/Web/AlignmentRule/GetAlignmentDetails',
data: { alignmentRuleId: alignmentRuleId },
success:
function (data) {
alert(data.Id);
alert(data.alignmentData.Id);
$("#ruleName").val(data.alignmentData.Name);
$("#level").val(data.alignmentData.Id);
},
error:
function () {
alert("Server Error!!!!");
},
dataType: 'JSON',
async: false
});
and Action method in contorller is:
public virtual JsonResult GetAlignmentDetails(int alignmentRuleId)
{
var alignmentData = _allignmentRuleRepository.GetAlignmentById(alignmentRuleId);
return Json( alignmentData );
}
And I want to return a list of alignmentRule class objects also....
you can compose your return object as you want, for example, create a ViewModel as decorator to hold everything you want to pass, like:
var json = new JsonViewModel() {
alignmentData = alignmentData,
rules = yourRules
};
return Json(json);
The error is thrown because by default MVC framework does't allow you to respond to an HTTP GET request with a JSON (because of security reasons).
In order to make it work, when you retrurn Json in your action, you need to specify JsonRequestBehavior.AllowGet
[HttpPost]
public virtual JsonResult GetAlignmentDetails(int alignmentRuleId)
{
var alignmentData = _allignmentRuleRepository.GetAlignmentById(alignmentRuleId);
return Json( alignmentData, JsonRequestBehavior.AllowGet);
}
EDIT
Annotate your action with [HttpPost] attribute.
For further investigation on this topic check this article

MVC RedirectToAction through ajax jQuery call in knockoutjs is not working

I am building a MVC3 web application and I am using knockoutjs. There are two views in the application. SetUpNewCompany and ManageAccount. To Set up a new company the user first enters the account number and clicks search. If the account number already exists the user can click on a button to go to the ManageAccount view. In the SetUpNewCompanyController I redirect using the RedirectToAction method. However, when the Index2 action in ManageAccount is executed the view is not displayed. If I type in the complete URL the view is displayed.
SetUpNewCompanyController.cs
[HttpPost]
public RedirectToRouteResult RedirectToManageAccount(string accountNumber)
{
return RedirectToAction("Index2", new RouteValueDictionary(new {controller=
"ManageAccount", companyId = "7e96b930-a786-44dd-8576-052ce608e38f" }));
}
This above is called by the function below when a button is clicked
self.redirectToManageAccount = function () {
var accountNumber = "7e96b930-a786-44dd-8576-052ce608e38f";
$.ajax({
type: "POST",
url: "/SetUpNewCompany/RedirectToManageAccount",
data: { accountNumber: accountNumber },
success: function (data) {
},
error: function () {
}
});
}
ManageAccountController.cs
public ActionResult Index2(String companyId)
{
var viewModel = new Models.Index();
List<String> compList = new List<String>();
compList.Add("MyCompany");
List<String> usersList = new List<String>();
usersList.Add("User1");
viewModel.Users = usersList;
viewModel.Companies = compList;
viewModel.CompanyId = companyId;
viewModel.Role = "Role1";
return View("ManageAccount",viewModel);
}
The URL that is generated is
http://localhost:53897/ManageAccount/Index2?companyId=7e96b930-a786-44dd-8576-
052ce608e38f
The console window in Firebug shows
GET http://localhost:53897/ManageAccount/Index2?companyId=7e96b930-a786-44dd-8576-
052ce608e38f 200 OK and the spinner keeps spinng
Also, how do I get the URL below instead of the one with querystring
http://localhost:53897/ManageAccount/Index2/7e96b930-a786-44dd-8576-052ce608e38f
Since you use AJAX to call the RedirectToManageAccount action method, you are responsible for handling its response yourself and as your success handler function is empty, you are effectively ignoring whatever arrives as a response.
If you want to force a redirect from within the AJAX response handler, I suggest
Modifying your action method as follows
[HttpPost]
public ActionResult RedirectToManageAccount(string accountNumber)
{
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index2", "ManageAccount", new { companyId = "7e96b930-a786-44dd-8576-052ce608e38f" });
return Json(new { Url = redirectUrl });
}
Updating your AJAX call in this way
self.redirectToManageAccount = function () {
var accountNumber = "7e96b930-a786-44dd-8576-052ce608e38f";
$.ajax({ type: "POST",
url: "/SetUpNewCompany/RedirectToManageAccount",
data: { accountNumber: accountNumber },
dataType: 'json',
success: function (response) {
window.location.href = response.Url;
},
error: function () {
}
});
}
As for your second question:
Also, how do I get the URL below instead of the one with querystring
http://localhost:53897/ManageAccount/Index2/7e96b930-a786-44dd-8576-052ce608e38f
You just have to define an appropriate route entry for this URL in your RegisterRoutes() function:
routes.MapRoute(null,
"ManageAccount/Index2/{companyId}",
new { controller = "ManageAccount",
action = "Index2" }
);
EDIT: As your AJAX call only serves to call an action method which causes a redirect, you can simplify it in a following way, provided you in this point (on the client side) know the companyId already:
self.redirectToManageAccount = function () {
var companyId = "12345";
window.location.href = '#(Html.ActionUri("Index2", "ManageAccount"))?companyId=' + companyId;
}
where I used this extension method
public static string ActionUri(this HtmlHelper html, string action, string controller)
{
return new UrlHelper(html.ViewContext.RequestContext).Action(action, controller);
}

Parameter to Web Service via Jquery Ajax Call

I am using revealing module pattern and knockout to bind a form. When data is entered in that form(registration), it needs to be posted back to MVC4 web method.
Here is the Jquery code
/*
Requires JQuery
Requires Knockout
*/
op.TestCall = function () {
// Private Area
var _tmpl = { load: "Loading", form: "RegisterForm"};
var
title = ko.observable(null)
template = ko.observable(_tmpl.load),
msg = ko.observable(),
postData = ko.observable(),
PostRegistration = function () {
console.log("Ajax Call Start");
var test = GetPostData();
$.ajax({
type: "POST",
url: obj.postURL, //Your URL here api/registration
data: GetPostData(),
dataType: "json",
traditional: true,
contentType: 'application/json; charset=utf-8'
}).done(Success).fail(Failure);
console.log("Ajax Call End");
},
GetPostData = function () {
var postData = JSON.stringify({
dummyText1: dummyText1(),
dummyText2: dummyText2(),
});
return postData;
}
return {
// Public Area
title: title,
template: template,
dummyText1: dummyText1,
dummyText2: dummyText2
};
}();
The controller code is simple as per now
// POST api/registration
public void Post(string data)
{
///TODO
}
When i am trying to, capture the data (using simple console.log) and validate it in jslint.com, it's a valid Json.
I tried hardcoding the data as
data: "{data: '{\'name\':\'niall\'}'}",
But still i get as null, in my web method.
Added the tag [System.Web.Script.Services.ScriptMethod(UseHttpGet = false, ResponseFormat = System.Web.Script.Services.ResponseFormat.Json)] to my Post method in controlled, but still no fruitful result
Even tried JSON.Stringify data: JSON.stringify(data) but still i get null in my web-method.
I am not able to figure out the solution.
Similar issue was found # this link
http://forums.asp.net/t/1555940.aspx/1
even Passing parameter to WebMethod with jQuery Ajax
but didn't help me :(
MVC and WebApi uses the concept of Model Binding.
So the easiest solution is that you need to create a Model class which matches the structure of the sent Json data to accept the data on the server:
public void Post(MyModel model)
{
///TODO
}
public class MyModel
{
public string DummyText1 { get; set; }
public string DummyText1 { get; set; }
}
Note: The json and C# property names should match.
Only escaped double-quote characters are allowed, not single-quotes, so you just have to replace single quotes with double quotes:
data: "{data: '{\"name\":\"niall\"}'}"
Or if you want to use the stringify function you can use it this way:
data: "{data: '" + JSON.stringify(data) + "'}"

ASP.NET MVC 3 - where is my JsonValueProvider?

I am trying to send JSON to an Action method:
[HttpPost]
public virtual ActionResult KoUpdateAccount(CostCentreDTOX cc)
{
if (cc.NameCC == null)
{
return Json(new { message = "Im null" });
}
else
{
string s = cc.NameCC;
return Json(new { message = s });
}
}
Where CostCentreDTOX is defined as:
[Serializable]
public class CostCentreDTOX
{
public int CostCentreId { get; set; }
public int IdTransactionType { get; set; }
public string NameCC { get; set; }
}
The Json is created by doing (I am using Knockoutjs):
var json = ko.toJSON(this.costCentres()[0]);
This produces the following string (which is what I want):
"{"CostCentreId":5,"IdTransactionType":2,"NameCC":"Impuestos"}"
The method that sends everything to the server is:
this.save = function() {
var json = ko.toJSON(this.costCentres()[0]);
api.postCud({
url: "/admin/Accounts/KoUpdateAccount/",
dataType: 'JSON',
data: json,
type: "post",
contentType: "application/json; charset=utf-8",
success: function(result) { alert(result.message) }
});
}
Where this.costCentre()[0] is an object defined as follows:
function costCentre(CostCentreId, IdTransactionType, NameCC) {
this.CostCentreId = ko.observable(CostCentreId);
this.IdTransactionType = ko.observable(IdTransactionType);
this.NameCC = ko.observable(NameCC);
}
However, the Action parameter cc just gets instantiated to its default values, as if the JsonValueProvider wasn't registered. But I am using ASP.NET MVC 3, so it should be there, right? Just there.
EDIT:
I have tried adding the following to the Global.asax file:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
}
But still, cc gets instantiated with default values.
any suggestions??
Is the api.postCud is that doing something exotic that could problems when it executes the post? Have you tried with $.ajax() instead just to see it that works?
As #Major Byte suspected, there was an issue with they way the ajax call was being made. This is done via a method, api.postCud, defined on an api.
The method is just a wrapper around $.ajax (see Eric Sowell's MvcConf2 video: Evolving Practices in Using jQuery and Ajax in ASP.NET MVC Applications). The problem being that it merges the options for the $.ajax call using $.extend() and I had included no provision for the dataType option.
So MVC was unaware that JSON was being posted, and therefore the model binding wasn't working.
This is what happens when I get 2 hours sleep...

Resources