asp.net-mvc - varios - pasar lista de vista a controlador mvc
ASP.NET MVC: ¿Deben los controladores llamados por AJAX devolver JSON o renderizado html? (7)
Tengo problemas para decidir si una acción del controlador, a la que llama AJAX, debería devolver una vista parcial o el JSON "sin formato".
Al devolver una vista parcial, con HTML renderizado, es más fácil para JavaScript simplemente actualizar el DOM actual con el HTML devuelto. Sin embargo, sí limita lo que el cliente javascript que consume el servicio web puede hacer con el HTML devuelto.
Por otro lado, hacer que la acción del controlador devuelva JSON requeriría que el javascript realice la llamada para "manualmente" crear el marcado basado en el JSON que se devuelve.
Entonces, como de costumbre, cada enfoque tiene sus beneficios y debilidad. ¿Hay otros pros / contras para cada enfoque?
¿Por qué no tanto json como html? En el proyecto actual, estamos haciendo rutas para que pueda elegir desde el front-end, qué formato es el más adecuado en algunos casos ... así que, ¿por qué no hacen dos controladores, primero devolverán los datos esperados en json y el otro controlador devolverá los mismos? datos pero con html ... de esta manera puede elegir jQuery qué y cuándo quiere y en qué formato lo desea ... y lo mejor es que, para un formato diferente, solo necesita llamar a una dirección diferente ...
en otras palabras, hazlo tranquilo, bebé! :)
aclamaciones
En cuanto a mí, elijo el enfoque basado en datos. Aquí hay un pequeño conjunto de características para ambos:
Basado en datos:
- JSON desde el servidor (el controlador envía el modelo directamente a la respuesta)
- Enlace de plantillas JS (puede llevar más tiempo en el lado del cliente)
- Baja carga de ancho de banda
- ¡Es tan sexy!
Html-impulsado:
- HTML del servidor (el controlador envía el modelo a una vista parcial, presenta el resultado y lo devuelve; puede llevar más tiempo en el lado del servidor)
- Sin sobrecarga en el enlace JS
- Alto ancho de banda de carga
- No sexy, no no :)
Así que puedes mantener MVC incluso con un enfoque basado en HTML, aunque será un poco más difícil.
En mi opinión, devolver JSON y luego dejar que la vista lateral del cliente lo resuelva puede ser complicado debido a las siguientes limitaciones:
- No hay lenguaje de plantillas estándar para JavaScript. En el peor de los casos, tendrá la tentación de concatenar cadenas para formar el HTML que necesita.
- No hay una manera fácil de probar el HTML generado por su código de concatenación.
- La falta de IntelliSense para su JavaScript significa que también es propenso a cometer más errores.
La forma en que he manejado esto es devolver HTML procesado, PERO devolver este HTML procesado usando una vista parcial en su lugar. Esto te da lo mejor de ambos mundos. Tienes plantillas del lado del servidor así como soporte de IntelliSense.
Aquí hay un ejemplo:
Aquí está mi llamada Ajax, como puedes ver, todo lo que hace es reemplazar el html de mi lista desordenada:
FilterRequests: function() {
$.post("/Request.aspx/GetFilteredRequests", { }, function(data) {
$(''ul.requests'').html(data);
});
},
Aquí está mi acción en mi controlador:
public ActionResult GetFilteredRequests(string filterJson)
{
var requests = _requestDao.LoadAll();
return PartialView("FilteredRequests", requests);
}
Finalmente, aquí está mi vista parcial (no hay necesidad de entender esto, solo te estoy mostrando qué tan complejo puede ser el procesamiento en una aplicación del mundo real. Me daría miedo hacerlo en JavaScript. También notarás que mi vista parcial a su vez también llama a otras vistas parciales.):
<%@ 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>
<%}%>
Me gusta permitir que la aplicación que llama decida. He reunido un MultiViewController (gran parte del código que encontré en línea, intentaré actualizar con el crédito cuando lo encuentre) que, según la extensión de acción, devolverá el formato apropiado. por ejemplo:
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...
Mis controladores heredan de MultiViewController y en lugar de "vista de retorno (Modelo)"; Simplemente llamo "return FormatView (Model); o FormatView (" ViewName ", Model);". El segundo, si tengo que aplicar una vista específica al resultado, no la vista implícita.
El MultiViewController se ve así. Preste especial atención a FormatView, que devuelve un resultado de acción:
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 es simplemente una página maestra que no contiene ningún html adicional, toma la vista (para que pueda consolidar las clases parciales) y la presenta con un html limpio que se puede colocar directamente.
Si quiero json, el controlador construye mi modelo de vista y luego devuelve ese modelo de vista como json, en lugar de enviarlo a la vista predeterminada, lo mismo con .xml.
Las vistas parciales son un poco interesantes porque, por convención, todas mis vistas principales se dividen en parciales, de modo que ese parcial en particular se puede solicitar por sí mismo. Esto es útil para imitar la funcionalidad de un panel de actualización usando jquery sin toda la basura. asociado al updatepanel.
Para mantener la separación de preocupaciones debe devolver JSON.
Cuando devuelve html, limita lo que puede hacer con los datos devueltos. Si necesita una lista de datos y desea presentarla de diferentes maneras, use JSON, de lo contrario, tendría que tener diferentes métodos en el servidor para obtener las diferentes representaciones de los mismos datos.
Si está utilizando el paradigma MVC, el controlador debería devolver los datos (JSON) y dejar que la vista los resuelva por sí misma, al igual que su trabajo es encontrar / adaptar los datos en el modelo y pasarlos a la vista en el servidor. lado.
Obtienes puntos browny por
preservar la separación de las preocupaciones entre la lógica y la interfaz de usuario
haciendo verificables sus acciones ajax (buena suerte al probar el HTML devuelto por esa acción ...)
Tal vez sea un poco más complicado, pero encaja.
Puede usar sistemas de plantillas de clientes como lo que ahora está disponible en el kit de herramientas de MS Ajax para ayudar a tomar parte de la carga y preservar la separación lógica / representación en el lado del cliente.
Así que diría JSON, definitivamente. Pero hey, YMMV como de costumbre ...
Si usa JQuery, debería usar JSON o XML porque es más fácil de modificar, pero si su llamada ajax solo devuelve elementos para un cuadro de lista, por ejemplo, también podría usar html.
Mi preferencia personal es JSON o XML porque uso JQuery muy a menudo