Kontrakty vo WCF umožňujú vytváranie robustných služieb s minimálnym počtom väzieb (loosely coupled). V tejto časti seriálu sa pozrieme na programovanie rôznych typov WCF kontraktov.
reklama
Kontrakty vo WCF umožňujú vytváranie robustných služieb s minimálnym počtom väzieb (loosely coupled). V tejto časti seriálu sa pozrieme na programovanie rôznych typov WCF kontraktov.
V nadväznosti na minulú časť môžeme povedať, že kontrakt je jedna z častí ktoré tvoria endpoint (adresa, binding, kontrakt). Vo WCF máme 3 druhy kontraktov:
- kontrakty služieb - service contracts,
- kontrakty dát - data contracts,
- kontrakty správ - message contracts.
Service contract
Service contract popisuje operácie, ktoré môže služba vykonávať. Definujeme ho pridaním atribútu [ServiceContract] k deklarácii rozhrania alebo triedy. Operácie služby definujeme pridaním atribútu [OperationContract] k deklarácii metód rozhrania alebo triedy. Service contract predstavuje mapovanie CLR/WSDL. Okrajovo ešte spomeniem, že service contract môže byť typu request-response, one way alebo duplex. Príklad na service contract:
[ServiceContract]
public interface ILibrary
{
[OperationContract]
FindBooksResponse FindBooks(FindBooksRequest request);
[OperationContract]
void AddBook(Book book);
}
Data contract
Data contract popisuje štruktúru dát. Ak prenášame niečo viac ako základné typy (int, string, ...) z/do operácii služby, musíme definovať data contract. Je to trieda reprezentujúca typ posielaný medzi službou a jej klientom. Na rozdiel od message contracts, sú data contracts používané pri viacerých operáciach služby alebo sú používané viacerými službami. Data contract definujeme pridaním atribútu [DataContract] k deklarácií triedy (prípadne štruktúry alebo enumerácie). Jednotlivé členy data contract-u označíme atribútom [DataMember]. Data contract predstavuje mapovanie CLR/XSD. Príklad na data contract:
[DataContract]
public class Book
{
private int id;
private string author;
private string title;
[DataMember]
public int Id
{
get { return id; }
set { id = value; }
}
[DataMember]
public string Author
{
get { return author; }
set { author = value; }
}
[DataMember]
public string Title
{
get { return title; }
set { title = value; }
}
}
Message contract
Message contract popisuje štruktúru správy. Je to trieda reprezentujúca správu (požiadavka, odpoveď). Message contract umožňuje kontrolovať či informácia pôjde do hlavičky alebo tela správy. Na rozdiel od data contracts, sú message contracts určené pre špecifickú operáciu služby a nie sú určené pre zdielanie a znovupoužitie. Message contract definujeme pridaním atribútu [MessageContract] k deklarácií triedy. Jednotlivé časti správy definujeme atribútmi [MessageHeader] a [MessageBodyMember]. Message contract predstavuje mapovanie CLR/SOAP. Príklad na message contract:
[MessageContract]
public sealed class FindBooksRequest
{
private string userName;
private string bookTitle;
[MessageHeader]
public string UserName
{
get { return userName; }
set { userName = value; }
}
[MessageBodyMember]
public string BookTitle
{
get { return bookTitle; }
set { bookTitle = value; }
}
}
Príklad
Ako príklad použitia WCF kontraktov použijem jednoduchú službu s operáciami na nájdenie kníh FindBooks alebo pridanie knihy do knižnice AddBook. Riešenie obsahuje 4 projekty (Service, Contracts, Host, Client). Service contract, ktorý implementuje služba je uvedený v sekcii, kde je popísaný pojem service contract. Perzistencia zoznamu kníh medzi jednotlivými volaniami operácií služby je realizovaná pomocou XML súboru. Pomocou XML serializéra a file streamu je pole prvkov typu Book ukladané (serializácia) do XML súboru alebo načítané (deserializácia) z XML súboru. Zdrojový kód služby je:
using System;
using System.IO;
using System.Collections.Generic;
using System.ServiceModel;
using System.Runtime.Serialization;
using System.Xml.Serialization;
using Contracts;
namespace Service
{
public class LibraryService : ILibrary
{
private static string xmlFileName = "books.xml";
#region ILibrary Members
public FindBooksResponse FindBooks(FindBooksRequest request)
{
List<Book> books = new List<Book>(LoadBooks());
List<Book> result = new List<Book>();
if (request.UserName == "Marian")
{
foreach (Book book in books)
{
if (book.Title.Contains(request.BookTitle))
result.Add(book);
}
}
FindBooksResponse response = new FindBooksResponse();
response.Books = result.ToArray();
return response;
}
public void AddBook(Book book)
{
List<Book> books = new List<Book>(LoadBooks());
books.Add(book);
SaveBooks(books.ToArray());
}
#endregion
private Book[] LoadBooks()
{
if (!File.Exists(xmlFileName)) return new Book[0];
using (FileStream fs = new FileStream(xmlFileName, FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(Book[]));
return (Book[])serializer.Deserialize(fs);
}
}
private void SaveBooks(Book[] books)
{
using (FileStream fs = new FileStream(xmlFileName, FileMode.Create))
{
XmlSerializer serializer = new XmlSerializer(typeof(Book[]));
serializer.Serialize(fs, books);
fs.Close();
}
}
}
}
Služba bude hostovaná v konzolovej aplikácii, ktorá bude realizovaná podobne ako hostovacia aplikácia služby z prvej časti seriálu (Začíname s WCF). Klientom služby bude konzolová aplikácia, ktorá bude volať operácie služby. So službou budeme komunikovať prostredníctvom proxy triedy, ktorá bude automaticky vygenerovaná, keď vytvoríme referenciu na službu voľbou Add Service Reference. Odporúčam prezrieť si kód vygenerovanej proxy triedy, pretože tam je vidieť akou formou sú reprezentované data contracts a message contracts používané službou. Klientská aplikácia bude komunikovať so službou volaním metód proxy triedy. Kód klienta bude:
using System;
using Client.Library;
namespace Client
{
class Program
{
static void Main(string[] args)
{
using (LibraryClient client = new LibraryClient())
{
client.AddBook(CreateBook(1, "M. MacDonald, M. Szpuszta", "Pro ASP.NET 2.0 in C# 2005"));
client.AddBook(CreateBook(2, "R. Lhotka", "Expert C# 2005 Business Objects"));
PrintResult(client.FindBooks("Marian", "C#"));
client.Close();
Console.ReadLine();
}
}
private static Book CreateBook(int id, string author, string title)
{
Book book = new Book();
book.Id = id;
book.Author = author;
book.Title = title;
return book;
}
private static void PrintResult(Book[] books)
{
Console.WriteLine("\nResult:");
foreach (Book book in books)
{
Console.WriteLine("\nId: " + book.Id);
Console.WriteLine("Author: " + book.Author);
Console.WriteLine("Title: " + book.Title);
}
}
}
}
Zdrojový kód celého príkladu si môžete stiahnúť tu.
Service Configuration Editor
Na záver ešte spomeniem zaujímavú utilitu Service Configuration Editor. Pomocou nej môžeme vytvárať konfiguračné súbory pre WCF bez toho, aby sme museli ručne písať kód. Utilitu spustíme tak, že klikneme v solution explorer-y pravým tlačítkom na konfiguračný súbor (app.config) a vyberieme možnosť Edit WCF Configuration:

Zobrazí sa nám okno v ktorom môžeme nakonfigurovať jednotlivé nastavenia služby alebo klienta:

Táto utilita nám ulahčí prácu pokial nemáme dostatok skúseností s WCF alebo sa nám nechce :) písať kód ručne do konfiguračného súboru.
Ing. Marián Košťál (csharp@azet.sk)