Compartir a través de


Este artículo proviene de un motor de traducción automática.

XHTML de RESTful

Servicios RESTful con ASP.NET MVC

Aaron Skonnard

Descarga de código disponible en la MSDN Code Gallery
Examinar el código en línea

En este artículo se describe:

  • RESTO
  • XHTML
  • ASP.NET MVC
En este artículo usa las tecnologías siguientes:
RESTO, XHTML, ASP.NET

Contenido

XHTML: Representación datos y vínculos
XHTML: Entrada con formularios de representación
Descripción de la arquitectura de ASP.NET MVC
Implementación del modelo
Implementar el controlador
Diseñar URI con rutas
Implementación de las vistas
Consumir el servicio de marcador
Confirmaciones

Puede desplazarse A RESTful servicio es un web de recursos que los programas.Al diseñar un servicio RESTful, tendrá que pensar cuidadosamente cómo funcionará su web.Esto significa diseñar representaciones de recursos con vínculos que facilitan la exploración, que describe el servicio de entrada de algún modo y teniendo en cuenta cómo los consumidores se desplazarse por el servicio en tiempo de ejecución.Hacer estas cosas derecho es a menudo de pasarse por alto, pero son fundamentales para darse cuenta de todo el potencial que REST tiene que ofrecer.

Hoy en día, los seres humanos explorar sitios mediante exploradores Web que sabe cómo representar HTML y otros tipos de contenido populares.HTML proporciona la sintaxis y semántica para establecer vínculos entre recursos (elemento <a>) y para describir y enviar la entrada de la aplicación (<form> y <input> elementos).

Cuando un usuario hace clic en un elemento <a> en la página representada, el explorador sabe para emitir una solicitud HTTP GET para el recurso de destino y representar la respuesta.Cuando un explorador encuentra un elemento <form>, sabe cómo representar la descripción de formulario en una interfaz de usuario que el usuario puede rellenar y enviar mediante solicitud un GET o POST.Cuando el usuario presiona un botón de envío, el explorador codifica los datos y los envía mediante la solicitud especificada.Estas dos características son en gran medida responsables del éxito de la Web.

Con vínculos junto con la interfaz HTTP universal permite redirigir las solicitudes a nuevas ubicaciones a lo largo del tiempo y cambiar determinados aspectos de seguridad sobre la marcha sin cambiar el código de cliente.Un enfoque estándar para formularios significa que puede agregar o quitar propiedades de entrada y cambiar valores predeterminados, de nuevo sin cambiar el código de cliente.Ambas características son muy útiles para crear aplicaciones que evolucionan con el tiempo.

Los servicios RESTful deben proporcionar también alguna forma estas dos características a través de cualquier representación de recurso que decida utilizar.Por ejemplo, si está diseñando un dialecto XML personalizado para el servicio, debe probablemente idear sus propios elementos para establecer vínculos y describir la entrada de servicio que le guiará a los consumidores a través de su web.O puede utilizar simplemente XHTML.

La mayoría de desarrolladores no considere inmediatamente XHTML como una opción de "servicios", pero que realmente de las maneras que se ha diseñado para utilizarse.Documentos XHTML son por definición XML bien formado, que permite el procesamiento automatizada mediante las API estándar de XML.Y puesto que XHTML es también HTML, viene con <a> <form>, y elementos <input> para el modelado de vínculo de exploración y entrada de servicio como describí anteriormente.Lo único que es un poco extraño en el primero es cómo modelar las estructuras de datos definido por el usuario; sin embargo, puede modelar las clases y los campos con <div> y <span> elementos y colecciones de entidades con <ol> y <li> elementos.Le guiaré a través de cómo hacer esto con más detalle más adelante en el artículo.

Hay varias razones para considerar XHTML como la representación predeterminada para los servicios RESTful de resumen.Primero, puede aprovechar la sintaxis y semántica de los elementos importantes como <a> <form> y <input> en lugar de crear su propio.En segundo lugar, terminará con los servicios que cree un lote como sitios, ya que será examinable por los usuarios y aplicaciones.Una persona sigue interpreta el XHTML, es sólo un programador durante el desarrollo en lugar de un usuario en tiempo de ejecución.Esto simplifica las cosas a lo largo del proceso de desarrollo y facilita para los consumidores aprender cómo funciona el servicio.Y, por último, puede aprovechar los marcos de desarrollo Web estándar para generar los servicios RESTful.

ASP.NET MVC es un marco de tal que proporciona un modelo de forma inherente RESTful para generar servicios basados en XHTML.Este artículo recorre algunos conceptos de diseño XHTML y, a continuación, muestra cómo crear un servicio RESTful completado basada en XHTML que se puede descargar desde el sitio MSDN Magazine.

XHTML: Representación datos y vínculos

Antes de profundizar en los detalles de ASP.NET MVC, primero veamos cómo se pueden representar estructuras de datos comunes y colecciones en XHTML.Este enfoque no es la única forma de hacerlo, pero es una práctica bastante habitual en servicios basados en XHTML de hoy.

En este artículo, describiré cómo implementar un servicio sencillo de marcador.El servicio permite a los usuarios crear, recuperar, actualizar y eliminar los marcadores y desplazarse de un sitio web de marcadores en una variedad de formas.Suponga que tiene una clase de C#, que representa un marcador que tiene este aspecto:

