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

Частичные взгляды против Json (или оба)

Я использую ASP.NET MVC с jQuery и имею много запросов Ajax для моих контроллеров.

Использовать частичные представления (usercontrols) для создания внутреннего представления при загрузке страницы. Затем, если мне нужно добавить/заменить данные на основе моего запроса Ajax, я создаю HTML из ответа Json.

Этот подход дает мне полный контроль, т.е. Я могу получить дополнительную информацию с моего контроллера, если что-то пошло не так, а затем отобразите на нем сообщение об ошибке.

Тем не менее, в последнее время меня очень раздражало все дополнительные работы, связанные с поддержкой структуры HTML как в моих частичных представлениях, так и в части, которая генерирует HTML из Json.

Мне нравится делать запрос ajax jQuery, а затем возвращать контроллер PartialView ( "mypartialview" ), а затем просто использовать jQuery для замены HTML в представлении.

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

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

Итак, как вы решаете эту проблему?

Спасибо за чтение.

4b9b3361

Ответ 1

На основе fooobar.com/questions/16451/...

Сначала создайте метод расширения для класса контроллера.

public static string RenderViewToString(this Controller controller, string viewName, object model)
{
    using (var writer = new StringWriter())
    {
         var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
         controller.ViewData.Model = model;
         var viewCxt = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, writer);
         viewCxt.View.Render(viewCxt, writer);
         return writer.ToString();
     }
}

Затем верните json в метод действий с контроллерами.

return Json(new
                            {
                                Html = this.RenderViewToString("MyView", model),
                                SomeExtraData = data
                            });

Ваши запросы ajax теперь получат json с содержащимся в нем html. Все еще экспериментирует с этим подходом к возврату простых фрагментов Html.

Надеюсь, что это поможет.

EDIT Обновлено для работы с бритвой

Ответ 2

Ниже приведен пример использования Content-Type, возвращаемого каждым соответствующим результатом. Мы используем это для отправки информации об ошибке, и там уже есть JS для отображения сообщений, поэтому мы получаем либо частичное представление, которое мы хотим, либо управляем информацией для сообщений об ошибках и т.д.

Для справки, частичный вид возвращает text/html, и ответ JSON должен возвращать application/json.

Как обычно, забавная часть находится на стороне javascript, и JQuery ajax() здесь не разочаровывает!

В вашем контроллере просто верните либо PartialView(), либо Json(model,), если это необходимо; мы используем его в формате try/catch.

public ActionResult Edit(int id) {
    try {
        var model = getYourModel();
        return PartialView("Edit", model);
    }
    catch (Exception ex) {
        var mi = new MessageInfo(MessageType.Error, String.Format("Edit failed: {0}", ex.Message), true);
        return Json(mi, "application/json", JsonRequestBehavior.AllowGet);
    }
}

На стороне JS мы используем следующую функцию. Обратите внимание, что вам необходимо заново установить любые события JQuery, которые вы подключили в $(document).ready(), от начального уровня GET на уровне страницы, поэтому у нас есть параметр обратного вызова.

function getPartialView(action, controller, model, divId, callback) {
    var url = "/" + controller + "/" + action + "/";
    $.ajax({
        type: "GET",
        url: url,
        data: model,
        success: function (data, textStatus, jqXHR) {
            var ct = jqXHR.getResponseHeader("Content-Type");
            var mx = ct.match("text\/html");
            if (mx != null) {
                $(divId).html(data);
                if (callback) {
                    callback($(divId));
                }
            }
            else {
                addMessage(data.type, data.title, data.text, data.sticky);
            }
        },
        error: function (jqXHR, textStatus, errorThrown) {
            addMessage(3, "\"" + url + "\": Failed", textStatus + ": " + errorThrown, false);
        }
    });
}

Единственный сложный бит - проверка заголовка Content-Type в ответе и поведение соответственно. Обратите внимание, что мы "обманываем", предполагая JSON, если это не HTML. Мы называем нашу ранее существовавшую функцию addMessage(), делаем все, что вам нужно!

И, наконец, вот пример элемента Anchor с onclick таргетингом getPartialView() выше.

<a href="#" onclick="getPartialView('Action', 'Controller', model, '#partialviewdivid', function(dvx) { connectJqueryEvents(dvx); })">Cancel</a>

Работает отлично...

За исключением того, что форма отправляется через Ajax.BeginForm(), где полезная нагрузка JSON ошибочно обрабатывается как HTML из-за недостаточной проверки Content-Type. В результате ваш div получает некоторый JSON, добавленный к нему, который в основном не отображает как HTML. Обратный вызов AjaxOptions.OnSuccess выполняется, но это слишком поздно для вашей DOM в этот момент!

Существует простое решение, но, к сожалению, он требует небольшого ремонта до jquery-unobtrusive-ajax.js, потому что функция asyncOnSuccess() была близорука, как написано.

function asyncOnSuccess(element, data, contentType) {
  var mode;

  if (contentType.indexOf("application/x-javascript") !== -1) {
    return;
  }
  if (contentType.indexOf("application/json") !== -1) {
    return;
  }
...snip...
}

В версии OOTB отсутствует второй оператор if; добавив, что это исправление, необходимое для того, чтобы не допустить его взлома вашей полезной нагрузки JSON в DOM.

С помощью этого исправления полезная нагрузка JSON переходит в ваш AjaxOptions.OnSuccess Javascript, и вы можете действовать по мере необходимости.

Да, вы можете получить как

Надеюсь, вы знаете, что когда вы отправляете Json, вы можете отправить любую модель и позволить Javascript разобраться в этом; hasOwnProperty() пригодится там. Поэтому, очевидно, вы можете отправить какой-либо HTML-код с помощью уже упомянутого RenderViewToString().

Ответ 3

Я считаю, что вы могли бы вернуть отображаемый html в виде строки - это может быть альтернативная строка html, содержащая сообщение об ошибке для отображения?

Ответ 4

Вы также можете сделать это, Поместите это внутри своего контроллера.

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

    ViewData.Model = model;

    using (StringWriter sw = new StringWriter()) {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

        return sw.GetStringBuilder().ToString();
    }
}