Il presente articolo è stato tradotto automaticamente.
OData e AtomPub
Creazione di un server AtomPub mediante WCF Data Services
Chris Sells
Scaricare il codice di esempio
Se non si ha familiarità con esso, il protocollo Open (OData) è una cosa di bellezza. Generazioni OData (descritto in dettaglio in odata.org ) sull'adeguatezza basato su HTTP di Atom per la pubblicazione di dati; AtomPub per la creazione, l'aggiornamento e l'eliminazione di dati e Microsoft Entity Data Model (EDM) per la definizione dei tipi di dati.
Se si dispone di un client JavaScript, è possibile ottenere i dati back direttamente in JSON anziché in formato Atom, e se avete un altro, ad esempio Excel, Microsoft .NET Framework, PHP, AJAX e più, esistono librerie client per formare OData richieste e l'utilizzo delle risposte OData. Se si utilizza .NET Framework sul lato server, Microsoft offre anche una libreria di facile utilizzo denominato WCF Data Services per esporre i tipi .NET Framework o di database supportati da Microsoft Entity Framework come origini OData. Questo semplice per esporre i dati attraverso Internet in modo basato su HTTP e standard.
Tutto questo detto, esistono alcune operazioni da eseguire con OData non sono abbastanza parte dell'esperienza-box, quali l'integrazione OData esistente basato su Atom e AtomPub lettori e scrittori. Ecco cosa ci concentreremo sperimentare.
Un Blog semplice
Ad esempio, immaginiamo let’s che la creazione di un sistema semplice blog (e in realtà questo lavoro si basa su me riscrittura del sistema di gestione dei contenuti su sellsbrothers.com). Sono un grande fan del primo modello di supporto in Visual Studio 2010, pertanto è stato creato un progetto ASP.NET MVC 2.0, aggiunto un EDM ADO.NET file denominato MyBlogDB.edmx e disposti a un'entità di post, come illustrato in di Figura 1.
Figura 1 A Post entità create in Visual Studio 2010
Software di blog più complicato utile registrare ulteriori dati, ma i campi di Figura 1 sono le nozioni di base. Quando scelta nell'area di progettazione, scegliere Genera dal modello di database, che mostra il file SQL che verrà creato per me (MyBlogDB.sql in questo caso) e SQL che verranno generati per la creazione del database. Facendo clic su Fine verrà creare file SQL e associare il database per le entità creata nella finestra di progettazione dell'EDM. Nella di Figura 2 vengono illustrati i bit importanti di SQL.
Figura 2 del codice SQL causando da “ genera database dal modello ”
...
USE [MyBlogDB];
GO
...
-- Dropping existing tables
IF OBJECT_ID(N'[dbo].[Posts]', 'U') IS NOT NULL
DROP TABLE [dbo].[Posts];
GO
...
-- Creating table 'Posts'
CREATE TABLE [dbo].[Posts] (
[Id] int IDENTITY(1,1) NOT NULL,
[Title] nvarchar(max) NOT NULL,
[PublishDate] datetime NULL,
[Content] nvarchar(max) NOT NULL
);
GO
...
-- Creating primary key on [Id] in table 'Posts'
ALTER TABLE [dbo].[Posts]
ADD CONSTRAINT [PK_Posts]
PRIMARY KEY CLUSTERED ([Id] ASC);
GO
In sostanza, abbiamo semplicemente stiamo creando una singola tabella dal nostro singola entità, come previsto e mapping campi di tipi SQL. Si noti che il PublishDate è impostato su NULL, che non è l'impostazione predefinita. È stato esplicitamente scelto tale impostazione nella finestra di progettazione EDM perché volevo essere OK non per una data di pubblicazione (alcuni strumenti non forniscono uno per impostazione predefinita).
Per eseguire questo SQL e il database creato è solo questione di facendo doppio clic su SQL nell'editor di testo di Visual Studio e scegliendo Esegui SQL. Verrà richiesto per le informazioni di connessione e il nome del database. Poiché si tratta di un nuovo database, sarà necessario digitare il nuovo nome, ad esempio MyBlogDB e scegliere OK per crearlo quando richiesto. Quando il database è stato creato, è possibile esplorare in Esplora Server sotto la connessione che Visual Studio ha creato automaticamente.
Per effettuare operazioni di testing, è possibile aggiungere dati direttamente nella tabella facendo doppio clic su POST e scegliere Mostra dati tabella, che fornirà una piccola griglia, come illustrato in di Figura 3.
Figura 3 la tabella dati Mostra griglia rende operazioni di testing
Esso non la migliore modifica in tutto il mondo, ma è meglio di scrittura di istruzioni SQL fino a quando abbiamo una soluzione modifica end-to-end e l'esecuzione (è entrata, continuare la lezione!).
Ora che abbiamo alcuni dati, possiamo fare un po' di ASP.NET in codice per mostrare aggiornando HomeController.cs (ulteriori informazioni su MVC in asp.net/mvc/ ):
...
namespace ODataBloggingSample.Controllers {
[HandleError]
public class HomeController : Controller {
MyBlogDBContainer blogDB = new MyBlogDBContainer();
public ActionResult Index() {
return View(blogDB.Posts);
}
public ActionResult About() {
return View();
}
}
}
Tutti ho fatto qui è stato creato un'istanza della classe MyBlogDBContainer, ovvero la classe derivata da ObjectContext principale creata dal nostro file MyBlogDB.edmx per farci accesso il nuovo database. (Se non si ha familiarità con Entity Framework, è necessario: vedere msdn.com/data/aa937723 ). Quando viene chiamato il metodo indice sulla classe HomeController, qualcuno sta richiedendo la home page della nostra nuova applicazione Web che si desidera utilizzare per visualizzare i nuovi post di blog in modo che abbiamo indirizzare all'insieme di inserimenti dal database a un'istanza della visualizzazione Home/Index.aspx, che è stato modificato come segue:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<ODataBloggingSample.Post>>" %>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<% foreach (var post in Model) { %>
<h1><%= post.Title %></h1>
<div><%= post.Content %></div>
<p><i>Posted <%= post.PublishDate %></i></p>
<% } %>
</asp:Content>
Qui abbiamo modificato la classe base per richiedere un insieme di tipo post generato (con la classe MyBlogDBContainer) per modellare la nostra tabella post. È stato sostituito la home page di contenuto con un'istruzione foreach per visualizzare titolo del ogni post, contenuto e la data di pubblicazione.
Non che è necessario. Ora quando si esegue il progetto (Debug | Avvia debug), viene avviato il browser e sono riportati i post di blog (solo una registrazione, a meno che non si sono inseriti più di che nel database), come illustrato in di Figura 4.
Figura 4 della pagina Web completata
Ora, detto tutto fino a questo punto in modo che potesse individuare è questo: Il motivo che è così favolosi OData è che, con un gesto rapido della mio mouse e due shakes della mia tastiera, è possibile esporre un'interfaccia di programmazione completa per i dati che è possibile accedere da JavaScript, .NET Framework, PHP e altro ancora. Per visualizzare questa chiave accadere, fare doppio clic sul progetto in Esplora soluzioni, scegliere Aggiungi | nuovo elemento, scegliere servizio WCF data, scegliere un nome (utilizzato odata.svc) e fare clic su Aggiungi. Si otterrà è un frammento di codice in un file (in questo caso odata.svc.cs) scheletro che, ignorando protezione solo ora, vorremmo conferire un aspetto simile al seguente:
using System.Data.Services;
using System.Data.Services.Common;
using ODataBloggingSample;
namespace ODataBloggingSample {
public class odata : DataService<MyBlogDBContainer> {
public static void InitializeService(DataServiceConfiguration config) {
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
}
}
}
Si noti che è stata generata in MyBlogDBContainer, ovvero la classe di accesso database principale, ovvero come parametro di template di classe DataService, che è il nucleo del lato server WCF Data Services (vedere msdn.com/data/bb931106 ). La classe DataService consente di esporre facilmente il database tramite HTTP basata sul verbo creare, leggere, aggiornare ed eliminare operazioni (CRUD) definite nel protocollo OData. Il tipo passato il DataService viene esaminato per proprietà pubbliche che espongono insiemi. Nel nostro esempio, la classe del contesto oggetto generato Entity Framework contiene l'insieme di post che si adatta bene distinta base:
...
namespace ODataBloggingSample {
...
public partial class MyBlogDBContainer : ObjectContext {
...
public ObjectSet<Post> Posts {...}
...
}
...
public partial class Post : EntityObject {
...
public global::System.Int32 Id { get { ... } set { ... } }
public global::System.String Title { get { ... } set { ... } }
public Nullable<global::System.DateTime> PublishDate {
get { ... } set { ... } }
public global::System.String Content { get { ... } set { ... } }
...
}
}
Si noti che MyBlogDBContainer generata espone un ObjectSet (che è semplicemente un tipo di insieme) chiamato post che contiene le istanze di tipo post. Inoltre, viene definito il tipo di post per fornire il mapping tra ID, title, PublishDate e le proprietà contenute nelle colonne sottostanti nella tabella post creati in precedenza.
Con odata.svc posto, è possibile navigare nel documento di servizio espone la proprietà di insieme contesto oggetto utilizzando il nome del file di endpoint del servizio dati nell'URL, ad esempio localhost:54423/odata.svc:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<service xml:base="http://localhost:54423/odata.svc/" xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
<workspace>
<atom:title>Default</atom:title>
<collection>
<atom:title>Posts</atom:title>
</collection>
</workspace>
</service>
L'intero file viene definito dalla specifica AtomPub (ietf.org/rfc/rfc5023.txt ). Richiede un livello più profondo, possiamo vedere il post esposte come un insieme di voci Atom in localhost:54423/odata.svc/Posts, come illustrato in di Figura 5.
Figura 5 POST esposte come un insieme di voci Atom
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed xml:base="http://localhost:54423/odata.svc/"
xmlns:d="https://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m=
"https://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom">
<title type="text">Posts</title>
<id>http://localhost:54423/odata.svc/Posts</id>
<updated>2010-03-15T00:26:40Z</updated>
<link rel="self" title="Posts" href="Posts" />
<entry>
<id>http://localhost:54423/odata.svc/Posts(1)</id>
<title type="text" />
<updated>2010-03-15T00:26:40Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Post" href="Posts(1)" />
<category term="MyBlogDB.Post"
scheme=
"https://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:Id m:type="Edm.Int32">1</d:Id>
<d:Title>My first blog post</d:Title>
<d:PublishDate m:type=
"Edm.DateTime">2010-03-14T00:00:00</d:PublishDate>
<d:Content>Hi! How are you?</d:Content>
</m:properties>
</content>
</entry>
</feed>
Questo file è quasi completamente in considerazione normale Atom (ietf.org/rfc/rfc4287.txt ), fatta eccezione per gli URI basato su Microsoft utilizzati a livello di funzionalità OData in Atom. In particolare, è opportuno notare l'elemento “ proprietà ” all'interno dell'elemento “ contenuto ”. Queste proprietà riconoscibile come gli stessi definiti precedenza nelle entità post e tabella post corrispondente. Questi dati sono contenuti nella busta definito da Atom e vengono esposte tramite commenti CRUD gli stessi sono definiti da AtomPub e
consentono di creare, lettura, aggiornamento ed eliminazione tramite i metodi HTTP POST, GET, PUT e DELETE, rispettivamente. Il problema è che non è abbastanza normale-semplicemente-Atom sufficienti. Ad esempio, navigare in a odata.svc/Posts in un lettore Atom, come Internet Explorer 8, il titolo e contenuto Don ’t forniti correttamente, come illustrato in di Figura 6.
Figura 6 visualizzazione post di Blog in lettura Atom indica che il titolo e contenuto siano mancanti
È possibile vedere che i dati siano presenti (si noti la data è corretto ed è visualizzata la categoria) ma il titolo e il contenuto non sono visibili. Perché le posizioni in cui Internet Explorer è alla ricerca per titolo e contenuto, gli elementi “ contenuti ” in ogni voce e “ titolo ” abbastanza logicamente, non contengono prevede sia presente. L'elemento “ titolo ” è vuoto e l'elemento “ contenuto ” è in un formato che Internet Explorer non riconosce. Il formato Internet Explorer piacerebbe davvero vedere ha il seguente aspetto:
<feed ...>
<title type="text">Posts</title>
<id>http://localhost:54423/atompub.svc/Posts</id>
<updated>2010-03-15T00:42:32Z</updated>
<link rel="self" title="Posts" href="Posts" />
<entry>
<id>http://localhost:54423/atompub.svc/Posts(1)</id>
<title type="text">My first blog post</title>
<updated>2010-03-15T00:42:32Z</updated>
...
<content type="html">Hi! How are you?</content>
<published>2010-03-14T00:00:00-08:00</published>
</entry>
</feed>
Si noti che l'elemento “ title ” è quello utilizzato per essere seppelliti nella proprietà titolo dall'elemento “ proprietà ” OData nell'elemento “ contenuto ” elemento “ contenuto ” è stato sovrascritto con la proprietà Content e dal valore della proprietà PublishDate è stato aggiunto l'elemento “ pubblicato ”. I dati visualizzati in Internet Explorer, si ottiene qualcosa di molto più come cosa ci piacerebbe avere, come illustrato in di Figura 7.
Figura 7 Modifica formato XML risultati in visualizzazione corretta del titolo e contenuto
È necessario ricordare che è solo per il supporto di strumenti di blog che si occupa anche. Internet Explorer non è previsto visualizzare un elenco di clienti o una fattura, è previsto visualizzare titoli e pubblicare contenuto HTML e date. Talvolta è utile per effettuare il mapping per cliente elenco e le fatture, nel qual caso Microsoft dispone di una funzionalità in WCF Data Services denominato “ nome feed ” (vedere blogs.msdn.com/astoriateam/archive/ 2008/09/28/making-feeds-friendly.aspx ). Abbastanza non tutti gli elementi, tuttavia (in particolare, esso non rimappare l'elemento “ contenuto ” Atom), poiché il team WCF Data Services desideri rendere sicuri anche “ descrittivo ” feed funzionano con varie librerie client. L'obiettivo è rendere i feed OData descrittivo, non abbandonare OData in favore di AtomPub/Atom.
In questo caso, comunque, stiamo abbandono OData e semplicemente utilizza WCF Data Services come l'endpoint AtomPub, che richiede un mapping tra Atom e OData, come illustrato in di Figura 8.
Figura 8 mapping tra Atom e OData
Il trucco è come si ottiene questo mapping si verifichi? Abbiamo ovviamente i dati, ma è necessario riassociare le proprietà Atom in modo che i lettori Atom (e gli autori) sappiano dove sono sicuro immediatamente i dati. A questo scopo infatti, WCF Data Services ancora effettuare il mapping per i tipi .NET Framework o tramite Entity Framework, i database. È sufficiente è un mapping alla porta minimo di Atom o AtomPub da OData.
Il codice di esempio fornito con questo articolo è parte del codice da inserire nella pipeline di WCF consente solo esattamente questo tipo di trasformazione dei dati dei messaggi. È possibile leggere a piacere (estrazione ODataBlogging.cs), ma ho intenzione di mostrare come utilizzarlo.
Innanzitutto, creare un nuovo endpoint WCF Data Services esattamente come era prima, ma con un nome diverso (utilizzato atompub.svc). Agganciare la classe del contesto di oggetto di primo livello ed esporre qualsiasi entità imposta è simile, esattamente come prima, ma anche tag al servizio di classe ODataBloggingServiceBehavior, come segue:
...
using ODataBlogging;
namespace ODataBloggingSample {
[ODataBloggingServiceBehavior(typeof(MyBlogDBContainer))]
[EntityAtomMapping("Posts", "PublishDate", "published")]
public class atompub : DataService<MyBlogDBContainer> {
public static void InitializeService(DataServiceConfiguration config) {
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
}
}
}
Ciò comporta il mapping da Atom o AtomPub in entrata, ad esempio “ titolo, ” “ contenuti ” e “ pubblicati ” elementi, ovvero a OData corrispondente formato tramite l'elemento “ proprietà ” nidificato all'interno dell'elemento “ contenuto ”. Per impostazione predefinita, se i nomi di entità corrispondono (ignorando i casi), quindi il mapping (e forzata) appena accadrà. Quando viene esposta un'entità che contiene una proprietà Title (come l'entità Post), viene mappato all'elemento “ titolo ” Atom.
D'altra parte, se non esiste alcun mapping automatico, è possibile ignorare tale comportamento fornendo un mapping esplicito in base al nome di entità, come abbiamo abbiamo fatto per associare la proprietà PublishDate per gli oggetti insieme “ post ” proprietà “ pubblicato ” atom. Questi due attributi sono sufficienti per attivare il nostro OData feed in un feed Atom, noi consentendo la visualizzazione completa dei dati come illustrato in di Figura 7.
Questo tipo di mapping non è unidirezionale, supporta tutti i metodi HTTP, è possibile utilizzare il protocollo AtomPub per creare, aggiornare ed eliminare gli elementi dell'insieme POST nonché leggerli. Ciò significa che è possibile configurare uno strumento come Windows Live Writer (WLW), che supporta AtomPub come un blog API, e utilizzarlo per la modifica di testo RTF di messaggi. Ad esempio, dato endpoint atompub.svc in WLW, è possibile scegliere i blog | Aggiungi account blog e specificare le opzioni seguenti nelle finestre di dialogo che seguono:
- Il servizio di blog che si utilizza. Altri servizi di blog
- Indirizzo Web del blog: http:// < server >>: << porta >> /atompub.svc
- Nome utente: < nomeutente >> (obbligatorio e deve essere implementata l'endpoint AtomPub utilizzando le tecniche standard HTTP)
- Password: < password >>
- Tipo di blog in uso: Protocollo di pubblicazione Atom
- URL del documento di assistenza: http:// < server >>: << porta >> /atompub.svc
- Nome alternativo del blog: << informato >>
Fare clic su Fine e avete un editor di testo RTF per la gestione dei post di blog, come illustrato in di Figura 9.
Figura 9 / Atom OData mapping agevola la creazione di un editor di testo RTF per la gestione dei post di Blog
Qui ci abbiamo preso il motore Data Services, che supporta tutte le funzionalità CRUD tramite le proprietà di trasporto nell'elemento “ contenuto ” Atom e hanno fatto un po' di mapping per supportare troppo semplice ol'ATOM e AtomPub.
Piccola libreria di esempio che consente di rendere questo lavoro (che è stato creato con Phani Raj, un software engineer presso Microsoft nel team WCF Data Services), non al minimo barest e non verrà mai essere sufficiente creare un blog reale. Ecco un elenco dalla parte superiore della mia testa che deve ancora effettivamente supportare solo Atom e AtomPub cose:
- Mapping sottoelementi dell'elemento di autore Atom, ad esempio il nome, l'uri e posta elettronica.
- La gestione delle immagini (sebbene WLW consente di FTP, in modo che sia sufficiente).
- Esposizione di funzionalità che WLW riconosca queste funzionalità.
Se si è interessati inserendo ulteriormente questo esperimento, Joe Cheng, un membro del team WLW ha scritto una serie di post del blog sul supporto AtomPub in WLW ispirato questo lavoro in primo luogo: jcheng.wordpress.com/2007/10/15/How-wlw-speaks-AtomPub-Introduction.
Buon lavoro.
Chris Sells è un program manager di Microsoft nella piattaforma Business Division. Ha scritto molti libri, tra cui “ ATL Internals ” (Addison-Wesley Professional, 1999) e “ programmatori WPF ” (O’Reilly Media, 2007), " Windows Forms 2.0 Programming" (Addison-Wesley Professional, 2006) con più autori. Nel tempo libero, egli ospita diverse conferenze e rende un pest del proprio account su elenchi di discussione team interno del prodotto Microsoft. Ulteriori informazioni sulle vendite e il suo progetti diversi, sono disponibili all'indirizzo sellsbrothers.com .
Grazie all'esperto di tecnica seguente per la revisione di questo articolo: Pablo Castro