ASP.NET: SignalR

Aplikacje webowe przeszły rewolucje od czasów pierwszych stron internetowych. Przez długi czas, aplikacje webowe opierały się na prostym schemacie zapytania i odpowiedzi. Wpisując jakiś adres w przeglądarce, generowany był po prostu dokument. Nie było możliwości interakcji. Nawigacja do innej strony, skutkowała przeładowaniem całej strony.

Później pojawił się AJAX, czyli wykonywanie metod usługi w tle. Był to na pewno krok do przodu ponieważ nie było potrzebne już przeładowanie całej strony, aby odświeżyć jakiś tylko fragment. Niestety wciąż była to komunikacja jednokierunkowa, od przeglądarki do serwera. W przeciwnym kierunku byłoby to możliwe wyłącznie poprzez przeładowanie całej strony. Nie istniał wtedy sposób na  łatwe powiadomienie przeglądarki, że stan bazy danych zmienił się.

Możliwe były oczywiście pewne obejścia. Najczęściej przeglądarka odpytywała serwer, czy są już jakieś zmiany, które powinny być odzwierciedlone w przeglądarce. Oczywiście w aplikacjach czasu rzeczywistego nie jest to perfekcyjne rozwiązanie, ponieważ wiąże się z dużym obciążeniem łącza i wynikającymi z tego opóźnieniami.

Dzisiaj na szczęście mamy inne, lepsze rozwiązania. Nie będę opisywał w tym poście szczegółów, ponieważ, chcę najpierw skupić się na samym framework’u SignalR, a potem dopiero prześledzimy jego internale.

W skrócie, tzw. Web Socket API umożliwia pełną komunikację między przeglądarką a serwerem. Możliwe jest zatem dzięki Web Socket, że klient wysyła w tle wiadomość do serwera (nic nadzwyczajnego) oraz serwer do przeglądarki (i to jest nowość). Jest to ogólny standard i nie ma nic wspólnego z ASP.NET. Ponadto, nie jest on wyłącznie ograniczony do przeglądarek internetowych. Działa zwykle na porcie 80 (korzystne dla firewalls itp.).

W HTTML 5 API do dyspozycji są tzw. Serer-Sent Events. Dzięki nim, serwer może powiadomić przeglądarkę o zmianach. Jest to jednak komunikacja również jednokierunkowa, od serwera do klienta.

SignalR jest z kolei frameworkiem dla ASP.NET ułatwiającym pisanie aplikacji czasu rzeczywistego, czyli takich gdzie nie chcemy przeładowywać całej strony bo dane zmieniają się w czasie “rzeczywistym”. Oczywiście kluczowym mechanizmem w takiej scenariuszu jest powiadomienie klientów o zmianach na serwerze. Można oczywiście bezpośrednio korzystać z Web Socket czy HTTML 5 SSE. Problem w tym, że część przeglądarek nie wspiera Web Socket ani SSE. SignalR za nas dostarczy warstwę abstrakcji, czyli wykorzysta najlepszą, dostępną aktualnie technologie.

Jeśli przeglądarka i serwer dostarczają Web Socket, to zostanie on oczywiście wykorzystany bo jest jedynym w pełni dwukierunkowym sposobem komunikacji. W przeciwnym razie HTML 5 SSE  może zostać użyty. W najgorszym przypadku, po prostu stary mechanizm odpytywania zostanie wykonany. Dzięki SignalR, programista ma jeden framework i nie interesuje go, co dokładnie przeglądarka wspiera. Framework dobierze najlepszą technologie jaka jest aktualnie dostępna. Programista  korzysta zawsze z tego samego API.

W SignalR do dyspozycji mamy dwa typy połączeń. PersistentConnection oraz HubAPI. Pierwszy z nic jest bardziej niskopoziomowy i dlatego dzisiaj nim zajmiemy się. W przyszłym wpisie pokażę Hub API.

Zaczynamy oczywiście od instalacji SignalR z NuGet:

image

NuGet zainstaluje pakiet, w którego skład wchodzą m.in. skrypty JS, biblioteki DLL oraz zostanie również wygenerowany Startup:

[assembly: OwinStartupAttribute(typeof(WebApplication9.Startup))]
namespace WebApplication9
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}

Na razie o Startup nie musimy martwić się. Stwórzmy nasze pierwsze połączenie:

public class MyFirstConnection:PersistentConnection
{
   protected override Task OnReceived(IRequest request, string connectionId, string data)
   {
       return Connection.Broadcast(data);
   }
}

Przeładowujemy tutaj OnReceived, metodę, która jest wywołana, gdy któryś z klientów wyśle jakąś wiadomość. Następnie tą samą wiadomość, przekazujemy do pozostałych (broadcast).

Pora na kod JS, czyli stronę klienta (przykład z dokumentacji SignalR):

$(function () {
        var connection = $.connection('/echo');

        connection.received(function (data) {
            $('#messages').append('<li>' + data + '</li>');
        });

        connection.start().done(function() {
            $("#broadcast").click(function () {
                connection.send($('#msg').val());
            });
        });

    });

Jak widzimy, mamy tutaj kod, polegający na zewnętrznych bibliotekach np. metoda $.connection. Musimy zatem podłączyć bibliotekę jquery.signalR-2.1.0, która została zainstalowana w ramach pakietu SignalR (NuGet). Oprócz tego, musimy dodać referencje do jQuery:

<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.signalR-2.1.0.js"></script>

Ostatnia rzecz jaka nam pozostała to mapowanie. Powyższy przykład, używa metody echo, która nie jest jeszcze zdefiniowana. Można zobaczyć w $.connection, że odwołujemy się do /echo, ale póki co nie zaimplementowaliśmy tego. Wystarczy, że zmapujemy /echo do naszego połączenia MyFirstConnection we wspomnianej wcześniej klasie Startup:

public partial class Startup
{
   public void Configuration(IAppBuilder app)
   {
       ConfigureAuth(app);
       app.MapSignalR<MyFirstConnection>("/echo");
   }
}

Po uruchomieniu aplikacji, szybko przekonamy się, że wpisując dane w oknie jednej przeglądarki, zostaną one rozesłane do pozostałych, podłączonych klientów (broadcast).

2 thoughts on “ASP.NET: SignalR”

  1. Hej, da się zrobić w Windows Forms coś takiego, żeby odświeżył się grid, gdy rekord zostanie dodany do bazy?

Leave a Reply

Your email address will not be published.