【问题标题】:ASP.NET MVC: View sometimes returned as application/json instead of text/htmlASP.NET MVC:视图有时返回为 application/json 而不是 text/html
【发布时间】:2012-07-10 08:00:19
【问题描述】:

我有一个视图,我从中调用另一个视图来在我的 html 中的脚本标记内呈现一些 json:

public ActionResult App()
{
  return View();
}

public JsonResult SomeJsonData()
{
  // ... here goes the code that generates the model
  return Json(model, JsonRequestBehavior.AllowGet);
}

在我的 App.cshtml 文件中,我有这样的内容:

<script type='text/javascript'>
  var myJsonData = @Html.Action("SomeJsonData", "MyController");
</script>

问题是,有时当我在浏览器中重新加载页面(现在使用 Chrome 20)时,它会显示所有标记,如果我转到开发人员工具中的网络选项卡,我可以看到 Content-Type页面请求的类型为“application/json”。如果我只是重新加载页面,那么它会正确加载(内容类型应该是“text/html”)。

知道为什么会发生这种情况吗?还是我做错了什么?

【问题讨论】:

    标签: asp.net-mvc json content-type


    【解决方案1】:

    当您返回 JsonResult 时,您将响应 Content-Type 修改为 application/json。因此,您首先调用 App 控制器操作,该操作返回一个 View 并显然将 Content-Type 设置为 text/html 并在返回的视图内调用 SomeJsonData 操作,该操作对先前的内容类型进行废话并将其修改为 @987654326 @。当然最后一个获胜,这就是用户代理在一天结束时看到的:application/json

    所以,下面是如何继续:

    public ActionResult App()
    {
        // ... here goes the code that generates the model
        var model = ...
    
        return View(model);
    }
    

    在你的强类型视图中:

    @model MyViewModel
    <script type="text/javascript">
        var myJsonData = @Html.Raw(Json.Encode(Model));
    </script>
    

    【讨论】:

    • 实际上我已经有一个模型,并且我从该 ActionMethod 返回的数据与模型无关,我必须将其添加到 ViewBag 或类似的东西中。
    • 哦不,愿上帝禁止你使用 ViewBag。请怜悯。使用视图模型。如果您已经从 App 操作返回了一个模型,那么只需向这个 view model 添加一个属性(我强烈坚持使用 view model 这个词,不要混淆model) 将包含所需的信息。如果出于某种无法解释的原因您决定使用 ViewBag,我只想简单地说这是废话,但它会起作用:ViewBag.FooBar = someModel; 和视图内部var myJsonData = @Html.Raw(Json.Encode(ViewBag.FooBar));。但是向我保证你不会使用 ViewBag。
    • 我知道,我讨厌使用 ViewBag,并且在可以避免的情况下尽量不要使用它。但是我需要来自某些视图的一些数据,这些数据不属于该视图模型。
    • But there is some data that I need from certain views that just doesn't belong to that view model. => 这是一个矛盾的句子。事情是这样的:如果视图需要一些数据,则该数据属于视图模型。句号。没有进一步讨论的可能。您可能会采取任何您想要的方法,但如果您不使用视图模型将数据传递给您的视图,那么您的方法将是错误的(根据我的个人标准,您应该随意忽略 :-),我只需要为阅读这篇文章的其他人指出这一点,以避免和你犯同样的错误)。
    • 因此,例如,如果我的站点上有一个使用当前用户实例的标题,那么您可以将该用户属性添加到基本视图模型中,并确保站点中的每个视图都使用继承自该基础模型的模型?
    【解决方案2】:

    其实我刚刚发现了另一个相关的问题

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

    在发布之前我找不到任何东西。

    我要采取的方法只是在返回 json 数据时更改内容类型:

    public JsonResult SomeJsonData(bool returnAsHtml = false)
    {
      // ... here goes the code that generates the model
      return returnAsHtml ?Json(model, "text/html", JsonRequestBehavior.AllowGet) : Json(model, JsonRequestBehavior.AllowGet);
    }
    

    在 App.cshtml 上

    <script type='text/javascript'>
      var myJsonData = @Html.Action("SomeJsonData", "MyController", new {returnAsHtml = true});
    </script>
    

    我还添加了一个标志,以允许从其他地方调用操作方法,这些地方期望应用程序/json 响应。

    【讨论】:

      【解决方案3】:

      正如其他人所说,返回 JSON 的操作正在更改响应的内容类型。

      我能够通过使用 HtmlHelper 将 JSON 放入页面来解决此问题。我避免使用控制器和动作;我的 HtmlHelper 正在调用静态方法。此解决方案可能并非在所有情况下都有效,而且有点像 hack,但您可以避免通过这种方式将数据放入一堆视图模型中。

      namespace System.Web.Mvc.Html
      {
         public static class JsonDataProviderHelper
         {
            public static MvcHtmlString JsonDataProvider(this HtmlHelper helper, JsonDataType jsonDataType)
            {
               switch (jsonDataType)
               {
                  case JsonDataType.YARDSALE_MINI_CALENDAR:
                     var yardsales = SalesEventCrud.GetByMonthForJavascript(null, MvcApplication.CurrentPortalId);
                     return new MvcHtmlString(JsonConvert.SerializeObject(SalesEventCrud.GetByMonthForJavascript(null, MvcApplication.CurrentPortalId)));
      
                  default:
                     return new MvcHtmlString("");
               }
            }
      
            public enum JsonDataType
            {
               YARDSALE_MINI_CALENDAR
            }
         }
      }
      

      我正在使用 json.net 进行序列化。我有 switch 语句,因为我计划使用这个助手来返回 JSON 用于其他情况。

      在页面中:

      <script type="text/javascript">
         jQuery(document).ready(function () {
            setupSmallSidebarCalendar(@Html.JsonDataProvider(JsonDataProviderHelper.JsonDataType.YARDSALE_MINI_CALENDAR));
         });
      </script>
      

      在页面中,数据是直接以 JSON 形式写入的,因此不需要对数据进行其他解析/按摩。

      【讨论】:

        【解决方案4】:

        @Daran 找到了原因 - ContentType 被last 所做的任何事情覆盖。他的解决方案应该有效,但是如果您仍然喜欢 Action 方法模式,您应该能够执行以下操作,并在返回之前简单地更改 ContentType。它仍然是 JSON 数据,但内容类型与 HTML 视图配合得很好。

            [HttpPost]
            public JsonResult GetJson(int someId, int foobar)
            {
                JsonResult result = CreateResult(someId, foobar);
                result.ContentType = "text/html";
                return result;
            }
        

        缺点是,这有点奇怪和/或意外的行为。例如,如果您通过 AJAX 调用端点,我怀疑这会起作用。但它看起来几乎可以工作,如果它在共享代码库中,可能会引起一些混乱。出于这个原因,如果您这样做,可能值得以不被滥用的方式命名端点。您甚至可以创建一种旨在以这种方式工作而不是使用 JsonResult 的新型 Result。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-17
          • 1970-01-01
          • 2017-12-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多