Подтвердить что ты не робот

ASP.NET MVC: Должны ли контроллеры, вызываемые AJAX, возвращать JSON или отображаемый html?

У меня возникли проблемы с решением о том, должно ли действие контроллера, вызываемое AJAX, возвращать частичный вид или "сырой" JSON.

Возвращение частичного представления, с визуализированным HTML упрощает для javascript просто обновлять текущую DOM с помощью возвращаемого HTML. Тем не менее, он ограничивает, что клиент javascript, потребляющий веб-сервис, может делать с возвращенным HTML.

С другой стороны, при возврате действия контроллера JSON потребуется, чтобы javascript вызывал "вручную" создание разметки на основе возвращаемого JSON.

Как обычно, каждый подход имеет преимущества и слабость. Существуют ли какие-либо другие плюсы и минусы для каждого подхода?

4b9b3361

Ответ 1

Если вы используете парадигму MVC, контроллер должен возвращать данные (JSON), и пусть представление сортирует это для себя, точно так же как его задача - найти/адаптировать данные в модели и передать ее в представление на стороне сервера.

Вы получаете коричневые точки для

  • сохранение разделения проблем между логикой и UI

  • делает ваши действия ajax проверенными (удача проверяет HTML, возвращенный из этого действия...)

Это немного сложнее, возможно, но подходит.

Вы можете использовать системы клиентского шаблона, такие как то, что теперь доступно в MS Ajax Toolkit, чтобы помочь выполнить некоторую нагрузку и сохранить разделение логики/рендеринга на стороне клиента.

Итак, я бы сказал, JSON, определенно. Но эй, YMMV, как обычно...

Ответ 2

На мой взгляд, возвращение JSON, а затем разрешение просмотра на стороне клиента может быть беспорядочным из-за следующих ограничений:

  • Нет стандартного шаблона для JavaScript. В худшем случае у вас возникнет соблазн объединить строки для формирования требуемого HTML.
  • Отсутствует простой способ unit test HTML, сгенерированный вашим конкатенационным кодом.
  • Отсутствие IntelliSense для вашего JavaScript означает, что вы также склонны совершать больше ошибок.

То, как я обработал это, - это вернуть отображаемый HTML, но верните этот визуализированный HTML, используя частичный вид. Это дает вам лучшее из обоих миров. У вас есть серверные шаблоны, а также поддержка IntelliSense.

Вот пример:

Здесь мой вызов Ajax, поскольку вы можете видеть все, что он делает, это заменить html для моего неупорядоченного списка:

FilterRequests: function() {
    $.post("/Request.aspx/GetFilteredRequests", { }, function(data) {
        $('ul.requests').html(data);
    });
},

Здесь мое действие на моем контроллере:

public ActionResult GetFilteredRequests(string filterJson)
{
    var requests = _requestDao.LoadAll();

    return PartialView("FilteredRequests", requests);
}

Наконец, вот мой частичный вид (мне не нужно это понимать, я просто покажу вам, как сложный рендеринг может получить в реальном мире. Я бы боялся сделать это в JavaScript. Вы также заметите, что мой частичный вид, в свою очередь, вызывает и другие частичные представления.):

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Request>>" %>
<%@ Import Namespace="Diangy.HelpDesk.Models.Lookups"%>
<%@ Import Namespace="Diangy.HelpDesk.Models.Requests"%>
<%@ Import Namespace="System.Web.Mvc.Html"%>

<% foreach (var request in ViewData.Model) %>
<%{%>
    <li class="request">
        <h2>#<%= request.Id %>: <%= request.InitialInteraction().Description %></h2>
        <p>from <%= request.Customer.FullName %> (<%= request.Customer.EmailAddress %>), <%= request.InitialInteraction().UsableTimeStamp %></p>

        <h3>Custom Fields & Lookups</h3>
        <div class="tabs">
            <ul>
            <li><a href="#customfields<%= request.Id %>">Custom Fields</a></li>
            <% foreach (var lookupDefinition in (List<LookupDefinition>)ViewData["LookupDefinitions"]) %>
            <%{%>
            <li><a href="#<%= lookupDefinition.Name.ToLowerInvariant().Replace(" ", "") + request.Id %>"><%= lookupDefinition.Name %></a></li>
            <%}%>
        </ul>
        <% Html.RenderPartial("CustomFields", request); %>
    </div>

    <% Html.RenderPartial("Discussion", request); %>
    <% Html.RenderPartial("Attachment", request); %>
    </li>
<%}%>

Ответ 3

Мне нравится разрешать вызывающему приложению решать. Я собрал MultiViewController (большую часть кода, который я нашел в Интернете, я попытаюсь обновить с кредитом, когда найду его), который, основываясь на расширении действия, вернет соответствующий формат. например:

