sobota, 16 listopada 2013

[HTML|JS|CSS] jQuery: Pluginy i rozszerzanie

Na githubie aż roi się od przeróżnych pluginów do jQuery pisanych przez mniej lub bardziej sprawnych programistów. Jak napisać własny plugin ? Przykład poniżej.

(function($){

 $.fn.print = function(props) {
  var functions = $.fn.print.functions;
  if ($.isArray(props)) {
   functions = $.merge(functions, props);
  }
  return this.each(function() {
   var element = $(this);
   functions.forEach(function(fn){
    console.log(fn, ': ', $(element)[fn]());
   });
  });
 };

 $.fn.print.functions= ['height', 'width'];

})(jQuery);

Trick z immediate function to zabezpieczenie na wypadek, gdyby aplikacja używała $ (który jest aliasem dla obiektu jQuery) do innych celów. Pisząc plugin rozszerza się obiekt fn, który jest referencją na prototype obiektu jQuery. Korzystając z faktu, że każda funkcja jest obiektem, możemy załączyć do niej obiekt, który może zostać wykorzystany, jako domyślne ustawienia pluginu.

Plugin wywołujemy na dowolnym selektorze, na przykład:

$(function(){
 $('div').print();
 $('a').print(['size']);
 $('button').print(['html']);
});

Drugi sposób na uzyskanie podobnego efektu, to funkcja extend z jQuery, którą wykorzysujemy do łączenia dwóch obiektów JavaScript w jeden. Wywołanie tej funkcji na $.fn spowoduje rozszerzenie jQuery o naszą funkcję.

(function($){

 $.fn.extend({
  count: function(){
   console.log(this.length);
  }
 });

})(jQuery);

$(function(){
 $('div').count();
});

sobota, 9 listopada 2013

[HTML|JS|CSS] jQuery: Lightbox

Lightbox to popularna na stronach internetowych technika wyświetlania obrazów z wyszarzonym tłem, znana na przykład z allegro. W tym poście przedstawione zostanie, jak zaimplementować taką funkcjonalność z użyciem jQuery.


Odnośniki do obrazków będą zwykłymi tagami typu <a>. Po kliknięciu w odnośnik zostaną dodane dwie warstwy: zewnętrzna (overlay) i ta, na której wyświetlany jest obrazek (lightbox).

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <title>Lightbox</title> 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    <script src="scripts/myscript.js"></script>
</head>
<body>
 <h2>Nice cars list</h2>
 <ul>
  <li>
   <a href='/images/bmw_seria6.jpg' class='lightbox'>BMW Seria 6</a>
   <a href='/images/hyundai_genesis.jpg' class='lightbox'>Hyundai Genesis</a>
   <a href='/images/lexus_ct200h.jpg' class='lightbox'>Lexus Ct200h</a>
   <a href='/images/mercedes_slk.jpg' class='lightbox'>Mercedes SLK</a>
   <a href='/images/nissan_350z.jpg' class='lightbox'>Nissan 350z</a>
  </li>
 </ul>
</body>
 <style>
  #lightbox_overlay {
   position:absolute;
   top:0;
   left:0;
   height:100%;
   width:100%;
   background:black url(spinner.gif) no-repeat scroll center center;
  }
  #lightbox {
   position:absolute;
  }
 </style>
</html>

Overlay pozycjonowany jest absolutnie z wymiarami na 100%. Pozycję lightboxa wylicza się tak, aby trafił na środek ekranu. Animacja opacity daje efekt półprzezroczystej warstwy.

$(document).ready(function(){
 $('a.lightbox').click(function(e) {
  $('body').css('overflow-y', 'hidden');
  $('<div id="lightbox_overlay"></div>').css('top', $(document).scrollTop())
  .css('opacity', '0')
  .animate({'opacity': '0.5'}, 'slow')
  .appendTo('body');
 $('<div id="lightbox"></div>')
  .hide()
  .appendTo('body');
 $('<img />')
  .attr('src', $(this).attr('href'))
  .load(function() {
   positionLightboxImage();
  })
  .click(function() {
   removeLightbox();
  })
  .appendTo('#lightbox');
  return false;
 });
 });