public class Bookmark
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Url { get; set; }
    public string User { get; set; }
}

¿La primera pregunta es cómo se puede representar una instancia de marcador en XHTML? Una consiste en combinar <div>, <span>, <a> elementos y, donde los elementos <div> representan estructuras, elementos <span> representan campos y <a> elementos representan identidad y vínculos a otros recursos. Además, puede anotar estos elementos con el atributo "class" de XHTML para proporcionar metadatos adicionales de tipo. Aquí es un ejemplo completo:

<div class="bookmark">
  <span class="bookmark-id">25</span>
  <span class="bookmark-title">Aaron's Blog</span>
  <a class="bookmark-url-link" href="http://pluralsight.com/aaron" 
  >http://pluralsight.com/aaron</a>
  <span class="bookmark-username">skonnard</span>
</div>

¿La siguiente pregunta es cómo procesará los consumidores a esta información? Puesto que es XML bien formado, consumidores pueden utilizar cualquier API de XML para extraer la información de marcador. La mayoría de los programadores de .NET encontrarán que XLinq proporciona el modelo de programación más natural para consumir XHTML mediante programación. Además, puede ir un paso más allá por mejorar XLinq con algunos métodos de extensión centradas en XHTML de útil que facilitan el modelo de programación.

En este artículo, usaré un conjunto de métodos de extensión XLinq que he incluido en el código de ejemplo descargable. Estas extensiones proporcionarle una idea de lo que es posible. El código siguiente muestra cómo utilizar el marcador XHTML que se muestra anteriormente mediante XLinq y algunas de estas extensiones:

var bookmarkDetails = bookmarkDoc.Body().Struct("bookmark");
Console.WriteLine(bookmarkDetails["bookmark-id"].Value);
Console.WriteLine(bookmarkDetails["bookmark-url"].Value);
Console.WriteLine(bookmarkDetails["bookmark-title"].Value);

Ahora, si desea mejorar cómo este marcador se representa en un explorador, puede agregar un Cascading StyleSheet (CSS) para controlar los detalles de representación específica del explorador o agregar algunos elementos de interfaz de usuario adicionales y el texto que no comprometer la capacidad del consumidor para extraer los datos de interés. Por ejemplo, el XHTML siguiente será más fácil para el usuario procesar, pero todavía puede utilizar el ejemplo de código anterior de .NET para procesar la información sin ninguna modificación:

<h1>Bookmark Details: 3</h1>
<div class="bookmark">
  BookmarkID: <span class="bookmark-id">25</span><br />
  Title: <span class="bookmark-title">Aaron's Blog</span><br />
  Url: <a class="bookmark-url-link" href="http://pluralsight.com/aaron" 
  >http://pluralsight.com/aaron</a><br />
  Username: <span class="bookmark-username">skonnard</span></a><br />
</div>

Colecciones de recursos no duros modelo cualquiera. Puede representar una lista de marcadores con una combinación de <ol>, <li> y <a> elementos tal como se muestra aquí:

<ol class="bookmark-list">
  <li><a class="bookmark-link" href="/bookmarks/1">Pluralsight Home</    a></li>
  <li><a class="bookmark-link" href="/bookmarks/2">Pluralsight On-    Demand!</a></li>
  <li><a class="bookmark-link" href="/bookmarks/3">Aaron's Blog</a></li>
  <li><a class="bookmark-link" href="/bookmarks/4">Fritz's Blog</a></li>
  <li><a class="bookmark-link" href="/bookmarks/5">Keith's Blog</a></li>
</ol>

El código siguiente muestra cómo imprimir esta lista de marcadores a la consola:

var bookmarks = bookmarksDoc.Body().Ol("bookmark-list").Lis();
bookmarks.Each(bm => Console.WriteLine("{0}: {1}",
    bm.Anchor().AnchorText, bm.Anchor().AnchorLink));

Observe cómo cada <li> contiene un elemento <a> que vincula a un marcador específico. Si deseara Desplácese uno de los elementos de anclaje, puede recuperar la representación de los detalles de marcador mostrada anteriormente. Como empezar a definir vínculos entre recursos así, el servicio comienza a convertirse en un sitio web de recursos vinculados.

Es bastante obvio el modo en que los usuarios pueden desplazarse entre recursos mediante un explorador Web, pero ¿consumir las aplicaciones? Una aplicación que sólo necesita localizar mediante programación el elemento delimitador de interés y, a continuación, emitir una solicitud GET destinar el URI especificado en el atributo "href". Estos detalles también se pueden ocultarse detrás de un método de extensión XLinq que encapsula la exploración del delimitador.

El código siguiente muestra cómo desplazarse por el primer marcador en la lista de marcador a la dirección URL de marcador de destino. El XHTML resultante se imprime en la consola:

var bookmarkDoc = bookmarks.First().Anchor().Navigate();
var bookmarkDetails = bookmarkDoc.Body().Struct("bookmark");
var targetDoc = bookmarkDetails.Anchor("bookmark-url-link").Navigate();
Console.WriteLine(targetDoc);

Una vez que comience a pensar en la creación de consumidores que desplazarse por el servicio como un web de recursos, oficialmente comienza a pensar de forma más RESTful.

