Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

calling @Html.Action for JsonResult changes my response type in parent template

I've got the following controller:

public class HelloController
{
    public ActionResult Index()
    {
        return View()
    }

    public ActionResult Hello()
    {
        return Json(new{ greeting = "hello, world!" }, JsonRequestBehavior.AllowGet);
    }
}

Then, inside Index.cshtml:

...html stuffs
<script type="text/javascript">
    alert("@Html.Action("Hello")");
</script>

What I'm finding is that, when going to this url in my browser, the response content type is application/json; charset=utf-8 which causes the browser to render the html as a string instead of as... a web page.

What's the best way to get around this?

like image 757
DMac the Destroyer Avatar asked May 11 '12 00:05

DMac the Destroyer


People also ask

What is the correct way to return JSON objects from action methods in ASP NET MVC?

In your action method, return Json(object) to return JSON to your page. SomeMethod would be a javascript method that then evaluates the Json object returned. ContentResult by default returns a text/plain as its contentType.

What is JsonResult type in MVC?

JsonResult is one of the type of MVC action result type which returns the data back to the view or the browser in the form of JSON (JavaScript Object notation format). In this article we will learn about JsonResult by taking scenario to bind view using the JSON Data .

What is JsonRequestBehavior?

If you need to send JSON in response to a GET, you'll need to explicitly allow the behavior by using JsonRequestBehavior. AllowGet as the second parameter to the Json method. However, there is a chance a malicious user can gain access to the JSON payload through a process known as JSON Hijacking.


2 Answers

Just use the overload of Json(...) to set the correct content type.

public class HelloController
{
    public ActionResult Index()
    {
        return View()
    }

    public ActionResult Hello()
    {
        return Json(new{ greeting = "hello, world!" }, "text/html", JsonRequestBehavior.AllowGet);
    }
}
like image 113
hwiechers Avatar answered Oct 28 '22 02:10

hwiechers


The reason to this is that all Html.Action invocations are executed directly. Something like:

  1. Index is called
  2. View result is executed
  3. Hello action is executed, set's ContextType
  4. Index view result is returned
  5. Browser displays the page

You got two options:

  1. Break out the logic which generates "Hello world!" into a regular C# class and invoke it directly in the Index controller action
  2. Load the Hello action through ajax and then display the alert.

Option 1

public class HelloController
{
    YourBusiness _yb;

    public HelloController(YourBusiness yb)
    {
        _yb = yb;
    } 
    public ActionResult Index()
    {
        return View(yb.GenerateHello())
    }

    // used for everything but Index
    public ActionResult Hello()
    {
        return Json(new{ greeting = yb.GenerateHello() }, JsonRequestBehavior.AllowGet);
    }
}

public class YourBusiness
{
    public string GenerateHello()
    {
        return "Hello wolrd!";
    }
}

Option 2

<script type="text/javascript">
    $.get('@Url.Action("Hello")', function(response) {
        alert(response.greeting);
    }
</script>

Side note

Internet Explorer is quite aggressive when it comes to caching. The JSON responses will be changed. I therefore recommend that you also specify no cache for the JSON action:

[OutputCache(Duration = 0, NoStore = true)]
public ActionResult Hello()
{
    return Json(new{ greeting = "hello, world!" }, JsonRequestBehavior.AllowGet);
}
like image 28
jgauffin Avatar answered Oct 28 '22 04:10

jgauffin