Spis treści:

Kategoria:C#Windows Communication Foundation


Rozpoczynamy przygodę z WCF

WCF? A co to jest?

WCF, czyli Windows Communication Foundation to programistyczny interfejs służący do pisania modułów komunikujących się. Pisząc modułów komunikujących się mam na myśli to, co wcześniej dostępne było pod wieloma postaciami, czy to usług Web Service, czy COM (DCOM, COM+), czy też .NET Remoting lub zwykłej komunikacji poziomu gniazd (socket), czy nawet MSMQ, czyli kolejek komunikatów.

Według zapewnień Microsoftu, wszystkie te technologie są integralną częścią WCF. Jak jest w rzeczywistości? Prawie tak jak w obietnicach. Różnice pojawiają się, ale dopiero w szczegółach.

Architektura klient-serwer

Zapoznając się z nową technologią należy od czegoś zacząć. Odpowiednikiem "Hello World!" w WCF jest prosta aplikacja klient-serwer, w której serwer posiada jedną metodę, a klient ją wywołuje. W naszym przykładzie będzie to metoda HelloWorld, która zwróci (tak, tak, oczywiście), tekst postaci Hello World! Aby przekonać się, że komunikacja rzeczywiście nastąpiła, stworzymy sobie dwa projekty. Projekt klienta i projekt serwera. Ci, którzy czekają na bardziej zaawansowane aplikacje niestety się rozczarują. Od razu ich jednak uspokoję, takie pojawią się, ale nieco później. Przejdźmy zatem do konkretów i zacznijmy w końcu pisać kod. W pierwszej linii pojawi się serwer.

Prosty serwer WCF

Serwer WCF może mieć różną postać. Może być usługą Web Service, może działać jako usługa windows. Jest również możliwość udostępnienia usług WCF z poziomu zwykłej, prostej aplikacji konsolowej. Tak też zrobimy.

Zanim zaczniemy czytać dalej, stwórzmy w Visual Studio nowy projekt aplikacji konsolowej. Tu będzie centrum zarządzania usługą WCF.

Pierwszą rzeczą, od której należy zacząć pisanie usług WCF jest stworzenie interfejsu, czyli pewnego rodzaju definicji metod udostępnianych przez WCF. Dodajmy więc do projektu konsolowego interfejs. W naszym przypadku będzie on wyglądał następująco:

interface IHelloWorld
{
  string Hello();
}

Taka właśnie funkcja HelloWorld udostępniana będzie przez nasz serwer. Każdy klient takiego serwera będzie mógł tę metodę wywołać i pobrać zwracany przez nią tekst powitalny. Na tym etapie interfejs nie różni się niczym od zwykłego interfejsu .NET. Aby jednak WCF mógł z niego korzystać, należy go odpowiednio oznaczyć. Sam interfejs oznacza się atrybutem ServiceContract, natomiast każdą jego metodę atrybutem OperationContract. Definicje obu tych atrybutów znajdują się w bibliotece System.ServiceModel.

Biblioteka System.ServiceModel nie jest automatycznie dodawana do większości typów projektów. Aby dodać ją należy w oknie Solution Explorer kliknąć prawym przyciskiem myszy na polu References, z menu podręcznego wybrać Add Reference... i z zakładki .NET wybrać element System.ServiceModel.

Interfejs po dodaniu atrybutów przyjmie więc następującą postać:

[ServiceContract]
interface IHelloWorld
{
  [OperationContract]
  string Hello();
}
W celu realizacji prostego przykładu zalecam usunięcie przestrzeni nazw z każdego pliku (fragmenty namespace Nazwa{...}). Przestrzenie powinny być używane i nie mam nic przeciwko korzystaniu z nich, ale na początku nie są do niczego potrzebne, a mogą trochę utrudnić uruchamianie usług WCF.

Drugim etapem niech będzie implementacja podanego interfejsu. Nie będzie ona szczególnie skomplikowana, ale nie o to na tym etapie chodzi. Stwórzmy sobie zatem nową klasą w Visual Studio i nawijmy ją HelloWorld. Klasa powinna implementować stworzony wcześniej interfejs IHelloWorld. Kod naszej klasy będzie zatem wyglądał następująco:

class HelloWorld : IHelloWorld
{
  public string Hello();
  {
    return "Hello World!";
  }
}

Na tym etapie mamy już cały kod, który realizuje konkretne zadanie. Należy go teraz udostępnić innym aplikacjom.

Udostępnianie metod innym aplikacjom

Przejdźmy teraz do metody Main, czyli do miejsca, gdzie nasz program, czyli serwer, rozpocznie swoje działanie. Nasza usługa WCF będzie działała w sieci, na tym etapie lokalnej, ale nic nie stoi na przeszkodzie, aby to w przyszłości zmienić. Zdefiniujmy więc adres, pod którym umieścimy naszą, skądinąd wysoce wyspecjalizowaną, usługę HelloWorld.

Dodajmy zatem do metody Main adres:

Uri adres = new Uri("http://localhost:2222/Hello");

Przeanalizujmy adres, bo dla niektórych może on się wydać dziwny: http, to protokół, po którym aplikacje będą komunikować się z naszym serwerem. To standardowy protokół sieciowy, więc nie będę go opisywał. Element localhost to adres komputera lokalnego, 2222 to port, na którym serwer będzie nasłuchiwał żądań. Nie ma on znaczenia i tylko od nas zależy co tw wpiszemy, może to być równie dobrze 2018 czy 2184. Ważne, żeby klient o tym wiedział i do takiego wysyłał żądanie. Ostatni element, czyli Hello to nazwa naszej usługi sieciowej. Za pomocą tej nazwy identyfikujemy konkretną usługę. W tym przypadku usługa jest jedna, ale w rozbudowanych systemach może być tych usług znacznie więcej. Nazwę tę także wybieramy sami. Powinna ona jednak być rozsądna, bo będzie udostępniana innym aplikacjom.