XHTML: Entrada con formularios de representación

Ahora vamos a decir un consumidor desea crear un nuevo marcador en el sistema. ¿Cómo el consumidor averiguar qué datos de envío y cómo enviarlo sin WSDL? La respuesta es fácil: formularios XHTML.

El consumidor emite primero una solicitud GET al URI para recuperar el formulario de marcador de crear. El servicio devuelve un formulario de aspecto similar al siguiente:

<h1>Create Bookmark</h1>
<form action="/bookmark/create" class="create-bookmark-form" method="post">
  <p>
    <label for="bookmark-title">Title:</label><br />
    <input id="bookmark-title" name="bookmark-title" type="text" value="" />
  </p>
  <p>
    <label for="bookmark-url">Url:</label><br />
    <input id="bookmark-url" name="bookmark-url" type="text" value="" />
  </p>
  <p><input type="submit" value="Create" name="submit" /></p>
</form>

El formulario describe cómo generar una solicitud HTTP POST para crear un nuevo marcador. El formulario indica que se necesita proporcionar los campos de título de marcador y marcador-url. En este ejemplo, id de marcador será generado automáticamente durante la creación y marcador-username se deriva de la identidad de usuario que ha iniciado sesión. El formulario también le indica qué necesita para enviar y cómo para enviarla.

Cuando este formulario se representa en un explorador, una persona sólo puede rellenar el formulario y haga clic en Enviar para crear un nuevo marcador. Una aplicación que hace básicamente lo mismo enviando el formulario mediante programación. De nuevo, este proceso se puede realizar más fácil utilizando algunos métodos de extensión basada en formularios, que se muestra aquí:

var createBookmarkForm = createBookmarkDoc.Body().Form("create-bookmark-  form");
createBookmarkForm["bookmark-title"] = "Windows Live";
createBookmarkForm["bookmark-url"] = "https://live.com/";
createBookmarkForm.Submit();

Cuando se ejecuta este código, el método Submit genera una solicitud HTTP POST como destino la dirección URL "acción", y los campos de entrada tienen el formato juntos de una cadena codificada como dirección URL (aplicación/x-www-form-urlencoded). En el final del no diferente utilizando el explorador, el resultado es un nuevo marcador.

Aunque exploradores hoy admiten GET y POST sólo para el método de formulario, nada está deteniendo puede también especificar PUT o DELETE que el formulario "método" al destino nonbrowser consumidores. El método de extensión enviar realiza igualmente bien para cualquier método HTTP que se especifique.

Descripción de la arquitectura de ASP.NET MVC

La arquitectura de ASP.NET MVC se basa en el patrón de diseño popular de controlador de vista de modelo que ha estado presente durante décadas. figura 1 ilustra los diversos componentes de ASP.NET MVC y cómo se relacionan entre sí. ASP.NET MVC incorpora un motor de enrutamiento se sitúa delante de los demás componentes MVC. El motor de enrutamiento recibe solicitudes HTTP entrantes y las encamine a un método de controlador. El motor de enrutamiento se basa en un conjunto centralizado de rutas que se definen en global.asax.

fig01.gif

Figura 1 arquitectura de ASP.NET MVC

Las rutas centralizadas definen asignaciones entre los patrones de la dirección URL y los métodos de controlador específico y argumentos. Cuando genere vínculos, utilice estas rutas para generar correctamente los vínculos. Esto facilita la modificar su diseño de la dirección URL durante el proceso de desarrollo en una ubicación central.

Es el trabajo del controlador para extraer información de la solicitud entrante y para interactuar con la capa de modelo user-defined. La capa de modelo puede ser cualquier (LINQ to SQL, ADO.NET Entity Framework, NHibernate etc.), es la capa que realiza la lógica empresarial y se comunica con la base de datos subyacente. Observe cómo el modelo no es System.Web.Mvc espacio de nombres. Cuando haya terminado el controlador mediante el modelo, se crea una vista, proporcionando la vista con datos de modelo para la vista al representar el resultado.

En las secciones siguientes, le guiará a través el proceso de implementar un servicio completo marcador usando la arquitectura de ASP.NET MVC. El servicio admite varios usuarios y marcadores públicos y privados. Los usuarios pueden examinar todos los marcadores públicos y filtro basándose en el nombre de usuario o de etiquetas y pueden administrar completamente (CRUD) su propia colección de marcadores privados.

Para empezar, deberá crear un proyecto de ASP.NET MVC. Encontrará la plantilla de proyecto ASP.NET MVC Web Application en la lista de tipos de proyectos Web. La plantilla de proyecto predeterminado le ofrece una aplicación de inicio MVC de ejemplo que realmente puede ejecutar presionando F5.

Observe cómo la estructura de solución proporciona directorios para modelos, vistas y controladores, éste es el lugar donde coloque el código de estos componentes diferentes. La plantilla predeterminada viene con dos controladores: uno para la administración de cuentas de usuario (AccountController) y otro para admitir las solicitudes para el directorio particular (HomeController). Ambas se utilizan en el servicio de marcador.

Implementación del modelo

Lo primero que debe centrarse en es el modelo para el servicio de marcador. He creado una base de datos simple de SQL Server que contiene tres tablas para administrar la información de marcador, marcador, etiqueta y BookmarkTag (consulte la figura 2 ), y son bastante fácil de entender.

