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

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

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

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

контроллер:

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="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<script>
  var states = <% Html.RenderAction("States"); %>;
</script>

person Gabe Moothart    schedule 15.03.2010    source источник


Ответы (6)


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

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

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

    return new JavaScriptSerializer().Serialize(states);
}
person Craig Stuntz    schedule 15.03.2010
comment
это сработает ... просто не похоже, что дочернее действие должно иметь возможность изменять ContentType всей страницы. - person Gabe Moothart; 15.03.2010
comment
Обратите внимание, что JavaScriptSerializer (). Serialize некорректно сериализует встроенные кавычки, в отличие от метода Json. Вам понадобится что-то вроде: Func ‹string, string› safeForJson = (s) = ›{return s.NotNull (). Replace (\, \\\); }; - person Rob Kent; 06.02.2012
comment
Извините, метод NotNull - мой, но он просто проверяет, не является ли входная строка нулевой (natch). - person Rob Kent; 06.02.2012

Считаю это ошибкой. Если визуализируется дочернее действие, зачем ему изменять ответ действия родительского? То же самое происходит с 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;
person niv    schedule 16.11.2010

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

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

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

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

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

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

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

person jamiecon    schedule 14.10.2011

Это может быть решено путем явного принудительного возврата типа mime к text/html:

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

Хотя, похоже, в этом нет необходимости.

person Gabe Moothart    schedule 15.03.2010
comment
Это не столько решает проблему, сколько скрывает ее. JsonResult здесь все еще меняется ContentType; он просто меняет его на то, что вы (в настоящее время!) ожидаете. - person Craig Stuntz; 15.03.2010
comment
а для меня он просто возвращает текстовый файл с результатом Json на нем ... Это только у меня или эта фигня невероятно глючит ... Кто вообще написал эту хрень? - person SoftwareSavant; 30.07.2011

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

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

person Çağdaş Tekin    schedule 15.03.2010
comment
Можете ли вы предложить сценарий, в котором это поведение (ContentType страницы с изменением дочернего действия) на самом деле является тем, что вы хотите? - person Gabe Moothart; 15.03.2010
comment
@Gabe Moothart, я не могу придумать сценарий, при котором вы бы этого хотели. Но дело в том, что проблема не в изменении ContentType. Проблема заключается в вызове действия Json Result при рендеринге представления HTML. JsonResult устанавливает для свойства ContentType объекта запроса значение application/json, как и положено. Но, к сожалению, поскольку вы вызываете это из представления HTML, тип исходного ответа изменяется, как вы видите. - person Çağdaş Tekin; 15.03.2010

У меня была проблема сегодня. Причина в том, что мне нужно повторно использовать существующее дочернее действие для заполнения некоторых данных 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.

person Qixing    schedule 22.05.2013
comment
Спасибо, мне нравится этот обходной путь, он кажется самым чистым. Я бы просто переименовал расширение, например, в MimePreserveChildAction, чтобы другим разработчикам было ясно, какова цель этого метода. - person Zoltán Tamási; 29.07.2014