myapp.com/api/Users/1 - defaults to html based on route
myapp.com/api/Users.html/1 - html
myapp.com/api/Users.json/1 - json
myapp.com/api/Users.xml/1 - xml
myapp.com/api/Users.partial/1 - returns a partial view of action name (see code)
myapp.com/api/Users.clean/1 - partial html without styling, etc...

Мои контроллеры наследуют от MultiViewController и вместо "return view (Model)"; Я просто называю "return FormatView (Model)" или "FormatView" ( "ViewName", Model); ". Второй, если мне нужно применить конкретный вид к результату - не подразумеваемый вид.

MultiViewController выглядит следующим образом. Обратите особое внимание на FormatView, whitch возвращает результат действия:

    public abstract class MultiViewController : Controller
{
    private const string FORMAT_KEY = "format";
    public enum FileFormat {Html, Json, Xml, Partial, Clean}

    protected MultiViewController()
    {
        RequestedFormat = FileFormat.Html;
    }
    protected FileFormat RequestedFormat { get; private set; }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        var routeValues = filterContext.RouteData.Values;
        if (routeValues.ContainsKey(FORMAT_KEY))
        {
            var requestedFormat = routeValues[FORMAT_KEY].ToString();
            if (isValidFormat(requestedFormat))
            {
                RequestedFormat = (FileFormat)Enum.Parse(typeof(FileFormat), requestedFormat, true);
            }
        }
    }

    private bool isValidFormat(string requestedFormat)
    {
        return Enum.GetNames(typeof (FileFormat)).Any(format => format.ToLower() == requestedFormat.ToLower());
    }

    protected ActionResult FormatView(string viewName, object viewModel)
    {
        switch (RequestedFormat)
        {
            case FileFormat.Html:
                if (viewName != string.Empty)
                {
                    return View(viewName,viewModel);
                }
                return View(viewModel);
            case FileFormat.Json:
                return Json(viewModel);
            case FileFormat.Xml:
                return new XmlResult(viewModel);
            case FileFormat.Partial:
            //return View(this.ControllerContext.RouteData.Values["action"] + "Partial");
            return PartialView(this.ControllerContext.RouteData.Values["action"] + "Partial");
            case FileFormat.Clean:
                if (viewName != string.Empty)
                {
                    return View(viewName, "~/Views/Shared/Clean.master", viewModel);
                }
                var v = View(viewModel);
                v.MasterName = "~/Views/Shared/Clean.Master";
                return v;
            default:
                throw new FormatException(string.Concat("Cannot server the content in the request format: ", RequestedFormat));
        }
    }
    protected ActionResult FormatView(object viewModel)
    {
        return FormatView("", viewModel);
    }




}

Clean.master - это просто главная страница, которая не содержит никаких дополнительных html - она ​​принимает представление (чтобы я мог консолидировать любые частичные классы) и отображал его с помощью чистого html, который можно разместить напрямую.

Если я хочу json - контроллер строит мою модель просмотра, а затем возвращает эту модель представления как json, вместо отправки в представление по умолчанию - то же самое с .xml.

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

Ответ 4

Чтобы поддерживать разделение проблем, вы должны вернуть JSON.

Когда вы возвращаете html, вы ограничиваете, что можете делать с возвращенными данными. Если вам нужен список данных и вы хотите представить его по-разному, используйте JSON, иначе вам придется иметь разные методы на сервере, чтобы получать разные визуализации одних и тех же данных.

Ответ 5

Почему бы и json и html? В текущем проекте мы делаем маршруты, чтобы вы могли выбирать из интерфейса, какой формат лучше всего подходит в некоторых случаях... так почему бы не сделать два контроллера, сначала вернет ожидаемые данные в json, а другой контроллер вернет такие же но с html... таким образом, вы можете выбрать из let say jQuery, что и когда вы хотите, и в каком формате вы хотите его... и самое лучшее, для разных форматов вам просто нужно вызвать другой адрес...

Другими словами, успокойтесь, детка!:)

веселит

Ответ 6

Что касается меня, я выбираю подход, основанный на данных. Вот небольшой набор функций для обоих:

на основе данных:

  • JSON с сервера (контроллер отправляет модель напрямую для ответа)
  • привязка шаблона JS (может потребоваться больше времени на стороне клиента)
  • Низкая пропускная способность нагрузка
  • Это просто так сексуально!

Html привод:

  • HTML с сервера (контроллер отправляет модель в некоторый частичный вид, он отображает результат и возвращает его - может потребоваться больше времени на стороне сервера)
  • Отсутствие перегрузки в привязке JS
  • Высокая пропускная способность
  • Не секси, нет нет:)

Таким образом, вы можете поддерживать MVC даже при помощи HTML-подхода, хотя это будет немного сложнее.

Ответ 7

Если вы используете JQuery, вы должны использовать JSON или XML, потому что его проще изменить, но если ваш вызов ajax возвращает только элементы для списка, например, вы также можете использовать html.

Мои личные предпочтения - JSON или XML, потому что очень часто используйте JQuery