fig02.gif

Figura 2 marcador servicio LINQ al modelo SQL

La única salvedad es que el ejemplo depende del integradas ASP.NET formularios autenticación y la pertenencia a servicio, que proporciona el valor predeterminado AccountController suministrada con el proyecto administrar el usuario del servicio de cuentas, por lo tanto, se almacenará la información en una base de diferente datos (aspnetdb.mdf) independiente de la información de marcador de cuenta de usuario. El nombre de usuario simplemente se almacena en la tabla de marcador.

Es el trabajo del modelo para proporcionar objetos de negocio y lógica on top of la base de datos. En este ejemplo, he definido el LINQ al modelo SQL que se muestra en la figura 2 . Este modelo, definido en BookmarksModel.dbml, genera el código de C# que se encuentra en BookmarksModel.designer.cs. Encontrará clases denominadas marcador, etiqueta y BookmarkTag. También encontrará una clase BookmarksModelDataContext, que ejecuta un bootstrap las entidades.

En este momento, puede decidir trabajar directamente con el de LINQ to SQL clases como la capa de modelo MVC, o puede ir un paso más allá definiendo una clase de repositorio de nivel superior que define las operaciones de negocio lógicas y protege la vista o controlador de aún más los detalles de manipulación de datos subyacente. figura 3 muestra la definición de la clase BookmarksRepository utilizada en el servicio de marcador.

Figura 3 BookmarksRepository clase

public class BookmarksRepository
{
    // generated Linq to SQL DataContext class
    BookmarksModelDataContext db = new BookmarksModelDataContext();

    // query methods
    public IQueryable<Bookmark> FindAllBookmarks() { ... }
    public IQueryable<Bookmark> FindAllPublicBookmarks() { ... }
    public IQueryable<Bookmark> FindBookmarksByUser(string username)  { ... }
    public IQueryable<Bookmark> FindPublicBookmarksByUser(string username) { ... }
    public IQueryable<Bookmark> FindBookmarksByTag(string tag) { ... }
    public Bookmark FindBookmarkById(int id) { ... }
    public IQueryable<string> FindUsers(){ ... }
    public IQueryable<Tag> FindTags() { ... }
    public Tag FindTag(string tag) { ... }

    // insert/delete methods
    public void AddBookmark(Bookmark bm) { ... }
    public void AddTag(Tag t) { ... }
    public void AddTagForBookmark(string tagText, Bookmark bm) { ... }
    public void DeleteBookmark(Bookmark bm) { ... }

    // persistence
    public void Save() { ... }
}

Implementar el controlador

El controlador es el fragmento de código responsable de administrar el ciclo de solicitud HTTP. Cuando llega una solicitud, el motor de enrutamiento de ASP.NET MVC determina qué controlador utilizar (según la dirección URL) y, a continuación, enruta la solicitud al controlador llamando a un método específico en él. Por lo tanto, cuando escribe un controlador, que escribe los puntos de entrada que será llamados por el motor de enrutamiento.

El servicio de marcador, desea permitir que los usuarios autenticados crear, editar y eliminar marcadores. Al crear los marcadores, los usuarios podrán marcarlos como público (compartido) o privado. Todos los usuarios deberían poder examinar marcadores públicos y filtrarlos por nombre de usuario o etiquetas. Marcadores privados, sin embargo, deberían estar visibles sólo para el propietario. Los consumidores también podrá recuperar los detalles de un marcador determinado, suponiendo que están autorizados a hacerlo. Se debe también hacen posible examinar todos los usuarios y las etiquetas en el sistema como forma de desplazarse por los marcadores públicos asociados con ellas.

figura 4 muestra los métodos de que la clase BookmarkController necesita admitir los requisitos de servicio que Acabo de describir. Los métodos de tres consulta primero permiten recuperar todos los marcadores públicos, los marcadores por usuario o los marcadores por etiqueta. La clase también incluye métodos para recuperar los usuarios y las etiquetas y para recuperar los detalles de una instancia de marcador específico. Todos estos métodos responden a solicitudes HTTP GET, pero cada uno de ellos se enlazará a una plantilla URI diferente cuando se definen las rutas.

Figura 4 BookmarkController clase

[HandleError]
public class BookmarkController : Controller
{
    // underlying model
    BookmarksRepository bmRepository = new BookmarksRepository();

    // query methods
    public ActionResult BookmarkIndex() { ... }
    public ActionResult BookmarksByUserIndex(string username) { ... }
    public ActionResult BookmarksByTagIndex(string tag) { ... }
    public ActionResult UserIndex() { ... }
    public ActionResult TagIndex() { ... }
    public ActionResult Details(int id) { ... }

    // create boomark
    [Authorize]
    public ActionResult Create() { ... }
    [Authorize]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(FormCollection collection) { ... }

    // update bookmark    
    [Authorize]
    public ActionResult Edit(int id) { ... }
    [Authorize]
    [AcceptVerbs(HttpVerbs.Put | HttpVerbs.Post)]
    public ActionResult Edit(int id, FormCollection collection)

    // delete bookmark
    [Authorize]
    public ActionResult Delete(int id) { ... }
    [Authorize]
    [AcceptVerbs(HttpVerbs.Delete | HttpVerbs.Post)]
    public ActionResult Delete(int id, FormCollection collection) { ... }
}

