2010-03-15 3 views
13

Похоже, что вызов Html.RenderAction в приложениях Asp.Net MVC2 может изменить тип mime страницы, если тип дочернего действия отличается от родительского действия.Asp.Net MVC2 RenderAction изменяет тип 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="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>. 
</p> 
<script> 
    var states = <% Html.RenderAction("States"); %>; 
</script> 

ответ

8

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

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

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

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

это будет работать ... это просто не похоже, что дочернее действие должно иметь возможность изменять ContentType всей страницы. –

+0

Обратите внимание, что JavaScriptSerializer(). Сериализация не выполняет сериализацию встроенных кавычек правильно, в отличие от метода Json. Вам понадобится что-то вроде: Func safeForJson = (s) => { return s.NotNull(). Заменить ("\" "," \\\ ""); }; –

+0

Извините, NotNull метод принадлежит мне, но только убедитесь, что строка ввода не является нулевой (natch). –

3

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

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

Это не кажется, что это должно быть необходимым, хотя.

+1

Это не так решает проблему, как скрыть ее. 'JsonResult' по-прежнему изменяет' ContentType' здесь; он просто меняет его на то, что вы (в настоящее время!) ожидаете. –

+0

и для меня он просто возвращает текстовый файл с результатом Json на нем ... Это просто я или этот мусор невероятно глючит ... Кто написал это дерьмо? – SoftwareSavant

1

Craig Stuntz said Предпочитаемый тип контента должен быть изменен.

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

+1

Можете ли вы предложить сценарий, в котором это поведение (дочернее действие, изменяющее страницу ContentType) на самом деле является тем, что вы хотите? –

+0

@Gabe Moothart, я не могу придумать сценарий, в котором вы хотите, чтобы это произошло. Но дело в том, что проблема заключается не в изменении ContentType. Проблема заключается в вызове действия ** Json ** Result при отображении ** HTML **. JsonResult задает свойство ContentType объекта запроса 'application/json', как и предполагалось. Но, к сожалению, поскольку вы вызываете это из представления HTML, тип исходного ответа изменяется, как вы видите. –

8

Я рассматриваю это как ошибку. Если это ребенок действие, которое визуализируется, почему оно изменило бы родителя ответ действия? То же самое происходит с 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; 
4

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

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

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

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

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

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

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

1

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

+0

Спасибо, мне нравится этот обходной путь, кажется, самый чистый. Я бы просто переименовал расширение, например, «MimePreserveChildAction», так что другим разработчикам ясно, что цель этого метода. –

Смежные вопросы