wtorek, 30 grudnia 2014

[Linux] VirtualBox, CentOS - konfiguracja sieci

Stawiając maszynę wirtualną z linuksem potrzebujemy skonfigurować sieć. Po stronie VirtualBoxa zmieniamy ustawienia w zakładce Network:


Następnie należy zalogować się na konto roota na maszynie wirtualnej z CentOS-em i wykonać następujące polecenia:

  • Wyedytować plik z konfiguracją interfejsu sieciowego (najlepiej ustawić na statyczny adres IP)

vi  /etc/sysconfig/network-scripts/ifcfg-eth0

Jako zawartość ustawiamy to co poniżej (nie zmieniając HADDR)

    DEVICE=eth0

    BOOTPROTO=static

    ONBOOT=yes

    NM_CONTROLLED=no

    HWADDR=08:00:27:08:47:E9

    IPADDR=192.168.1.30

    NETMASK=255.255.255.0

    GATEWAY=192.168.1.1

  • Restartujemy interfejsy sieciowe

service network restart

  • Ustawiamy adresy dns

vi /etc/resolv.conf


nameserver 8.8.8.8
nameserver 8.8.4.4

środa, 17 grudnia 2014

[C#|Visual Studio] ASP .NET SignalR: .NET Hubs Client API

Pracę z klientem .NET zaczynamy od zainstalowania odpowiedniego pakietu NuGet-a.

Komunikacja z Hubami odbywa się w sposób asynchroniczny zarówno ze strony JavaScript, jak i .NET. Mamy zatem do czynienia z programowaniem opartym o Taski, z których w C# 5.0 możemy w wygodny sposób korzystać przy użyciu słów kluczowych async/await.

API przypomina nieco to dostępne po stronie JS, nie wykorzystujące dynamicznego proxy. Kluczową klasą jest HubConnection tworzące proxy do konkretnego Huba. Interfejs IHubProxy udostępnia dwie ważne metody: Invoke (do wysyłania danych do serwera) oraz On (do obsługi wiadomości przychodzących).

static async Task Execute()
{
    const string url = "http://localhost:1968";
    var connection = new HubConnection(url);
    var echo = connection.CreateHubProxy("modernChat");

    await connection.Start();
    Console.WriteLine("Connected, transport is: {0}", connection.Transport.Name);
    
    echo.On<string>("newMessageFrom", message => Console.Write(message));

    var response = await echo.Invoke<string>("SendMessage", "hello!");
    
    Console.ReadLine();
}

[C#|Visual Studio] ASP .NET SignalR: JavaScript Hubs Client API

Najczęściej komunikować z hubami będziemy się chcieli z poziomu kodu wykonywanego w środowisku przeglądarki. Klient oparty na bibliotece jQuery nie jest jednak jedynym dostępnym klientem signalR. Do dyspozycji mamy także klienta .NET oraz między innymi WP8, WinRT czy C++. Konsumentami mogą być także inne huby.

Klient JS może komunikować się z serwerem w dwóch trybach:

  • bazującym na późnym wiązaniu i opartym na wołaniu metod i zdarzeń poprzez podawanie ich nazw jako stringów
  • bardziej zaawansowanym, opartym na dynamicznie wygenerowanych proxy 
Kluczem do dynamicznego proxy jest endpoint /signalr/hubs/, który generuje kod kliencki na podstawie kodu w .NET. Kod taki można także wygenerować statycznie za pomocą narzędzie signalr.exe (NuGet Microsoft.AspNet.SignalR.Utils).

Przykładowe wywołania klienckie w oparciu o dynamic proxy.
<script>
    $(function () {
        var hub = $.connection.modernChat;

        hub.client.newMessage = function(msg){
         console.log(msg);
        }

        $.connection.hub
            .start()
            .done(function () {
          hub.server.sendMessage('Hello');    
            });
    });
</script>

Huby stają się propercjami na $.connection. Wszystkie metody pogrupowane są w hub.server.* (metody zdefiniowane po stronie serwera) oraz hub.client.* (metody klienckie wołane przez serwer). Wywołanie metody start rozpoczyna asynchroniczne negocjowanie protokołu i zwraca obiekt promise. Jako parametr można przekazać obiekt, w którym wybierzemy, z jakich sposobów transportu chcemy korzystać (SignalR wybierze ten najlepszy).

var started = hub.start({
    transport: [
        'webSockets',
        'longPolling',
        'serverSentEvents',
        'foreverFrame'
    ]
});

started.done(function () {
    console.log('connected, transport: ' +
       hub.transport.name);
});

Do celów diagnostycznych warto uruchomić po stronie klienckiej tryb konsolowego logowania za pomocą poniższego polecenia.

$.connection.hub.logging = true;

Przy użyciu late binding możemy uzyskać identyczny jak powyżej efekt w poniższy sposób.


var connection = $.hubConnection();
var proxy = connection.createHubProxy('modernChat');
proxy.on('newMessage', function(msg){
 console.log(msg);
});
connection.start();
proxy.invoke('sendMessage', 'Hello');

poniedziałek, 15 grudnia 2014

[C#|Visual Studio] ASP .NET SignalR: Hubs

Kod serwerowy można pisać na dwóch poziomach abstrakcji. Niskopoziomowo możemy wykorzystać tzw. Persistent Connection, natomiast prostszym modelem, wystarczającym do większości potrzeb są Huby. Hub można postrzegać jako zbiór metod wystawionych przez serwer do dwukierunkowej komunikacji z klientem. Nazwy metod powinny odpowiadać biznesowym operacjom, dlatego zasadna wydaje się analogia do kontrolerów ze wzorca MVC. Nie powinniśmy nigdzie w kodzie przechowywać referencji do naszych hubów - nie mamy kontroli nad ich cyklem życia, a zatem nie warto także przechowywać stanu bezpośrednio w hubie. Każda publiczna metoda może być wołana z zewnątrz (zostanie dodana do dynamicznie generowanego klienckiego proxy). Serwer może też wołać dowolną metodę kliencką dzięki Dynamic Language Runtime. Wywołanie takie sprowadzi się do serializacji metody i jej parametrów. Domyślnym serializatorem jest JSON.NET.

[HubName("modernChat")]
public class ModernChatHub : Hub
{
    public void SendMessage(string message)
    {
        Clients.All.newMessageFrom(Context.ConnectionId);
        Clients.Caller.acknowledged();
        Clients.Others.postMessage(message);
    }

    public void Subscribe(string groupName)
    {
        Groups.Add(Context.ConnectionId, groupName);
    }

    public void Unsubscribe(string groupName)
    {
        Groups.Remove(Context.ConnectionId, groupName);
    }

    public void Hello(string groupName)
    {
        var msg = string.Format("Welcome from {0}",
            groupName);
        Clients.Group(groupName).greetings(msg);
    }

    public override Task OnConnected()
    {
        var dependencyResolver = GlobalHost.DependencyResolver;
        var connectionManager = dependencyResolver.Resolve<IConnectionManager>();
        var hubContext = connectionManager.GetHubContext<ModernChatHub>();
        var all = hubContext.Clients.All;
        all.connected(Context.ConnectionId);
        return base.OnConnected();
    }
}

Mamy do dyspozycji kilka możliwości przetwarzania wiadomości. Możemy skorzystać z property Clients, wysyłając wiadomości do nadawcy, do wszystkich, do wszystkich poza nadawcą. Można także selektywnie wybierać odbiorców po id połączenia. Property Context zawiera także cookies, tożsamość użytkownika czy query string.

Kolejnym modelem są grupy agregujące użytkowników wg pewnego klucza. Trzeba pamiętać, że SignalR w żaden sposób nie przechowuje stanu po stronie serwera, co otwiera znakomite możliwości skalowalności, ale też nie zapamięta nam tego, kto był w której grupie przy restarcie aplikacji. Grupa jest zatem jedynie zrzeszeniem kilku połączeń. Grupy są tworzone w sposób dynamiczny (jeżeli łączymy się do grupy, która nie istnieje, to zostanie założona). Jedno połączenie może być skojarzone z wieloma grupami.

Ostatni przykład, to zdarzenia, do których mamy dostęp z poziomu Hub-a, takie jak OnConnected, OnDisconnected oraz OnReconnected. Wewnątrz nich możemy wołać dowolny kod. Jeżeli chcemy notyfikować podłączonych klientów spoza Huba, możemy skorzystać z DependencyResolvera (odpowiednik ServiceLocatora).

[C#|Visual Studio] ASP .NET SignalR: Wprowadzenie

ASP .NET SignalR to genialny framework rozwiązujący problem notyfikacji serwerowych i komunikacji typu push. Wraz z rozwojem sieci i technologii z nią związanych, pojawia się potrzeba tworzenia serwisów dostarczających dane użytkownikom "w czasie rzeczywistym" i takich, które będą w stanie same dostarczać dane na dowolne urządzenie (przeglądarka, desktop, aplikacje mobilne). Całą sieć do tej pory opierała się głównie na protokole HTTP, który jest mechanizmem typu pull (klient wysyła request i otrzymuje odpowiedź od serwera). Serwis typu push działa tak, że otwiera połączenia od klientów i notyfikuje ich o zmianach w jakimś źródle danych (np. w tabeli bazy danych). Podobnie działają mechanizmy typu publish - subscribe (np. MSMQ), ale potrzebujemy czegoś, co będzie dobrze działało na każdej platformie i każdym urządzeniu.

Programowanie w SignalR daje właśnie taki model ideowy zapewniając dobór technologii odpowiadającej możliwościom urządzenia klienckiego. Serwisy typu push są w SignalR zaimplementowane na cztery sposoby, rozpoczynając od tych najmniej wydajnych, a kończąc na najwydajniejszych:

  1. Long polling - mechanizm cyklicznego odpytywania serwera AJAX-owymi zapytaniami. Zapytanie takie ma ustawiony długi timeout (np. 30 sekund), a serwer nie odpowiada na nie od razu, ale w momencie, gdy pojawią mu się jakieś dane do wysłania. Jeżeli serwer nie ma nic ciekawego do wysłania, to nie wysyła odpowiedzi, a klient ponowi żądanie za 30 sekund
  2. Forever frame - po stronie klienta pojawia się ukryty iFrame, który wysyła zapytanie do serwera. Serwer zwraca odpowiedzi z nagłówkiem Transfer-encoding: chunked, który pozwala na wysłanie odpowiedzi w kilku paczkach. Każda taka wiadomość jest wysyłana tylko wtedy, kiedy na serwerze pojawią się nowe dane. Serwer wysyła wiadomości, które wstrzykują skrypt wywołujący jakąś metodę po stronie klienta.
  3.       
  4. Server-sent events - jednokierunkowy model komunikacji, w którym serwer wysyła do klienta zdarzenia. Wykorzystuje ideę persistent connection (reużywania połączenia TCP do wysłania wielu requestów / responsów w oparciu o nagłówek connection: 'keep-alive'). Wiadomości takie wykorzystują specjalny content-type: text/event-stream, a po stronie klienta także obiekt EventSource
  5. WebSocket - komunikacja dwukierunkowa, oparta na prostym API WebSocket ze specyfikacji HTML5. Przeglądarka negocjuje z serwerem upgrade protokołu z HTTP/HTTPS na odpowiednio WS lub WSS i jeżeli serwer wyrazi zgodę (kod HTTP 101), to połaczenie TCP/IP zostanie użyte do otwarcia dwukierunkowego kanału pomiędzy klientem, a serwerem. Po stronie JS mamy do dyspozycji obiekt WebSocket.
SignalR może być osadzony w aplikacji ASP.NET lub jako self-host. Pracę z tym frameworkiem najlepiej rozpocząć od dodania kilku NuGetów:



Następnie tworzymy najprostszy rodzaj huba - echo, które będzie odpowiadało na klienckie wiadomości.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WebApp.Start<WsStartup>("http://localhost:1968"))
            {
                Console.WriteLine("Server running!");
                Console.ReadLine();
            }
        }
    }

    public class WsStartup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.MapSignalR();
        }
    }

    [HubName("echo")]
    public class EchoHub : Hub
    {
        public string Call(string text)
        {
            return text + " from hub";
        }
    }
}