El resto de los métodos son para crear, modificar y eliminar instancias de marcador. Observe que hay dos métodos para cada operación lógica, uno para recuperar el formulario de entrada y otro para responder al envío del formulario, y cada uno de estos métodos requiere autorización. El atributo de autorizar garantiza que el llamador es autenticado y autorizado para tener acceso el método de controlador. (El atributo también permite especificar los usuarios y funciones.) Si un usuario no autenticado o no autorizado intenta tener acceso a un método de controlador anotado con [autorizar], el filtro de autorización redirige automáticamente al usuario al método de inicio de sesión del AccountController, que presenta la vista de "Logon" al consumidor.

Utilice el atributo de AcceptVerbs para especificar qué verbos HTTP que controlará un método de controlador en particular (el valor predeterminado es GET). Un solo método puede controlar varios verbos por ORing los valores de HttpVerb juntos. El motivo que ha enlazado el segundo método Edit a PUT y POST es para acomodar exploradores. Esta configuración permite que los exploradores invocar la operación mediante POST, mientras nonbrowser consumidores pueden utilizar PUT (que es más correcta). He hecho algo similar en el segundo método Delete, enlazarlo a DELETE y POST. Sigo teniendo cuidado de que mis implementaciones de método garantizar idempotencia, que es un requisito para PUT y DELETE.

Echemos un vistazo a cómo se han implementado algunos de estos métodos. En primer lugar es BookmarkIndex:

public ActionResult BookmarkIndex()
{
    var bms = bmRepository.FindAllPublicBookmarks().ToList();
    return View("BookmarkIndex", bms);
}

Esta implementación simplemente recupera la lista de entidades públicas de marcador desde el repositorio y a continuación, devuelve una vista denominada BookmarkIndex (pasando en la lista de entidades de marcador). La vista es responsable de mostrar la lista de entidades de marcador proporcionó el controlador.

El método Details, se busca el marcador de destino y devuelve un error 404 no encontrado si no existe. A continuación, se asegura de que el usuario está autorizado para ver el marcador. Si es así, devuelve la vista de detalles, proporcionando la entidad de marcador identificada. En caso contrario, devuelve una respuesta no autorizada al consumidor.

public ActionResult Details(int id)
{
    var bm = bmRepository.FindBookmarkById(id);
    if (bm == null)
        throw new HttpException(404, "Not Found");
    if (!bm.Shared)
    {
        if (!bm.Username.Equals(HttpContext.User.Identity.Name))
            return new HttpUnauthorizedResult();
    }
    return View("Details", bm);
}

Como último ejemplo, veamos los dos métodos de crear. El primero es realmente bastante sencillo, vuelve a crear vista para presentar la descripción del formulario para crear un nuevo marcador:

[Authorize]
public ActionResult Create()
{
    return View("Create");
} 

la figura 5 muestra el segundo método Create, que responde a la solicitud de envío de formulario. Crea una nueva entidad de marcador de la información marcador que se encuentra en el objeto ColecciónFormulario entrante y, a continuación, se guarda en la base de datos. También actualiza la base de datos con las etiquetas nuevas que se han asociado con el marcador y redirecciona a los usuarios a sus listas de personales marcadores para indicar el éxito.

Figura 5 el método que responda a una solicitud de envío de formulario Create

[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
    try
    {
        Bookmark bm = new Bookmark();
        bm.Title = collection["bookmark-title"];
        bm.Url = collection["bookmark-url"];
        bm.Shared = collection["bookmark-shared"].Contains("true");
        bm.LastModified = DateTime.Now;
        bm.Username = HttpContext.User.Identity.Name;
        bm.Tags = collection["bookmark-tags"];

        bmRepository.AddBookmark(bm);
        bmRepository.Save();

        ... // create any new tags that are necessary

        return RedirectToAction("BookmaryByUserIndex", 
            new { username = HttpContext.User.Identity.Name });
    }
    catch
    {
        return View("Error");
    }
}

No hay espacio para tratar la implementación de controlador de todo, pero estos ejemplos de código deben dar una idea para el tipo de código que escribe en el controlador.

Diseñar URI con rutas

Lo siguiente que debe hacer es definir rutas de dirección URL que se asignan a los diversos métodos BookmarkController. Defina sus rutas de aplicación en global.asax dentro del método RegisterRoutes. Cuando se crea primero un proyecto MVC, su global.asax contendrá el código de enrutamiento de predeterminada que se muestra en la figura 6 .

Figura 6 predeterminado código enrutamiento

public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",                             // Route name
            "{controller}/{action}/{id}",          // URL with parameters
            new { controller="Home",               // Parameter defaults
                   action="Index", id="" } 
        );

    }

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }
}

La única llamada a MapRoute crea una regla de enrutamiento predeterminada que actúa como un catchall para todos los identificadores URI. Esta ruta describe que el primer segmento de ruta de acceso representa el nombre del controlador, el segundo segmento de ruta de acceso representa el nombre de acción (método de controlador) y el tercer segmento de ruta de acceso representa un valor de ID. Esta regla única puede controlar a los identificadores siguientes y enrutar al método de controlador apropiado:

/Account/Logon
/Bookmark/Create
/Bookmark/Details/25
/Bookmark/Edit/25

