2

I'm trying to submit a form to a controller action and process the response based on OnSuccess or OnFailure. The problem is that even when the data isn't valid and I fail the ModelState.IsValid test, the OnSuccess method is called. The OnFailure method should be called.

My View:

@using (Ajax.BeginForm("UpdateCategory", "Home", null, new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "categoryForm", OnSuccess = "alert('success');", OnFailure = "alert('failure');" }, new { id = "formEditCategory" }))
{
    @Html.ValidationSummary(true)

    @Html.HiddenFor(model => model.CategoryID)

    <div>
        <div class="editor-label">
            @Html.LabelFor(model => model.CategoryName)
        </div>
        <div class="small-multiline-field">
            @Html.EditorFor(model => model.CategoryName)
        </div>
        <div class="validationMsg">
            @Html.ValidationMessageFor(model => model.CategoryName)
        </div>
    </div>
}

My Controller Action:

[HttpPost]
public ActionResult UpdateCategory(CategoryVM category)
{
    try
    {
        if (ModelState.IsValid)
        {
            var itemService = new ItemViewModels();
            itemService.UpdateCategory(category);
        }
    }
    catch (DataException)
    {
        //Log the error (add a variable name after DataException)
        ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
    }

    return PartialView("EditCategoryInfo", category);
}

My ViewModel:

public class CategoryVM
{
    public int CategoryID { get; set; }

    [StringLength(75, ErrorMessage = "Category Name must be under 75 characters.")]
    [DataType(DataType.MultilineText)]
    [Display(Name = "Name")]
    public string CategoryName { get; set; }

    [StringLength(3800, ErrorMessage = "Category Description must be under 3800 characters.")]
    [DataType(DataType.MultilineText)]
    [Display(Name = "Description")]
    [AllowHtml]
    public string CategoryDesc { get; set; }

    [Display(Name = "Display on Web")]
    public bool DisplayOnWeb { get; set; }
}

So if I enter a string in the CategoryName field that exceeds 75 characters I can see that the form does not pass the ModelState.IsValid test and the view is sent back annoted with the "Category Name must be under 75 characters." error message. But rather than firing the OnFailure event, it fires the OnSuccess event. Why?

Thanks in advance.

BKahuna
  • 601
  • 2
  • 11
  • 23

3 Answers3

6

Since you've caught the exception, what you are returning is a PartialView with HTTP status code of 200. That's why OnSuccess gets triggered.

What you can do instead is explicitly set the response code to 400(bad request)

[HttpPost]
public ActionResult UpdateCategory(CategoryVM category)
{
    try
    {
        if (ModelState.IsValid)
        {
            var itemService = new ItemViewModels();
            itemService.UpdateCategory(category);
        }
    }
    catch (DataException)
    {
        //Log the error (add a variable name after DataException)
        ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
        Response.StatusCode = 400;
    }

    return PartialView("EditCategoryInfo", category);
}
Jack
  • 2,600
  • 23
  • 29
  • I was using `HttpStatusCodeResult` to return a specific code in one scenario--one that was breaking in Firefox because no content was returned. I switched to use `Response.StatusCode`, `Response.StatusDescription`, and `Content(" ")`, and it works fine now. – Seth Sep 11 '13 at 16:14
  • If you set the StatusCode to an error, then you will not get your validation errors and your page may get sent to the global error page. This isn't the kind of solution I would want. – Don Rolling Jan 12 '17 at 16:46
  • The error details (in your case, it's the validation errors) will be return as part of the response body along with the status code. Setting status code is only telling the you there is an issue with the request. Whether you want to send the user to global error page or display the error message on the existing page, it's totally up to you. You can control this behaviour via your javascript. – Jack Feb 20 '17 at 04:55
2

OnSuccess method is called if the server returns a success HTTP response e.g. 200 OK and if the client successfully receives the response and update the page (as described on MSDN)

It's up to you to process content of the response.

Lukas Kabrt
  • 5,441
  • 4
  • 43
  • 58
1

With some more research (and Lukas' help below) I discovered this, which solves my problem.

Community
  • 1
  • 1
BKahuna
  • 601
  • 2
  • 11
  • 23
  • What could've made this answer work would've been if you had posted the solution, rather than a link to the solution. Just a tip. I upvoted you because I like the solution that you linked to. – Don Rolling Jan 12 '17 at 16:50