Mając adres, możemy utworzyć klasę ServiceHost, czyli naszą usługę. Na nasze potrzeby tworzymy ją w sposób następujący:

ServiceHost host = new ServiceHost(typeof(HelloWorld), adres);

Pierwszy parametr to typ klasy, która będzie obsługiwała żądania różnych klientów. Drugi parametr to adres naszej usługi. To jest centrum naszej usługi i tu będzie się wykonywał kod. To wnętrze, serce WCF nie komunikuje się bezpośrednio ze światem zewnętrznym. Robi to za pomocą tzw. końcówek (ang. endpoints). To właśnie końcówki wystawiają interfejsy oraz zajmują się transportem, końcówki definiują także protokół. Usługa bez końcówki jest bezużyteczna. Jest jednak dobra wiadomość: końcówki w podstawowej formie tworzy się dość łatwo. Kod zaprezentowany jest poniżej:

host.AddServiceEndpoint(typeof(IHelloWorld), new BasicHttpBinding(), adres);

Pierwszym parametrem jest udostępniany interfejs. Drugi parametr to protokół, w naszym przypadku zwykły protokół HTTP. trzeci parametr to adres, ten sam, co w przypadku całej usługi. Wydaje mi się, że wyjaśnień wymaga drugi parametr. WCF może obsługiwać komunikację różnymi protokołami. W najprostszej postaci jest to zwykłe HTTP, ale nic nie stoi na przeszkodzie, aby korzystać z, powiedzmy, TCP/IP. W takim przypadku jako drugi parametr przekazujemy obiekt klasy NetTcpBinding. Należy jednak wtedy pamiętać o zmianie adresu (nie będzie się już zaczynał przedrostkiem http. Rodzaje komunikacji, protokoły i powiązane z nimi klasy zostaną opisane później.

Po stworzeniu klasy usługi i dodaniu końcówki możemy rozpocząć nasłuchiwanie. Służy do tego metoda Open klasy ServiceHost. Cały kod serwera, czyli metody Main, będzie zatem wyglądał następująco:

static void Main(string[] args)
{
  Uri adres = new Uri("http://localhost:2222/Hello");
  ServiceHost host = new ServiceHost(typeof(HelloWorld), adres);
  host.AddServiceEndpoint(typeof(IHelloWorld), new BasicHttpBinding(), adres);
  host.Open();
  Console.WriteLine("Serwer uruchomiony");
  Console.ReadLine();
}

Ostatnia linijka, czyli Console.Readline() służy tylko i wyłącznie zatrzymaniu okna konsolowego. W przeciwmnym razie program dojdzie do końca i zakończy się, a co za tym idzie nie będzie dłużej nasłuchiwał i obsługiwał żądań.

Warto też wspomnieć o dobrej praktyce umieszczania kontruktora ServiceHost w bloku using tak, aby zwolnić wszystkie zasoby przez niego zajmowane zaraz po wyjściu z bloku. W tym przykładzie nie ma problemu, bo kończy się cały program i wszystko samo się zwalnia, a poza tym jest on mocno demonstracyjny, więc przejrzystość postawiona jest na pierwszym miejscu.

Podczas uruchamiania programu może pojawić się wyjątek następującej treści: "Protokół HTTP nie może zarejestrować adresu URL http://+:2222/Hello/. Używany proces nie ma praw dostępu do obszaru nazw...". W takim przypadku należy uruchomić Visual Studio (lub bezpośrednio aplikację konsolową) z prawami administratora.

Klient WCF

Serwer jest gotowy, teraz należy napisać aplikację, która będzie korzystała z napisanej metody. O tym w kolejnym artykule: Tworzenie prostego klienta WCF.

Kategoria:C#Windows Communication Foundation

, 2013-12-20

Komentarze:

fejo (2014-09-26 19:57:38)
Hej,

Dzięki za świetny tutorial.

Mam pytanie: czy nie powinniśmy na zakończenie programu skorzystać z metody host.Close() ?

Pozdrawiam
Mattioo (2017-06-16 00:29:35)
Hej fejo,
skoro host.Open() uruchamia usługę to host.Close() po prostu ją zamyka. Jak wspomniał autor artykułu pod jego koniec tłumacząc wykorzystanie Console.ReadLine() robi to ponieważ jeżeli nie zatrzyma wykonywania programu w ten sposób to ten zwyczajnie się zakończy wraz z działającą do tej pory usługą. Skoro usługa i tak jest zamykana na koniec działania programu to w tak prostym przykładzie nie ma sensu dodawania linii host.Close() ze względu na jej nadmiarowość w tym przykładzie. Przyda się na pewno jeśli jeszcze przed zakończeniem programu zechcesz w sposób płynny zatrzymać jakąś usługę powiedzmy w zależności od jakichś instrukcji sterujących.. Ja tak to rozumiem :)
Dodaj komentarz
Wyślij
Ostatnie komentarze
Dzieki za rozjasnienie zagadnienia upsert. wlasnie sie ucze programowania :).
Co się stanie gdy spróbuję wyszukać:
SELECT * FROM NV_Airport WHERE Code='SVO'
SELECT * FROM V_Airport WHERE Code=N'SVO'
(odwrotnie są te N-ki)
Będzie konwersja czy nie znajdzie żadnego rekordu?