figura 7 muestra las rutas que utilizo para este ejemplo de servicio marcador. Con estas rutas adicionales en su lugar, pueden examinar los consumidores "/ a los usuarios" recuperar la lista de usuarios,"/ etiquetas" para recuperar la lista de etiquetas, o "/ marcadores" para recuperar la lista de marcadores públicos. Los consumidores también pueden desplazarse a "/tags/ {tagname}" o "/users/ {username}" a los marcadores de filtro por etiqueta o nombre de usuario, respectivamente. Todos los otros identificadores URI se controlan mediante la ruta predeterminada se muestra en la figura 6 .

Figura 7 marcador servicio rutas

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    // customer routes
    routes.MapRoute("Users", "users",
        new { controller = "Bookmark", action = "UserIndex" });
    routes.MapRoute("Tags", "tags",
        new { controller = "Bookmark", action = "TagIndex" });
    routes.MapRoute("Bookmarks", "bookmarks",
        new { controller = "Bookmark", action = "BookmarkIndex" });
    routes.MapRoute("BookmarksByTag", "tags/{tag}",
        new { controller = "Bookmark", action = "BookmarksByTagIndex", tag = "" });
    routes.MapRoute("BookmarksByUser", "users/{username}",
        new { controller="Bookmark", action="BookmarksByUserIndex", username="" });
    // default route
    routes.MapRoute("Default", "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = ""});
}

Implementación de las vistas

Llegados a este punto, la mayor parte de lo que hemos hecho se aplica a MVC "sitios" y "servicios". Todas las aplicaciones de MVC necesitan modelos, controladores y las rutas. La mayoría de las diferentes sobre la creación de MVC "servicios" se encuentra en la vista. En lugar de producir una vista HTML tradicional para consumo humano, un servicio debe producir una vista que sea apropiada para el consumo humano y mediante programación.

Vamos a utilizar XHTML para nuestra representación de servicio predeterminado y aplicar las técnicas descritas anteriormente para asignar datos de marcador a XHTML. Se le asignan entidades de datos a <div> y elementos <span> y se le representan colecciones utilizando una combinación de <ol> y <li>. También se podrá anotar estos elementos con el atributo "class" para proporcionar a los consumidores con metadatos de tipo adicionales.

ASP.NET MVC "vistas" son sólo las páginas .aspx que define una plantilla de vista. Las páginas .aspx se organizan por nombre de controlador dentro del directorio de vistas. Cada vista se puede asociar con una página principal de ASP.NET para mantener una plantilla coherente. la figura 8 muestra la página principal para el servicio de marcador.

Figura 8 principales del servicio marcador página

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html >
<head runat="server">
    <title><asp:ContentPlaceHolder ID="Title" runat="server" /></title>
</head>
<body>
    <div style="text-align:right">
        <% Html.RenderPartial("LogOnUserControl"); %>
    </div>
    <h1><asp:ContentPlaceHolder ID="Heading" runat="server" /></h1>
    <hr />
    <asp:ContentPlaceHolder ID="MainContent" runat="server" />
    <hr />
    <div class="nav-links-footer">
        <%=Html.ActionLink("Home", "Index", "Home", null, 
           new { @class = "root-link" } )%> |
        <%=Html.ActionLink("Public Bookmarks", "BookmarkIndex", "Bookmark", null, 
           new { @class = "public-bookmarks-link" } )%> |
        <%=Html.ActionLink("User Bookmarks", "BookmarksByUserIndex", "Bookmark", 
           new { username = HttpContext.Current.User.Identity.Name }, 
           new { @class = "my-bookmarks-link" })%> |
        <%=Html.ActionLink("Users", "UserIndex", "Bookmark", null, 
           new { @class = "users-link" } )%> |
        <%=Html.ActionLink("Tags", "TagIndex", "Bookmark", null, 
           new { @class = "tags-link" } )%> 
    </div>    
</body>
</html>

La página maestra define tres marcadores de posición: uno para el título de página, otro para el encabezado <h1> y otro para el área de contenido principal. Cada vista individual se rellenará estos marcadores de posición. Además, la página principal muestra un control de inicio de sesión en la parte superior de la página y proporciona un pie de página que contiene los vínculos de servicio de raíz para simplificar la exploración. Observe cómo Estoy utilizando el método HTML.ActionLink para generar estos vínculos según las rutas predefinidas y controlador de acciones.

figura 9 muestra la vista de índice de marcador principal que obtendrá cuando vaya a "/ marcadores". Muestra la lista de marcadores mediante una combinación de <ol>, <li>, <a> elementos y. Los elementos de <ol> se anotan con clase = "marcador-lista", y cada elemento <a> se anota con clase = "vínculo marcador". Esta vista también proporciona un vínculo para recuperar la descripción del formulario Crear marcador (derecho sobre la lista). Si se desplaza al vínculo, la vista de crear que se muestra en la figura 10 entra en acción.

