1

Is there a way to add a JSON Result that would be consumed by the OnSuccess or OnFailure options of an AJAX.BeginForm when the controller is using the return View(model) syntax?

Everything is pretty standard C# / MVC. The Ajax.BeginForm would look like this

@using (Ajax.BeginForm("AnyAction", "Home", null,
    new AjaxOptions
    {
        HttpMethod = "Post",
        OnBegin = "OnBegin",
        OnFailure = "OnFailure(xhr, status)",
        OnSuccess = "OnSuccess(xhr, status)"
    },
    new { id = "myform" }))

The OnSuccess and OnFailure scripts are defined like this

    function OnSuccess(xhr, status) {
        console.log("OnSuccess");
    }
    function OnFailure(xhr, status) {
        console.log("OnFailure");       
    }

The controller returns like this

    HttpContext.Response.StatusCode = (int)HttpStatusCode.NotAcceptable;
    return View(model);

I can inject the HTTPStatusCode, either OK or Not OK, into the HTTPContext.Response and that will trigger the OnSuccess or OnFailure javascript functions. From that I know that I can manipulate the response stream but is there anyway to add a JSON response to the HTTPContext.Response such that the OnSuccess or OnFailure can consume it.

How can I pass this, while using the return View(model) syntax, to the OnSuccess function?

dynamic jsonMessage;
jsonMessage = new { param1 = "ModelState", param2 ="Error", param3 = "Error Message" };

Some quick notes:

This is not a requirement, just a question.

I am already using the Return JSON(jsonMessage, JsonRequestBehavior.AllowGet) elsewhere in my project, don't need help with that.

3
  • You could add your JSON string as a response header using HttpContext.Response.AddHeader("json", "json_string");. You could then access the header value in your OnSuccess/Failure method. It can seem like a hack because response headers aren't meant to carry data. How big is your JSON? Commented Mar 28, 2019 at 1:12
  • The JSON is quite small, only a couple of flags. I was thinking it would be something in the output stream but the header makes more sense. I will verify this early tomorrow and give what credit I can to a comment. Commented Mar 28, 2019 at 4:29
  • I'll add it to the answer since a header solution would be acceptable. Alternatively you could have put it into a Model property, that could then be bound with a data-* attribute of a hidden field in your CSHTML. It would need a few extra lines of code in your OnSuccess to get the JSON out from that data-* attribute, but that could also work for larger jsons. Commented Mar 28, 2019 at 13:02

2 Answers 2

1

Since your JSON is small, you could add your JSON string as a response header using

HttpContext.Response.AddHeader("json", "json_string");.

It can then be accessed from the header value in OnSuccess/Failure method.

Sign up to request clarification or add additional context in comments.

1 Comment

Saharsh, I gave you credit for pointing me in the right direction but I wanted to provide a more complete answer, since there were several additional steps involved and anyone that finds this post should have a complete answer.
1

I wanted to follow up with the my final solution. First we need to adjust the OnSuccess definition of the Ajax.BeginForm property to look like this. I tried several variations of this but this exact code is the only one that worked.

@using (Ajax.BeginForm("AddUserRole", "AppRoles", null,
    new AjaxOptions
    {
        HttpMethod = "Post",
        OnBegin = "OnBegin",
        OnFailure = "OnFailure(xhr, status)",
        OnSuccess = "OnSuccess(data, status, xhr)"
    },
    new { id = "myform" }))

Next the javascript for the OnSuccess looks like this. A few things to note; first the controller, shown farther down, can return either a JsonResult or a View / Model. The OnSuccess function will be fired regardless of which is returned as long as the HttpResponseStatus is OK. If the controller returns a View/Model, the data parm will contain the entire rendered view and the json I want will be in the XHR parameter. To work with the json response it must be extracted using the getResponseHeader and then serialized to JSON. After that we can work with it as a regular old JSON object.

function OnSuccess(data, status, xhr) {
    console.log("OnSuccess");
    // this is for capturing from the Response header WHEN the controller returns a view
    var srchMessage = xhr.getResponseHeader("srchMessage")
    if (srchMessage != null) {
        var srchJson = JSON.parse(srchMessage);
        console.log("srchMessage:param1" + srchJson.param1);
        return;
    }
    // this is for capturing the json WHEN the controller returns a JsonResult
    if (xhr.responseJSON != null) {
        console.log("xhr.responseJSON.param1" + xhr.responseJSON.param1);
    }
}

The MVC controller can return either a 'short' JsonResult or the complete view, looks kinda like this

public ActionResult AjaxTest(AppModel model)
{
    if (model.status == "ReturnView")
    {
        jsonMessage = new { param1 = "param1", param2 = "param2", param3 = "param3" };
        string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(jsonMessage);
        HttpContext.Response.AddHeader("srchMessage", jsonString);
        HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
        return View(model);
    }

    if (model.status == "ReturnJSON")
    {
        jsonMessage = new { param1 = "param1", param2 = "param2", param3 = "param3" };
        HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
        return Json(jsonMessage, JsonRequestBehavior.AllowGet);
    }
}

I'm not sure why I wanted to do this, I should have separate controllers for the different actions, but this is how it can be done if you wanted to do it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.