function positionLightboxImage() {
 var top = ($(window).height() - $('#lightbox').height()) / 2;
 var left = ($(window).width() - $('#lightbox').width()) / 2;
 $('#lightbox')
  .css({
   'top': top + $(document).scrollTop(),
   'left': left
  })
 .fadeIn();
}

function removeLightbox() {
 console.log('asd');
 $('#lightbox_overlay, #lightbox')
  .fadeOut('slow', function() {
   $(this).remove();
   $('body').css('overflow-y', 'auto');
  });
}

czwartek, 7 listopada 2013

[WCF] REST

REST (Representational State Transfer) to drugi obok SOAP (Simple Object Access Protocol) wzorzec budowy aplikacji wymagających komunikacji pomiędzy stroną kliencką i serwerową. Oparty jest na protokole HTTP (w przeciwieństwie do niezależnego od protokołów SOAP). Wzorzec ten zakłada prostą definicję dostępu do zasobów (poprzez czasowniki HTTP, takie jak GET, POST, PUT, DELETE). Różna są też formaty, w jakich zwracany jest ten zasób, głównie jest to XML i JSON. Mówi się więc, że REST to wzorzec nastawiony na zasoby, natomiast SOAP kładzie nacisk na akcje (wykonywane na zasobach). Dużą przewagą REST-a jest interoperacyjność i skalowalność. Pomiędzy REST i SOAP definiuje się POX (Plain Old Xml) - przesyłanie danych w formacie XML, ale bez narzutów SOAP.

Dla samego REST wykorzystujemy w WCF webHttpBinding oraz webHttpBehavior. Adresowanie zasobów odbywa się poprzez dwa atrybuty zawarte w System.ServiceModel.Web: WebGet i WebInvoke. Pierwszy z nich definiuje operacje wykonywane przy żądaniach typu GET, drugi zapewnia obsługę pozostałych żądań.

[ServiceContract]
public interface IEvaluationService
{
    [OperationContract]
    [WebInvoke(Method ="POST", UriTemplate = "evals")]
    void SubmitEvaluation(Evaluation eval);

    [OperationContract]
    [WebGet(UriTemplate = "evals", ResponseFormat = WebMessageFormat.Json)]
    List<Evaluation> GetEvaluations();

    [OperationContract]
    [WebGet(UriTemplate = "eval/{id}")]
    Evaluation GetEvaluation(string id);

    [OperationContract]
    [WebInvoke(Method = "DELETE", UriTemplate = "eval/{id}")]
    void RemoveEvaluation(string id);
}

Poprzez atrybuty WebGet i WebInvoke można także ustawić format zwracanej / przyjmowanej wiadomości. Domyślnie jest to XML. Plik konfiguracyjny dla aplikacji hostującej jest bardzo krótki, a wszystko dzięki specjalnej klasie hostującej REST-owe serwisy.

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true"/>
  </system.web>
  <system.serviceModel>
    <services>
      <service name="EvaluationServiceLibraryRest.EvaluationService" >
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:18081/evaluations/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>


WebServiceHost host = new WebServiceHost(typeof(EvaluationService));
try
{
    host.Open();
    Console.ReadKey();
    host.Close();
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
    Console.ReadKey();
    host.Abort();
}

czwartek, 31 października 2013

[WCF] Clients

Stronę kliencką po utworzeniu serwisów WCF można stworzyć na dwa sposoby. Strona serwerowa wystawia metadane pod specjalnym adresem MEX (Metadata EXchange) lub plik WSDL. Na podstawie tych danych możemy za pomocą narzędzia svcutil wygenerować kod kliencki oraz plik z ustawieniami. Narzędzie svcutil.exe wymaga korzystania z command line, dlatego Microsoft od VS 2008 wprowadził funkcjonalność AddServiceReference, która na podstawie podanego adresu z metadanymi tworzy kod w C#, konfigurację oraz dodaje do projektu klienckiego odpowiednie dll-ki. Wygenerowany kod można swobodnie przegenerowywać zmieniając niektóre opcje (klikamy prawym przyciskiem myszy na referencji i wybieramy Update Service Reference).