Figura 9 vista de índice de marcador

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.
Master" Inherits="System.Web.Mvc.ViewPage
<IEnumerable<MvcBookmarkService.Models.Bookmark>>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="Title" runat="server">
Public Bookmarks</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Heading" runat="server">
Public Bookmarks</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
    <%= Html.ActionLink("Create bookmark", "Create", "Bookmark", new { id = "" },
           new { @class = "create-bookmark-form-link" } )%>
    <ol class="bookmark-list">
        <% foreach (var item in Model) { %>
            <li><%= Html.ActionLink(Html.Encode(item.Title), "Details", "Bookmark", 
                    new { id = item.BookmarkID }, new { @class = "bookmark-link" })%></li>
        <% } %>        
    </ol>
</asp:Content>

Figura 10 marcador crear vista

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<MvcBookmarkService.Models.Bookmark>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="Title" runat="server">
Create Bookmark</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Heading" runat="server">
Create Bookmark</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
    <% using (Html.BeginForm("Create", "Bookmark", FormMethod.Post, 
       new { @class = "create-bookmark-form" } ))
       {%>
        <p>
            <label for="Title">Title:</label><br />
            <%= Html.TextBox("bookmark-title")%>
        </p>
        <p>
            <label for="Url">Url:</label><br />
            <%= Html.TextBox("bookmark-url")%>
        </p>
        <p>
            <label for="Tags">Tags:</label><br />
            <%= Html.TextBox("bookmark-tags")%>
        </p>
        <p>
            <label for="Shared">Share with public: </label>
            <%= Html.CheckBox("bookmark-shared")%>
        </p>
        <p>
            <input type="submit" value="Create" name="submit" />
        </p>
    <% } %>
</asp:Content>

Crear vista produce un sencillo formulario XHTML, pero el elemento <form> se anota con clase = "Crear-marcador-formulario", y cada elemento <input> se le ha dado un valor de identificador de nombre contextuales que identifica cada campo de marcador. Este formulario ofrece a los consumidores una descripción de XHTML completa de cómo crear mediante programación un nuevo marcador mediante nuestro servicio (simplemente envía el formulario).

Un último ejemplo figura 11 muestra el principio de la vista de detalles de marcador. Aquí Estoy utilizando un elemento <div> para representar la estructura de marcador (clase = "marcador") junto con <span> y <a> elementos para representar los campos de marcador. Cada uno de ellos lleva a un atributo "class" para especificar el nombre del campo.

Ver detalles de la figura 11 marcador

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
   Inherits="System.Web.Mvc.ViewPage<MvcBookmarkService.Models.Bookmark>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="Title" runat="server">
Bookmark Details: <%= Model.BookmarkID %></asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="Heading" runat="server">
Bookmark Details: <%= Model.BookmarkID %></asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
    <br />
    <div class="bookmark">
     BookmarkID: <span class="bookmark-id"><%= Html.Encode(Model.BookmarkID) %></span><br />
     Title: <span class="bookmark-title"><%= Html.Encode(Model.Title)    %></span><br />
     Url: <a class="bookmark-url-link" href="<%= Html.Encode(Model.Url) %>">
     <%= Html.Encode(Model.Url) %></a><br />
     Username: <%=Html.ActionLink(Model.Username, "BookmarksByUserIndex", "Bookmark", 
     new { username=Model.Username }, new { @class="bookmark-username-link" }) %><br />
...

De nuevo, no tengo espacio para que examine todos los ejemplos de vista de detalle, pero espero que esto ilustra cómo puede producir limpias conjuntos de resultados XHTML que son fáciles para aplicaciones y los seres humanos consumir.

Consumir el servicio de marcador

La forma más fácil de consumir el servicio de marcador es a través de un explorador Web. Gracias al diseño XHTML, debe poder vaya a la dirección URL de raíz del servicio y empezar a exploración desde allí. figura 12 muestra qué aspecto el explorador cuando vaya a la raíz del servicio marcador y sesión. Puede hacer clic en pública marcadores para desplazarse a la lista de todos los marcadores públicos y, a continuación, desplazarse a un marcador específico en la lista. Si hace clic en Edición, realmente puede editar los detalles de marcador (consulte la figura 13 ). El servicio está totalmente utilizable desde cualquier explorador Web.

fig10.gif

Figura 12 examen para el servicio de marcador MVC

fig13.gif

Figura 13 modificar un marcador específico

Mientras estás explorando alrededor del servicio, seleccione Ver código fuente ocasionalmente en el explorador, y observará sencillos los resultantes XHTML es, que nuevo facilita para programar.

figura 14 muestra el código para una completa aplicación de cliente .NET que consume el servicio de marcador. Utiliza el conjunto de métodos de extensión XLinq que describí anteriormente para simplificar la XHTML y detalles de procesamiento de HTTP. Lo interesante de este ejemplo es más actúa como una persona, que necesita la raíz URI que se vaya a todos los elementos de interés expuestos por el servicio de marcador.

Figura 14 escribir un cliente .NET para consumir el servicio de marcador mediante XLinq

