Asp.Net MVC2 RenderAction изменяет тип mime страницы?

Похоже, что вызов Html.RenderAction в приложениях Asp.Net MVC2 может изменить тип mime страницы, если тип дочернего действия отличается от родительского действия.

Код ниже (тестирование в RTM MVC2), который кажется мне разумным, вернет результат типа application/json при вызове Home/Index. Вместо того, чтобы рассылать страницу, браузер будет barf и спросит вас, хотите ли вы загрузить его.

Мой вопрос: я что-то упустил? Это ошибка? Если да, то какое лучшее обходное решение?

контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewData[ "Message" ] = "Welcome to ASP.NET MVC!";

        return View();
    }

    [ChildActionOnly]
    public JsonResult States()
    {
        string[] states = new[] { "AK", "AL", "AR", "AZ", };

        return Json(states, JsonRequestBehavior.AllowGet);
    }
}

Вид:

<h2><%= Html.Encode(ViewData["Message"]) %></h2>
<p>
    To learn more about ASP.NET MVC visit <a href="#" onclick="location.href='http://asp.net/mvc'; return false;" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<script>
  var states = <% Html.RenderAction("States"); %>;
</script>

Ответ 1

Это не ошибка. Предполагается, что тип JsonResult задает результат JSON, потому что это обычно то, что вы хотите.

Здесь вам действительно не нужен результат JSON , вам нужна строка JSON . Так почему бы просто не написать это?

[NonAction]
public string States()
{
    string[] states = new[] { "AK", "AL", "AR", "AZ", };

    return new JavaScriptSerializer().Serialize(states);
}

Ответ 2

Я считаю это ошибкой. Если это обработанное дочернее действие, почему оно изменит ответ родительского действия? То же самое происходит с Html.Action, который превращает его в строку. Мой способ обхода:

Html.ViewContext.HttpContext.Response.ContentType = "text/html";

после вызова Html.Action. Я полагаю, кто-то мог написать расширение Html Helper оболочки, что-то вроде:

var aux = Html.ViewContext.HttpContext.Response.ContentType;
Html.Action(....); // or Html.RenderAction(...)
Html.ViewContext.HttpContext.Response.ContentType = aux;

Ответ 3

Вы ничего не упускаете (если только я не слишком), и я думаю, что это ошибка. У меня такая же проблема в ASP.NET MVC3.

У нас есть действие контроллера, которое возвращает содержимое из простой системы управления контентом. CMS позволяет пользователю определять тип содержимого возвращаемого (например, text/plain или text/xml).

Действие контроллера либо вызывается непосредственно, либо вызывается как дочернее действие, чтобы разрешить представление содержать элементы, управляемые содержимым.

Если часть контента создается с типом контента "text/plain", и это встроено в представление ASP.NET MVC, тип содержимого родителя переопределяется, а браузер отображает HTML.

Гейб, я думаю, вы нанесли гвоздь на голову в том, что, похоже, не существует сценария, где дочернее действие, переопределяющее родителя, является желательным результатом.

Мое решение состоит в ветвлении на ControllerContext.IsChildAction и построении моего собственного объекта возврата, но это, на мой взгляд, является тем, что должно быть обработано каркасом.

Я уверен, что вы это знаете, но в вашем случае я бы предложил явно установить JsonResult.ContentType в тип содержимого родителя.

Ответ 4

Это можно решить, явно заставив тип mime "назад" на text/html:

return Json(states, "text/html", JsonRequestBehavior.AllowGet);

Не похоже, что это должно быть необходимо.

Ответ 5

Как Крейг Стунц сказал, тип контента должен измениться.

Лучшим подходом будет вызов этого действия с AJAX, а затем назначение возвращаемого объекта переменной states в коде JavaScript.

Ответ 6

У меня была проблема сегодня. Причина в том, что мне нужно повторно использовать существующее дочернее действие для заполнения некоторых json-данных на странице, чтобы избежать ненужных запросов ajax.

Основываясь на идее Джейми и Нива, я создал следующий вспомогательный метод.

public static MvcHtmlString ChildAction( this HtmlHelper htmlHelper, ActionResult result )
{
   var aux = htmlHelper.ViewContext.HttpContext.Response.ContentType;
   var actionResult = htmlHelper.Action( result );
   htmlHelper.ViewContext.HttpContext.Response.ContentType = aux;
   return actionResult;
}

Вызовите Html.ChildAction вместо Html.Action, когда вам нужно использовать результат дочернего действия, который возвращает данные json.