W oknie możemy wybrać między innymi, czy chcemy generować asynchroniczne wywołania operacji z Operation Contract-ów. Ponadto możemy wybrać, na jaki tym mają być rzutowane kolekcje (lista, tablica itd.). Co więcej, w przypadku, gdy strona kliencka i serwerowa znajdują się w jednej solucji, możemy reużywać niektóre typy zdefiniowane po stronie serwerowej.

Serwisy możemy wywoływać tworząc jawnie channele za pomocą klasy ChannelFactory<T> lub korzystając z wygenerowanych klas proxy, które przejmują odpowiedzialność tworzenia channeli.

bool useProxy = new Random().Next()%2 == 0;
IEvaluationService channel = null;

try
{
    if (!useProxy)
    {
        //Transparent proxy
        ChannelFactory<IEvaluationService> factory =
            new ChannelFactory<IEvaluationService>("WSHttpBinding_IEvaluationService");
        channel = factory.CreateChannel();
    }
    else
    {
        //Generated proxy
        channel = new EvaluationServiceClient("WSHttpBinding_IEvaluationService");
    }

    var eval = new Evaluation()
    {
        TimeSent = DateTime.Now,
        Comments = "Nice",
        Submitter = "Johnny"
    };

    channel.SubmitEvaluation(new EvaluationRequest()
    {
        EvaluationBody = eval
    });

    ((IClientChannel)channel).Close();
}
catch (FaultException e)
{
    ((IClientChannel)channel).Abort();
}
catch (CommunicationException e)
{
    ((IClientChannel)channel).Abort();
}
catch (TimeoutException e)
{
    ((IClientChannel)channel).Abort();
}

Ważne aby odpowiednio obsługiwać wyjątki w WCF.FaultException, to propagacja wyjątku powstałego w kodzie po stronie serwerowej. CommunicationException wynika ze złej konfiguracji endpointu po którejś ze stron (np. źle podana nazwa do konstruktora ChannelFactory). TimeoutException zostanie rzucony, jeżeli serwer nie odpowie przez dłużej niż ustalony przez klienta próg.

Podstawowa różnica pomiędzy poleceniami Close i Abort polega na tym, że pierwsze zamyka połączenie w sposób prawidłowy, natomiast drugie warto wykorzystywać, jeżeli chcemy zamknąć połączenie natychmiast. Polecenie Close zostaje wstrzymane do póki nie zakończą się wszystkie operacje, także te asynchroniczne, może ono także rzucić wyjątkiem typu CommunicationException lub TimeoutException.

Nazwa klasy klienckiej zostaje wygenerowana przez konwencję (odcięcie od nazwy interfejsu pierwszej litery "I" oraz dodanie na końcu "Client"). Również przez konwencję tworzone są metody asynchroniczne, do których podajemy callback, który wywoła się po otrzymaniu odpowiedzi.

var client = channel as EvaluationServiceClient;
client.GetEvaluationsCompleted += (e, o) => Console.WriteLine(o.Result.Length);
client.GetEvaluationsAsync();

Metadane można pobierać nie tylko przez VS czy svcutil, ale także w kodzie. Przykład poniżej.

var endpoints = MetadataResolver.Resolve(typeof (IEvaluationService),
                             new EndpointAddress("http://localhost:8732/evals/mex/"));

foreach (var endpoint in endpoints)
    Console.WriteLine(endpoint.Name);

poniedziałek, 28 października 2013

[WCF] Address, Binding

Zdefiniowanie serwisu WCF wymaga określenie tzw. ABC, czyli adresu, bindingów i kontraktu, które odpowiadają na pytania gdzie ? jak ? i co ?

Adres definiuje, gdzie serwis jest hostowany. WCF wspiera różne sposoby przesyłania danych, a co za tym idzie różne są rodzaje adresów. Poniższa tabela przedstawia sposoby adresowania w WCF.

Technologia Przykładowy adres Opis
HTTP http://localhost:8001 Najczęściej używany tekstowy sposób przesyłania danych, dane przeważnie w XML lub JSON
HTTPS https://localhost:8001 Bezpieczny sposób przesyłania danych po HTTP. Szyfrowanie za pomocą TLS lub SSL.
TCP Peer network net.tcp://localhost:8002/Service1, net.p2p://localhost/ Bardzo szybki sposób przesyłania danych w formacie binarnym.
IPC (Inter-process communication over named pipes) net.pipe://localhost/PipeService1 Szybki sposób przesyłania danych w obrębie jednej maszyny (współdzielona pamięć).
MSMQ (Microsoft Message Queue) net.msmq://localhost Wiadomości wysyłane przez klienta są kolejkowane. Użyteczny sposób dla scenariuszy, w których istnieje możliwość rozłączenia klienta z serwerem.