class Program
{
    static void Main(string[] args)
    {
        // navigate to the root of the service
        Console.WriteLine("Navigating to the root of the service...");
        Uri uri = new Uri("http://localhost:63965/");
        CookieContainer cookies = new CookieContainer();
        var doc = XDocument.Load(uri.ToString());
        doc.AddAnnotation(uri);

        // navigate to public bookmarks
        Console.WriteLine("Navigating to public bookmarks...");
        var links = doc.Body().Ul("nav-links").Lis();
        var bookmarksLink = links.Where(l => l.HasAnchor("public-bookmarks-link")).First();
        var bookmarksDoc = bookmarksLink.Anchor().Navigate();
        bookmarksDoc.AddAnnotation(cookies);

        // display list of bookmarks
        Console.WriteLine("\nPublic bookmarks found in the system:");
        var bookmarks = bookmarksDoc.Body().Ol("bookmark-list").Lis();
        bookmarks.Each(bm => Console.WriteLine("{0}: {1}",
            bm.Anchor().AnchorText, bm.Anchor().AnchorLink));

        // navigate to the first bookmark in the list
        Console.WriteLine("\nNavigating to the first bookmark in the list...");
        var bookmarkDoc = bookmarks.First().Anchor().Navigate();
        var bookmarkDetails = bookmarkDoc.Body().Struct("bookmark");

        // print the bookmark details out to the console window
        Console.WriteLine("Bookmark details:");
        Console.WriteLine("bookmark-id: {0}", bookmarkDetails["bookmark-id"].Value);
        Console.WriteLine("bookmark-url-link: {0}", 
            bookmarkDetails["bookmark-url-link"].Value);
        Console.WriteLine("bookmark-title: {0}", bookmarkDetails["bookmark-title"].Value);
        Console.WriteLine("bookmark-shared: {0}", bookmarkDetails["bookmark-shared"].Value);
        Console.WriteLine("bookmark-last-modified: {0}", 
            bookmarkDetails["bookmark-last-modified"].Value);

        // retrieving login form
        Console.WriteLine("\nRetrieving login form...");
        Uri logonUri = new Uri("http://localhost:63965/Account/Logon");
        var logonDoc = XDocument.Load(logonUri.ToString());
        logonDoc.AddAnnotation(logonUri);
        logonDoc.AddAnnotation(cookies);

        // logging on as skonnard
        Console.WriteLine("Logging in as 'skonnard'");
        var logonForm = logonDoc.Body().Form("account-logon-form");
        logonForm["username"] = "skonnard";
        logonForm["password"] = "password";
        logonForm.Submit();
        Console.WriteLine("Login successful!");

        // create a new bookmark as 'skonnard'
        var createBookmarkDoc = bookmarksDoc.Body().Anchor(
            "create-bookmark-form-link").Navigate();
        createBookmarkDoc.AddAnnotation(cookies);
        var createBookmarkForm = createBookmarkDoc.Body().Form("create-bookmark-form");
        createBookmarkForm["bookmark-title"] = "Test from console!";
        createBookmarkForm["bookmark-url"] = "https://live.com/";
        createBookmarkForm["bookmark-tags"] = "Microsoft, Search";
        createBookmarkForm.Submit();
        Console.WriteLine("\nBookmark created!");
    }
}

El cliente se inicia desplazándose a la dirección de raíz y, a continuación, busca el vínculo a los marcadores públicos.A continuación se desplaza a la lista marcador pública y identifica un marcador específico de interés (en este caso, primero).A continuación se desplaza a los detalles de marcador y los muestra en la ventana de consola.A continuación, recupera el formulario de inicio de sesión y realiza un inicio de sesión mediante un conjunto de credenciales.Una vez iniciada la sesión, la aplicación recupera el formulario de marcador de crear, cumplimenta y envía un nuevo marcador para el sistema.

Hay unas cuantas observaciones clave que en este momento.En primer lugar, la aplicación de consola es capaz de hacer lo mismo que una persona a través del explorador Web.Es la característica de uso masivo de este estilo de diseño XHTML.En segundo lugar, los consumidores sólo tiene que ser rígida contra la URI expuestos por el servicio de raíz.Todos los otros identificadores URI están reconocible en tiempo de ejecución desplazándose vínculos encontrados en el XHTML.Y por último, procesamiento de las estructuras XHTML no que muy diferentes de nada, es que sólo los datos.Además, este tipo de código sólo obtiene más fácil cuando se mueven hacia lenguajes dinámicos en futuras versiones de .NET.

Finalmente, ASP.NET MVC proporciona un marco intrínsecamente RESTful para implementar un sitio web de recursos basado en XHTML que puede ser utilizado simultáneamente por los humanos y aplicaciones.Puede descargar la aplicación de ejemplo completo que se muestra en este artículo desde el sitio Web de MSDN Magazine.

Para obtener otro ejemplo completo de un servicio RESTful basado en XHTML que se encuentra en el mundo real, busque elPublicación de servicios de contenido de sistema (MTPS) de Microsoft/TechNet. Este servicio utiliza muchas de las prácticas que ha descrito en este artículo.

Confirmaciones

Gracias a Tim Ewald y Craig Andera cuyo creative pensar en esta área proporciona combustible para mi artículo.Tim también proporciona los métodos de extensión XLinq que se encuentra en la aplicación de ejemplo que lo acompaña.

Aaron Skonnard es cofundador de Pluralsight, un proveedor de formación de Microsoft ofrece dos cursos de desarrollador impartido por un instructor y a petición.Estos días Aaron dedica la mayor parte de su tiempo de grabación a petición de Pluralsight!cursos se centró en equipos de la nube, Azure de Windows, WCF y REST.Puede ponerse enhttp://pluralsight.com/Aaronyhttp://Twitter.com/Skonnard.