Wywołanie metody WebApp.Start("http://localhost:1968") powoduje zainicjalizowanie endpointów SignalR za pomocą klasy Startup pod wyspecyfikowanym adresem. Atrybut HubName określna przyjazną nazwę, po której będzie łączył się do niego klient. 

Najprostszy przykład kodu klienckiego (wysyłający wiadomość i wyświetlający odpowiedź) wygląda następująco:
 

<!DOCTYPE html>
<html >
<head>
    <title></title>
    <script src="Scripts/jquery-2.1.0.js"></script>
    <script src="Scripts/jquery.signalR-2.0.2.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
        $(function () {
            var hub = $.connection.echo;
            $.connection.hub
                .start()
                .done(function () {
                    hub.server.call('Hello SignalR!').done(function(msg){
                      alert(msg);
                    });;
                });
        });
    </script>
</head>
<body>
</body>
</html>

Trzeci tag <script> wskazuje na dynamiczny endpoint /signalr/hubs wystawiony przez serwer. Endpoint ten generuje w locie kod JS na podstawie dostępnych hubów. Dzięki niemu możemy pobrać referencję do naszego huba ($.connection.echo). Następnie w asynchroniczny sposób zostaje wołana metoda start. Metoda ta zwraca obiekt promise, w którym możemy zasubskrybować się na metodzie done, gdzie możemy wołać kod z naszego huba.