Kluczowym elementem architektury WCF jest binding, odpowiadający na pytanie "jak?". Główne obszary, jakie definiuje binding to protokół transportu danych, format wiadomości oraz szczegóły przesyłania wiadomości specyficzne dla danego protokołu. WCF udostępnia szereg protokołów, niemniej jednak zawsze istnieje możliwość zdefiniowania własnego.Poniżej przedstawiono listę bindingów dostarczanych przez WCF. Te, które rozpoczynają się od przedrostka "net" są dedykowane dla technologii .NET, z kolei bindingi rozpoczynające się od "ws" reprezentują ogólnie przyjęte standardy implementowane w wielu technologiach.

Binding Opis
basicHttpBinding Wiadomości przesyłane po Http i zakodowane w Utf-8. Oparte na WS-I profile.
webHttpBinding Serwisy wystawiane jako requesty Http, format XML lub JSON umożliwia tworzenie serwisów w oparciu o wzorzec REST.
wsHttpBinding Korzysta z zaawansowanych profili WS-*, takich jak WS-Security, WS-Transactions, WS-BusinessActivity, etc.
wsDualHttpBinding Korzysta z tych samych profili, co wsHttpBinding ale wspiera komunikację typu duplex.
wsFederationHttpBinding Profile WS-* rozszerzone o federated identity.
netTcpBinding Wiadomości binarne przesyłane po TCP. Wymaga, aby obie strony korzystały z WCF.
netNamedPipeBinding Zoptymalizowany pod kątem komunikacji w obrębie jednej maszyny.
netPeerTcpBinding Komunikacja po TCP z wykorzystaniem technologii P2P.
netMsmqBinding Asynchroniczna komunikacja z wykorzystaniem kolejki komunikatów.

Bindingi można ustawiać w sposób proceduralny...

ServiceHost host = new ServiceHost(typeof(EvaluationService));

host.AddServiceEndpoint(typeof (IEvaluationService), 
    new BasicHttpBinding(), "http://localhost:8080/evals/");

...ale znacznie wygodniej jest robić to w ustawieniach projektu (App.config lub Web.config), gdzie mamy do dyspozycji narzędzie wbudowane w Visual Studio.


W oknie tym możemy ustawić behavior dla określonego typu bindingu zmieniając domyślne parametry. Po zamknięciu okna zmiany zostaną przeniesione do pliku XML z konfiguracją. Na przykład:

<configuration>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="MyBindingConfiguration" allowCookies="true" />
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="EvaluationServiceLibrary.EvaluationService">
        <endpoint address="/evals/" binding="wsHttpBinding" bindingConfiguration="MyBindingConfiguration"
          contract="EvaluationServiceLibrary.IEvaluationService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

niedziela, 27 października 2013

[WCF] ServiceContract, DataContract, MessageContract

Kontrakty w WCF można porównać do kontraktów w życiu codziennym. Podpisując jakiś kontrakt obie strony potwierdzają, że są świadome pewnych warunków. W WCF kontrakt definiuje między innymi wystawione serwisy, adresy, rodzaje wiadomości, jakie te serwisy odbierają i zwracają. WCF wykorzystuje  WSDL (Web Services Description Language) oraz XSD do dostarczenie metadanych na temat wystawionych serwisów. Ważne jest, aby kontrakty były niezależne od technologii, dlatego definiuje się je w neutralnym formacie bazującym na XML. Dzięki temu WebSerwisy wystawione na przykład w technologiach Javy mogą być wykorzystywane przez proxy WCF i aplikację napisaną w .NET i na odwrót.

ServiceContract

Definiuje funkcjonalność wystawioną przez serwis WCF. Dobrą praktyką jest oznaczanie tym atrybutem interfejsu .NET tak, aby zapewnić pewną warstwę abstrakcji nad konkretnymi implementacjami. Przykładowo:

