How to catch postpack result to Web Api - asp.net-mvc

I know I have done some basic mistake, but I can't find solution by myself,
I have next form at ASP MVC 4
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "frmMy", data_bind = "submit: onSubmit", action = "/api/MyService/SaveUpload", enctype = "multipart/form-data" }))
{
<button type="submit" class="btn btn-default">Save</button>
}
and web api method
[HttpPost]
[AllowAnonymous]
public async Task<HttpResponseMessage> SaveUpload()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/");
var provider = new MultipartFormDataStreamProvider(root);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
...
return new HttpResponseMessage(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
but after /api/MyService/SaveUpload call my page is make redirect to web api method.
How to prevent this behavior and catch method result on page.

This is happening because you are not telling the Beginform method what to do when the call is successful or unsuccessful.
There are a few things you can do to correct this.
Instead of directly calling the api from view, You can make a call to an action method of MVC controller that will in turn call the api. On a successful return, your action method can decide what you want to do with the view, as in redirect to a different view/action or show some kind of notification.
If you don't want to add another layer, you can use AJAX.BeginForm instead (I am not sure if html.beginform allows success handlers) and then you'll have to write a javascript success/error handler function (a normal js function) and pass that to Ajax.Beginform in ajaxoptions. So that it will execute that handler function based on what your API returns (success /error). In that javascript handler function, you can write script to show a success method to the user or whatever next logical step for your application is. More on Ajax.BeginForm ajax optionshere.

Related

void ActionMethod call using ajax post request with verificationtoken overwrites page, turning it blank. How come?

I am trying to call an action method without affecting the view. I call the following action method
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public void Index(LoginModel login)//, string returnUrl)
{
if (ModelState.IsValid &&
System.Web.Security.Membership.ValidateUser(login.UserName, login.Password))
{
FormsAuthentication.SetAuthCookie(login.UserName, login.RememberMe);
login.JavascriptToRun = "updateForm()";
}
// handle error
}
by doing this
$('#loginBtn').click(function () {
var success = false;
var form = $('#loginForm');
var token = $('input[name="__RequestVerificationToken"]', form).val();
$.ajax({
url: $(this).data('url'),
type: 'POST',
data: {
__RequestVerificationToken: token,
LoginModel: "#Model"
},
success: function (result) {
alert("logged in");
}
});
});
The form is in a separate view which also contains above JS-code snippet.
Everything works fine except for that the entire page reloads and since the actionmethod is void this turns out blank. I do not want anything to happen to the webpage, only to change js code snippet stored in a model which BTW is an empty function as of now.
I've looked at related posts such as ASP.NET MVC - How to call void controller method without leaving the view? but I am none the wiser.
Feels like I'v hit a wall and others' input would be much appreciated. Cheers!
You can use ActionResult as a data type for Index() Action and use View() to return your javascript into it. (return JavaScriptResult())
Check out this too:
Working example for JavaScriptResult in asp.net mvc

ASP.NET MVC AJAX onError handling

I am trying to delete item from table. There is Ajax link for it.
#Ajax.ActionLink("Delete", "DeleteConfirm", new { id = Model.ID }, new AjaxOptions {
HttpMethod = "POST", UpdateTargetId = "TableID", OnSuccess = "CloseDialog", OnFailure = "AlerDialog"
})
It calls DeleteConfirm method from controller with POST method. I made simple controller which should do something so ActionLink should catch error and run OnFailure function (to show alert dialog).
Controller:
public ActionResult DeleteConfirm(int id)
{
// code here
}
What to return from controller method so OnFailure function invokes?
OnError is fired when error happens on serverside. By error, I mean exception, and I think you can't pass exception message on clientside except of 500 Server error.
I think that good aproach is to have some CustomResponse class that your action will return.
In your case, something like:
Class DeletionResponse
{
public bool IsDeletionSuccesfull {get; set; }
public string Message {get; set;}
}
In DeleteConfirm action you create new response, which maybe needs to inheriteActionResult class(I'm not sure because I'm new to MVC). If some error ocures while deleting, set DeletionSuccesfull to false, and Message to message of exception, or some custom message.
On client side, the point is to examine success in OnSuccess handler, and then decide what to do.
Something like:
function handleResponse(deletionResponse){
if(deletionResponse.d.IsDeletionSuccesfull){
CloseDialog();
}
else{
AlertDialog(deletionResponse.d.Message);
}
}
The OnFailure will fire based off the status code of the result, so something like this would give the desired effect.
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "Reason for failure");
Also, not sure if it's related but shouldn't your OnFailure text be "AlertDialog" instead of "AlerDialog"?
EDIT: In your controller action you should be able to test that the request is being made via Ajax by using this Extension method MVC provides Request.IsAjaxRequest(). Note that there is no true way to check if a request is an Ajax request on the server, this method is utilizing the presence of a custom header jQuery sets for all ajax requests it makes, in other words don't use Request.IsAjaxRequest() in business logic.
Source for IsAjaxRequest() method
namespace System.Web.Mvc
{
public static class AjaxRequestExtensions
{
public static bool IsAjaxRequest(this HttpRequestBase request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
return (request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest"));
}
}
}
how about throwing an exception?
public ActionResult DeleteConfirm(int id)
{
try
{
//make your call to the database here
return View();
}
catch (ExceptionType1 ex)
{
//log the details of your error for support purposes, alerting tracing etc.
ex.Message = "Nice message for user"
throw ex;
}
catch (ExceptionType2 ex)
{
//log the details of your error for support purposes, alerting tracing etc.
ex.Message = "Another nice message for user"
throw ex;
}
}
Your ajax call would then know it was a failure, and run the correct function.

Using $.getJSON in .NET MVC 3.0

I want to use jQuery.getJSON function in ASP.NET MVC 3.0, so I wrote the code below for test:
<input id="btn" type="button" />
<script>
$("#btn").click(function () {
$.getJSON("/Location/GetData", null, function (data) {
alert(data);
});
});
</script>
and I have a LocationController with below method:
public JsonResult GetData()
{
List<int> result = new List<int>(){1, 4, 5};
return Json(result);
}
But it doesn't work!
The GetData method calls, but 'alert' is not shown!
You need to tell MVC to allow your JSON action to be called via GETs by changing your return to:
return Json(result, JsonRequestBehavior.AllowGet);
By default (for security reasons) they only allow Json to be requested via POSTs.
To protect against cross-side-scripting attacks & JSON Hijacking, MVC 2+ (I think it was 2), requires that you access actions with JSON responses using POST, rather than GET.
You can override this behaviour by using the overload of Json(), where you set the JsonRequestBehavior.AllowGet flag, but as described in the blog post, this is not a good/safe idea.
The way I do all of my JSON requests, whether they be jsut loading data, or posting back, is to use the $.post jQuery method, and limit the controller action to only accept HttpPost.
so your code would become:
$("#btn").click(function () {
$.post("/Location/GetData", null, function (data) {
alert(data);
});
});
and
[HttpPost]
public JsonResult GetData()
{
List<int> result = new List<int>(){1, 4, 5};
return Json(result);
}
First of all. Install Firebug for Firefox so you can inspect the response the server sends, Chrome and IE has built in tools you can use too.
Without knowing the response I will assume the problem is that ASP.NET MVC protects you against JSON hijacking byt not allowing to return JSON for a GET request by default.
Try changing to:
return Json(result, JsonRequestBehavior.AllowGet);

jQuery post to another controller

If I have a Controller called "HomeController" and I'm on the Index page of that controller, how can I do a jQuery Ajax post to another controller.
I tried the below,
$.post("/DetailedQuote/jQueryGetDetailedQuote", { productCode: "LPJ" }, function(newHTML) {
alert(88);
});
I have a DetailedQuoteController.
I have also tried;
post("DetailedQuote/
post("DetailedQuote.aspx/
post("/DetailedQuote.aspx/
post("/DetailedQuoteController/
post("DetailedQuoteController/
post("DetailedQuoteController.aspx/
post("/DetailedQuoteController.aspx/
And still no joy.
I should also mention that this is running a Hybrid WebForms and MVC site on IIS 6.
EDIT
The error that is being returned in error: is "error" so I assume that's maybe a 404.
In fact, it is a 404. I just checked.
This should work:
public class DetailedQuoteController : Controller
{
[HttpPost]
public ActionResult GetDetailedQuote(string productCode)
{
return Json(new { Code = productCode, Quote = 123 });
}
}
And to invoke it first declare a global javascript variable containing the address of this controller somewhere inside the view:
var quoteAddress = '<%= Url.RouteUrl(new { controller = "DetailedQuote", action = "GetDetailedQuote" }) %>';
And finally call the method:
$(function() {
$.post(quoteAddress, { productCode: 'LPJ' }, function(json) {
alert(json.Quote);
});
});
There doesn't appear to be anything wrong with your jQuery command, so the most obvious place to start looking is in the controller itself. Things to check would be:
Does your Controller action return a Json response (e.g. public JsonResult jQueryGetDetailedQuote)?
Are you using the Json() method to return your object?
Do you have your action decorated with the [HttpPost] attribute?
Perhaps you could post part of your controller code as well?
I notice that in your jQuery method you're calling an action called jQueryGetDetailedQuote. If your intention is purely to just GET a result, then perhaps you should use jQuery's $.get() or $.getJSON() functions instead?

ASP.NET MVC Ajax post to Action requiring authentication returns login view when user session has timed out

I am using the Ajax.BeginForm to create a form the will do an ajax postback to a certain controller action and then the response view is inserted into the UpdateTargetId.
using (Ajax.BeginForm("Save", null,
new { userId = Model.UserId },
new AjaxOptions { UpdateTargetId = "UserForm" },
new { name = "SaveForm", id = "SaveForm" }))
{
[HTML SAVE BUTTON]
}
Everything works great except when the Users session has timed out and then they are redirected back to the login page. The login page then gets returned from the Ajax call because of the Authorize attribute and the html gets loaded into the UpdateTargetId and therefore I end up with the login page html within the user profile page (at the Target Id). My controller action looks like this:
[Authorize]
public ActionResult Save(Int32 UserId)
{
//code to save user
return View("UserInfoControl", m);
}
How can I solve this problem?
UPDATE (2011-10-20):
Found this post from Phil Haack about this exact issue - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx. I have not gotten a chance to digest or implement his solution yet.
I think that you can handle the authorization issue from inside the action.
First remove [Authorize], the use this code:
public ActionResult Save(Int32 UserId)
{
if (!User.Identity.IsAuthenticated)
{
throw new Exception();
}
//code to save user
return View("UserInfoControl", m);
}
Then you can put a OnFailure condition in your AjaxOptions and redirect your page or something.

Resources