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

3

11

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?

Hottempered answered 11/5, 2012 at 0:38 Comment(0)
R
5

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);
}
Recurrence answered 11/5, 2012 at 5:13 Comment(1)
I'm currently using option 2, but think I'll switch it out for something more like your first option to reduce my number of http requests. Thanks!Hottempered
D
7

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);
    }
}
Demarcate answered 11/5, 2012 at 1:51 Comment(1)
I'd rather keep the content type as application/json so that the url can be used for purposes other than this particular use caseHottempered
R
5

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);
}
Recurrence answered 11/5, 2012 at 5:13 Comment(1)
I'm currently using option 2, but think I'll switch it out for something more like your first option to reduce my number of http requests. Thanks!Hottempered
P
0

If you return a JsonResult, via calling the Json() method, it won't return a web page. To return a page, you need to return a ViewResult, via calling the View method. Your method should have a corresponding view template

Check out this link or this one

Phytology answered 11/5, 2012 at 1:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.