[ServiceContract]
public interface IEvaluationService
{
    [OperationContract(IsOneWay = true)]
    void SubmitEvaluation(Evaluation eval);
    [OperationContract]
    List<Evaluation> GetEvaluations();
}

Property IsOneWay oznacza, że dana operacja nie zwraca wyniku. Konkretną implementację interfejsu można konfigurować poprzez atrybut ServiceBehavior.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
    ConcurrencyMode = ConcurrencyMode.Single)]
public class EvaluationService : IEvaluationService
{
    private List<Evaluation> _evals = new List<Evaluation>();

    public void SubmitEvaluation(Evaluation eval)
    {
        _evals.Add(eval);
    }

    public List<Evaluation> GetEvaluations()
    {
        return _evals;
    }
}

InstanceContextMode:  Single - Singleton, PerCall - zawsze nowa instancje, Session - każdy klient dostaje unikalną instancje w obrębie sesji.
ConcurrencyMode - Single - tylko jeden wątek ma dostęp do obiektu, Multiple - dostępny dla wielu wątków, Reentrant - nowe operacje mogą być wykonywane tylko podczas wywoływania innego serwisu.

DataContract

Definiuje typy, które mają być serializowane i przesyłane dalej przez WCF. Domyślny serializator to DataContractSerializer, który sprawdza, które obiekty są oznaczone tym atrybutem. Serializowane będą te propercje lub pola, które są oznaczone atrybutami DataMember.

[DataContract]
public class Evaluation
{
    [DataMember(IsRequired = true)]
    public string Submitted { get; set; }
    [DataMember(Order = 2)]
    public DateTime TimeSent { get; set; }
    [DataMember]
    public string Comments { get; set; }
}

Jeżeli w odebranej wiadomości nie będzie wartości, którą możnaby zdeserializować na property oznaczone z opcją IsRequired, aplikacja zwróci błąd. Poprzez opcję Order możemy ustawiać kolejność elementów w XML-u.

Problem może pojawić się w sytuacji, gdy chcemy wykorzystać mechanizm polimorfizmu. Jeżeli w sygnaturach metod mamy klasy bazowe, natomiast chcemy zwrócić klasę po nich dziedziczącą musimy użyć atrybutu KnownType. Znane typy dziedziczące po klasie bazowej zostaną dodane do kontraktu..

[DataContract]
[KnownType(typeof(Car))]
public abstract class Vehicle
{
    [DataMember]
    public string Name { get; set; }
}

[DataContract]
public class Car : Vehicle
{
    [DataMember]
    public int Year { get; set; }
}

MessageContract

Pozwala na zdefiniowanie, które pola mają znajdować się w nagłówku SOAP, a które w body. Typ oznaczony typ atrybutem przekazujemy do metody oznaczonej atrybutem OperationContract. 

[DataContract]
public class Evaluation
{
    [DataMember(IsRequired = true)]
    public string Submitted { get; set; }
    [DataMember(Order = 2)]
    public DateTime TimeSent { get; set; }
    [DataMember]
    public string Comments { get; set; }
}

[DataContract]
public class CustomHeader
{
   [DataMember]
   public string Username { get; set; }
}

[MessageContract]
public class EvaluationRequest
{
    [MessageHeader]
    public CustomHeader EvaluationHeader { get; set; }

    [MessageBodyMember]
    public Evaluation EvaluationBody { get; set; }
}

Dzięki temu wiadomość SOAP przyjmuje poniższą postać:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://tempuri.org/IEvaluationService/SubmitEvaluation</a:Action>
    <h:EvaluationHeader xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:h="http://tempuri.org/">
      <Username xmlns="http://schemas.datacontract.org/2004/07/EvaluationServiceLibrary">Joe</Username>
    </h:EvaluationHeader>
  </s:Header>
  <s:Body>
    <EvaluationRequest xmlns="http://tempuri.org/">
      <EvaluationBody xmlns:d4p1="http://schemas.datacontract.org/2004/07/EvaluationServiceLibrary" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <d4p1:Comments>Git</d4p1:Comments>
        <d4p1:Submitted>Yes</d4p1:Submitted>
        <d4p1:TimeSent>2013-10-27T12:46:00</d4p1:TimeSent>
      </EvaluationBody>
    </EvaluationRequest>
  </s:Body>
</s:Envelope>

wtorek, 8 października 2013

[WCF] Wprowadzenie

Windows Communication Foundation to technologia, którą świat ujrzał z .NET Framework 3.0 jako odpowiedź na potrzebę budowania rozproszonych systemów, które MS zaczął marketingowo nazywać "Connected Systems". Podczas tworzenia aplikacji rozproszonych ważne jest, aby umożliwić komunikowanie się systemów napisanych w różnych technologiach. Stąd pomysł serwisów jako jednostek udostępniających pewne funkcjonalności poprzez przesyłanie ustandaryzowanych wiadomości.

Dominują dwa wzorce, SOAP i REST.

SOAP (Simple Object Access Protocol) - wiadomości wysyłane są w formacie XML i WS-* protocols. Wspiera wiele protokołów transportowych np. HTTP, TCP, MSMQ.

REST (Representational State Transfer) - różne formaty wiadomości (XML, coraz częściej JSON), protokół transportowy HTTP, paradygmat ukierunkowany na adresowanie, modyfikowanie i odczytywanie zasobów.

WCF wprowadza unifikację, umożliwiając wymianę wiadomości po różnych protokołach, w różnych formatach, wzorcach.

Większość funkcjonalności WCF zawarte jest w System.ServiceModel.dll. Najprościej filozofię WCF oddaje zdanie: serwisy wystawiają swoje funkcjonalności poprzez endpointy, natomiast klienci konsumują je poprzez kanały. WCF-owe endpointy składają się z trzech składowych ABC definiujące podstawowe pojęcia (Address - gdzie?, Binding - jak?, Contract - co?).

Tworzenie najprostszej aplikacji WCF:

Pierwszy projekt to serwisy WCF.

[DataContract]
public class Name
{
    [DataMember]
    public string First { get; set; }

    [DataMember]
    public string Last { get; set; }
}

[ServiceContract]
public interface IMyFirstService
{
    [OperationContract]
    string SayHello(Name name);
}

public class MyFirstService : IMyFirstService
{
    public string SayHello(Name name)
    {
        return string.Format("Hello, {0} {1}", name.First, name.Last);
    }
}

Klasa Name będzie przesyłaną wiadomością, natomiast oznaczenie interfejsu przez atrybuty definiuje, jakie operacje chcemy wystawić na zewnątrz. Kolejne zmiany nanosimy w pliku App.config.Wystawiamy jeden serwis dostępny pod trzema endpointami wykorzystującymi różne protokoły transportowe.

<services>
  <service name="WcfEssentials.MyFirstService">
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:8080/helloworld/"   />
      </baseAddresses>
    </host>
    <endpoint address="ws"  binding="wsHttpBinding" contract="WcfEssentials.IMyFirstService" />
    <endpoint address="basic"  binding="basicHttpBinding" contract="WcfEssentials.IMyFirstService" />
    <endpoint address="net.tcp://localhost:8081/helloworld/"  binding="netTcpBinding" contract="WcfEssentials.IMyFirstService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  </service>
</services>

Uruchomienie aplikacji spowoduje pojawienie się okna, w którym możemy testować nasze endpointy.


Jeżeli chcemy wykorzystać nasz serwis w kodzie, dodajemy osobny projekt, np. aplikację konsolową. Następnie musimy dodać referencję do serwisów WCF. Klikamy prawym przyciskiem myszy i wybieramy Add Service Reference....


Strona kliencka pobierze metadane i utworzy obiekty proxy, którymi będziemy mogli się łączyć do stworzonych wcześniej serwisów. W pliku app.config automatycznie wygenerują się bindingi dla strony klienckiej, gdzie każdy endpoint otrzyma swoją nazwę. Wywołanie serwisu w kodzie C# jest bardzo proste.

using (var client = new MyFirstServiceClient("NetTcpBinding_IMyFirstService"))
{
    var name = new Name() { First = "Tom", Last = "Smith" };
    Console.WriteLine(client.SayHello(name));
    Console.Read();
}

Jako parametr konstruktora podajemy wygenerowaną przez VS nazwę serwisu.