przewodnik interfejsu API usługi ASP.NET SignalR Hubs — klient platformy .NET (C#)

Ostrzeżenie

Ta dokumentacja nie dotyczy najnowszej wersji usługi SignalR. Przyjrzyj się ASP.NET Core SignalR.

Ten dokument zawiera wprowadzenie do korzystania z interfejsu API usługi Hubs dla usługi SignalR w wersji 2 na klientach platformy .NET, takich jak Sklep Windows (WinRT), WPF, Silverlight i aplikacje konsolowe.

Interfejs API usługi SignalR Hubs umożliwia wykonywanie zdalnych wywołań procedur (RPC) z serwera do połączonych klientów i od klientów do serwera. W kodzie serwera definiuje się metody, które mogą być wywoływane przez klientów, a metody uruchamiane na kliencie. W kodzie klienta definiuje się metody, które mogą być wywoływane z serwera, a metody uruchamiane na serwerze. Usługa SignalR zajmuje się całą instalacją wodną typu klient-serwer.

Usługa SignalR oferuje również interfejs API niższego poziomu o nazwie Połączenia trwałe. Aby zapoznać się z wprowadzeniem do usługi SignalR, centrów i połączeń trwałych lub samouczka przedstawiającego sposób kompilowania kompletnej aplikacji SignalR, zobacz SignalR — Wprowadzenie.

Wersje oprogramowania używane w tym temacie

Poprzednie wersje tego tematu

Aby uzyskać informacje o wcześniejszych wersjach usługi SignalR, zobacz SignalR Starsze wersje.

Pytania i komentarze

Przekaż opinię na temat tego, jak ci się podobał ten samouczek i co możemy ulepszyć w komentarzach w dolnej części strony. Jeśli masz pytania, które nie są bezpośrednio związane z tym samouczkiem, możesz opublikować je na forum ASP.NET SignalR lub StackOverflow.com.

Omówienie

Ten dokument zawiera następujące sekcje:

Aby zapoznać się z przykładowymi projektami klienta platformy .NET, zobacz następujące zasoby:

Aby uzyskać dokumentację dotyczącą programowania klientów serwera lub języka JavaScript, zobacz następujące zasoby:

Linki do tematów referencyjnych interfejsu API to wersja interfejsu API platformy .NET 4.5. Jeśli używasz platformy .NET 4, zobacz tematy dotyczące platformy .NET 4 interfejsu API.

Konfiguracja klienta

Zainstaluj pakiet NuGet Microsoft.AspNet.SignalR.Client (a nie pakiet Microsoft.AspNet.SignalR ). Ten pakiet obsługuje klientów WinRT, Silverlight, WPF, aplikacji konsolowej i Windows Phone dla platformy .NET 4 i .NET 4.5.

Jeśli wersja usługi SignalR, która znajduje się na kliencie, różni się od wersji serwera, usługa SignalR jest często w stanie dostosować się do różnicy. Na przykład serwer z usługą SignalR w wersji 2 będzie obsługiwać klientów z zainstalowanym programem 1.1.x, a także klientami z zainstalowaną wersją 2. Jeśli różnica między wersją na serwerze a wersją na kliencie jest zbyt duża lub jeśli klient jest nowszy niż serwer, usługa SignalR zgłasza InvalidOperationException wyjątek, gdy klient próbuje nawiązać połączenie. Komunikat o błędzie to "You are using a version of the client that isn't compatible with the server. Client version X.X, server version X.X".

Jak nawiązać połączenie

Przed nawiązaniem połączenia należy utworzyć HubConnection obiekt i utworzyć serwer proxy. Aby ustanowić połączenie, wywołaj metodę StartHubConnection w obiekcie .

using (var hubConnection = new HubConnection("http://www.contoso.com/")) 
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Uwaga

W przypadku klientów języka JavaScript należy zarejestrować co najmniej jedną procedurę obsługi zdarzeń przed wywołaniem Start metody w celu nawiązania połączenia. Nie jest to konieczne w przypadku klientów platformy .NET. W przypadku klientów javaScript wygenerowany kod serwera proxy automatycznie tworzy serwery proxy dla wszystkich centrów, które istnieją na serwerze, a zarejestrowanie programu obsługi jest sposobem wskazywania, które centra mają być używane przez klienta. Jednak w przypadku klienta platformy .NET tworzysz serwery proxy koncentratora ręcznie, dlatego usługa SignalR zakłada, że będziesz używać dowolnego centrum, dla którego tworzysz serwer proxy.

Przykładowy kod używa domyślnego adresu URL "/signalr", aby nawiązać połączenie z usługą SignalR. Aby uzyskać informacje na temat określania innego podstawowego adresu URL, zobacz przewodnik interfejsu API usługi ASP.NET SignalR Hubs — serwer — adres URL /signalr.

Metoda Start jest wykonywana asynchronicznie. Aby upewnić się, że kolejne wiersze kodu nie są wykonywane dopiero po nawiązaniu połączenia, użyj await metody asynchronicznej ASP.NET 4.5 lub .Wait() w metodzie synchronicznej. Nie używaj .Wait() go w kliencie WinRT.

await connection.Start();
connection.Start().Wait();

Połączenia między domenami z klientów programu Silverlight

Aby uzyskać informacje na temat włączania połączeń między domenami z klientów silverlight, zobacz Udostępnianie usługi w granicach domeny.

Jak skonfigurować połączenie

Przed nawiązaniem połączenia można określić dowolną z następujących opcji:

  • Limit połączeń współbieżnych.
  • Parametry ciągu zapytania.
  • Metoda transportu.
  • Nagłówki HTTP.
  • Certyfikaty klienta.

Jak ustawić maksymalną liczbę połączeń współbieżnych na klientach WPF

W przypadku klientów WPF może być konieczne zwiększenie maksymalnej liczby połączeń współbieżnych z wartości domyślnej 2. Zalecana wartość to 10.

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    ServicePointManager.DefaultConnectionLimit = 10;
    await hubConnection.Start();
}

Aby uzyskać więcej informacji, zobacz ServicePointManager.DefaultConnectionLimit.

Jak określić parametry ciągu zapytania

Jeśli chcesz wysłać dane na serwer, gdy klient nawiąż połączenie, możesz dodać parametry parametrów zapytania do obiektu połączenia. W poniższym przykładzie pokazano, jak ustawić parametr ciągu zapytania w kodzie klienta.

var querystringData = new Dictionary<string, string>();
querystringData.Add("contosochatversion", "1.0");
var connection = new HubConnection("http://contoso.com/", querystringData);

W poniższym przykładzie pokazano, jak odczytać parametr ciągu zapytania w kodzie serwera.

public class StockTickerHub : Hub
{
    public override Task OnConnected()
    {
        var version = Context.QueryString["contosochatversion"];
        if (version != "1.0")
        {
            Clients.Caller.notifyWrongVersion();
        }
        return base.OnConnected();
    }
}

Jak określić metodę transportu

W ramach procesu nawiązywania połączenia klient usługi SignalR zwykle negocjuje z serwerem w celu określenia najlepszego transportu obsługiwanego przez serwer i klienta. Jeśli wiesz już, którego transportu chcesz użyć, możesz pominąć ten proces negocjacji. Aby określić metodę transportu, przekaż obiekt transportowy do metody Start. W poniższym przykładzie pokazano, jak określić metodę transportu w kodzie klienta.

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start(new LongPollingTransport());
}

Przestrzeń nazw Microsoft.AspNet.SignalR.Client.Transports zawiera następujące klasy, których można użyć do określenia transportu.

  • LongPollingTransport
  • ServerSentEventsTransport
  • WebSocketTransport (dostępne tylko wtedy, gdy zarówno serwer, jak i klient używają platformy .NET 4.5).
  • AutoTransport (automatycznie wybiera najlepszy transport obsługiwany przez klienta i serwer. Jest to domyślny transport. Przekazanie tego elementu do Start metody ma taki sam efekt, jak brak przekazywania żadnych elementów).

Transport ForeverFrame nie znajduje się na tej liście, ponieważ jest używany tylko przez przeglądarki.

Aby uzyskać informacje o sposobie sprawdzania metody transportu w kodzie serwera, zobacz ASP.NET SignalR Hubs API Guide - Server — How to get information about the client from the Context property (Przewodnik po interfejsie API usługi SignalR Hubs — serwer — jak uzyskać informacje o kliencie z właściwości Context). Aby uzyskać więcej informacji na temat transportu i rezerwowych, zobacz Wprowadzenie do usługi SignalR — transporty i rezerwowe.

Jak określić nagłówki HTTP

Aby ustawić nagłówki HTTP, użyj Headers właściwości w obiekcie połączenia. W poniższym przykładzie pokazano, jak dodać nagłówek HTTP.

hubConnection = new hubConnection("http://www.contoso.com/");
connection.Headers.Add("headername", "headervalue");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await connection.Start();

Jak określić certyfikaty klienta

Aby dodać certyfikaty klienta, użyj AddClientCertificate metody w obiekcie połączenia.

hubConnection = new hubConnection("http://www.contoso.com/");
hubConnection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await connection.Start();

Jak utworzyć serwer proxy centrum

Aby zdefiniować metody na kliencie, który centrum może wywołać z serwera i wywołać metody w centrum na serwerze, utwórz serwer proxy dla centrum, wywołując CreateHubProxy obiekt połączenia. Przekazany CreateHubProxy ciąg to nazwa klasy Hub lub nazwa określona przez HubName atrybut, jeśli została użyta na serwerze. Dopasowanie nazwy jest bez uwzględniania wielkości liter.

Klasa koncentratora na serwerze

public class StockTickerHub : Hub

Tworzenie serwera proxy klienta dla klasy Hub

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Jeśli udekorujesz klasę Hub atrybutem HubName , użyj tej nazwy.

Klasa koncentratora na serwerze

[HubName("stockTicker")]
public class StockTickerHub : Hub

Tworzenie serwera proxy klienta dla klasy Hub

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("stockTicker");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
        Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Jeśli wywołasz wiele HubConnection.CreateHubProxy razy z tym samym hubNameobiektem , otrzymasz ten sam obiekt w pamięci podręcznej IHubProxy .

How to define methods on the client that the server can call (Jak zdefiniować metody na kliencie, który może wywołać serwer)

Aby zdefiniować metodę, którą serwer może wywołać, użyj metody serwera proxy On , aby zarejestrować procedurę obsługi zdarzeń.

Dopasowanie nazwy metody jest bez uwzględniania wielkości liter. Na przykład Clients.All.UpdateStockPrice na serwerze zostanie wykonane updateStockPricepolecenie , updatestockpricelub UpdateStockPrice na kliencie.

Różne platformy klienckie mają różne wymagania dotyczące sposobu pisania kodu metody w celu zaktualizowania interfejsu użytkownika. Pokazano przykłady dla klientów WinRT (Windows Store .NET). Przykłady aplikacji WPF, Silverlight i konsoli znajdują się w oddzielnej sekcji w dalszej części tego tematu.

Metody bez parametrów

Jeśli obsługiwana metoda nie ma parametrów, użyj przeciążenia On innego niż ogólny metody:

Kod serwera wywołujący metodę klienta bez parametrów

public class StockTickerHub : Hub
{
    public void NotifyAllClients()
    {
         Clients.All.Notify();
    }
}

Kod klienta WinRT dla metody wywoływanej z serwera bez parametrów (zobacz przykłady WPF i Silverlight w dalszej części tego tematu)

using (var hubConnection = new HubConnection("http://www.contoso.com/")) 
{
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHub.On("notify", () =>
        // Context is a reference to SynchronizationContext.Current
        Context.Post(delegate
        {
            textBox.Text += "Notified!\n";
        }, null)
    );
    await hubConnection.Start();
}

Metody z parametrami, określając typy parametrów

Jeśli obsługiwana metoda ma parametry, określ typy parametrów jako typy On ogólne metody. Istnieją ogólne przeciążenia On metody, aby umożliwić określenie maksymalnie 8 parametrów (4 w Windows Phone 7). W poniższym przykładzie do metody jest wysyłany UpdateStockPrice jeden parametr.

Kod serwera wywołujący metodę klienta z parametrem

public void BroadcastStockPrice(Stock stock)
{
    context.Clients.Others.UpdateStockPrice(stock);
}

Klasa Stock używana dla parametru

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

Kod klienta WinRT dla metody wywoływanej z serwera z parametrem (zobacz przykłady WPF i Silverlight w dalszej części tego tematu)

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Metody z parametrami, określając obiekty dynamiczne dla parametrów

Alternatywą dla określenia parametrów jako typów On ogólnych metody można określić parametry jako obiekty dynamiczne:

Kod serwera wywołujący metodę klienta z parametrem

public void BroadcastStockPrice(Stock stock)
{
    context.Clients.Others.UpdateStockPrice(stock);
}

Klasa Stock używana dla parametru

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

Kod klienta WinRT dla metody wywoływanej z serwera z parametrem przy użyciu obiektu dynamicznego dla parametru (zobacz przykłady WPF i Silverlight w dalszej części tego tematu)

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Jak usunąć procedurę obsługi

Aby usunąć procedurę obsługi, wywołaj metodę Dispose .

Kod klienta metody wywoływanej z serwera

var updateStockPriceHandler = stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Kod klienta w celu usunięcia programu obsługi

updateStockPriceHandler.Dispose();

Jak wywoływać metody serwera od klienta

Aby wywołać metodę na serwerze, użyj Invoke metody na serwerze proxy centrum.

Jeśli metoda serwera nie ma wartości zwracanej, użyj przeciążenia Invoke innego niż ogólne metody .

Kod serwera dla metody, która nie ma wartości zwracanej

public class StockTickerHub : Hub
{
    public void JoinGroup(string groupName)
    {
        Groups.Add(Context.ConnectionId, groupName); 
    }
}

Kod klienta wywołujący metodę, która nie ma wartości zwracanej

stockTickerHubProxy.Invoke("JoinGroup", "SignalRChatRoom");

Jeśli metoda serwera ma wartość zwracaną, określ typ zwracany jako typ Invoke ogólny metody.

Kod serwera dla metody, która ma wartość zwracaną i przyjmuje parametr typu złożonego

public IEnumerable<Stock> AddStock(Stock stock)
{
    _stockTicker.AddStock(stock);
    return _stockTicker.GetAllStocks();
}

Klasa Stock używana dla parametru i wartości zwracanej

public class Stock
{
    public string Symbol { get; set; }
    public decimal Price { get; set; }
}

Kod klienta wywołujący metodę, która ma wartość zwracaną i przyjmuje złożony parametr typu w metodzie asynchronicznej ASP.NET 4.5

var stocks = await stockTickerHub.Invoke<IEnumerable<Stock>>("AddStock", new Stock() { Symbol = "MSFT" });
foreach (Stock stock in stocks)
{
    textBox.Text += string.Format("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}

Kod klienta wywołujący metodę, która ma wartość zwracaną i przyjmuje parametr typu złożonego w metodzie synchronicznej

var stocks = stockTickerHub.Invoke<IEnumerable<Stock>>("AddStock", new Stock() { Symbol = "MSFT" }).Result;
foreach (Stock stock in stocks)
{
    textBox.Text += string.Format("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}

Metoda Invoke wykonuje asynchronicznie i zwraca Task obiekt. Jeśli nie określisz await polecenia lub .Wait(), zostanie wykonany następny wiersz kodu przed zakończeniem wykonywania wywoływanej metody.

Jak obsługiwać zdarzenia okresu istnienia połączenia

Usługa SignalR udostępnia następujące zdarzenia okresu istnienia połączenia, które można obsłużyć:

  • Received: Wywoływane, gdy jakiekolwiek dane są odbierane w połączeniu. Udostępnia odebrane dane.
  • ConnectionSlow: Wywoływane, gdy klient wykryje powolne lub często upuszczanie połączenia.
  • Reconnecting: Podniesione, gdy podstawowy transport rozpoczyna ponowne nawiązywanie połączenia.
  • Reconnected: podniesione po ponownym połączeniu transportu bazowego.
  • StateChanged: Wywoływane po zmianie stanu połączenia. Zapewnia stary stan i nowy stan. Aby uzyskać informacje o wartościach stanu połączenia, zobacz ConnectionState, wyliczenie.
  • Closed: Podniesiono, gdy połączenie zostało rozłączone.

Jeśli na przykład chcesz wyświetlić komunikaty ostrzegawcze dotyczące błędów, które nie są krytyczne, ale powodują sporadyczne problemy z połączeniem, takie jak spowolnienie lub częste upuszczanie połączenia, obsługa ConnectionSlow zdarzenia.

hubConnection.ConnectionSlow += () => Console.WriteLine("Connection problems.");

Aby uzyskać więcej informacji, zobacz Opis i obsługa zdarzeń okresu istnienia połączenia w usłudze SignalR.

Jak obsługiwać błędy

Jeśli nie włączysz jawnie szczegółowych komunikatów o błędach na serwerze, obiekt wyjątku zwracany przez usługę SignalR po błędzie zawiera minimalne informacje o błędzie. Jeśli na przykład wywołanie newContosoChatMessage zakończy się niepowodzeniem, komunikat o błędzie w obiekcie błędu zawiera "There was an error invoking Hub method 'contosoChatHub.newContosoChatMessage'." Wysyłanie szczegółowych komunikatów o błędach do klientów w środowisku produkcyjnym nie jest zalecane ze względów bezpieczeństwa, ale jeśli chcesz włączyć szczegółowe komunikaty o błędach na potrzeby rozwiązywania problemów, użyj następującego kodu na serwerze.

var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
App.MapSignalR(hubConfiguration);

Aby obsłużyć błędy wywoływane przez usługę SignalR, można dodać procedurę obsługi dla Error zdarzenia w obiekcie połączenia.

hubConnection.Error += ex => Console.WriteLine("SignalR error: {0}", ex.Message);

Aby obsłużyć błędy z wywołań metod, opakuj kod w bloku try-catch.

try
{
    IEnumerable<Stock> stocks = await stockTickerHub.Invoke<IEnumerable<Stock>>("GetAllStocks");
    foreach (Stock stock in stocks)
    {
        Console.WriteLine("Symbol: {0} price: {1}", stock.Symbol, stock.Price);
    }
}
catch (Exception ex)
{
    Console.WriteLine("Error invoking GetAllStocks: {0}", ex.Message);
}

Jak włączyć rejestrowanie po stronie klienta

Aby włączyć rejestrowanie po stronie klienta, ustaw TraceLevel właściwości i TraceWriter dla obiektu połączenia.

using (var hubConnection = new HubConnection("http://www.contoso.com/"))
{
    hubConnection.TraceLevel = TraceLevels.All;
    hubConnection.TraceWriter = Console.Out;
    IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
    stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
    await hubConnection.Start();
}

Przykłady kodu aplikacji WPF, Silverlight i konsoli dla metod klienckich, które serwer może wywołać

Przykłady kodu pokazane wcześniej do definiowania metod klienta, które serwer może wywołać do klientów WinRT. W poniższych przykładach pokazano odpowiedni kod dla klientów aplikacji WPF, Silverlight i konsolowych.

Metody bez parametrów

Kod klienta WPF dla metody wywoływanej z serwera bez parametrów

stockTickerHub.On<Stock>("notify", () =>
    Dispatcher.InvokeAsync(() =>
        {
            SignalRTextBlock.Text += string.Format("Notified!");
        })
);

Kod klienta programu Silverlight dla metody wywoływanej z serwera bez parametrów

stockTickerHub.On<Stock>("notify", () =>
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += "Notified!";
    }, null)
);

Kod klienta aplikacji konsoli dla metody wywoływanej z serwera bez parametrów

stockTickerHubProxyProxy.On("Notify", () => Console.WriteLine("Notified!"));

Metody z parametrami, określając typy parametrów

Kod klienta WPF dla metody wywoływanej z serwera z parametrem

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Dispatcher.InvokeAsync(() =>
        {
            textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
        })
);

Kod klienta programu Silverlight dla metody wywoływanej z serwera z parametrem

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Kod klienta aplikacji konsoli dla metody wywoływanej z serwera z parametrem

stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => 
    Console.WriteLine("Symbol {0} Price {1}", stock.Symbol, stock.Price));

Metody z parametrami, określając obiekty dynamiczne dla parametrów

Kod klienta WPF dla metody wywoływanej z serwera z parametrem przy użyciu obiektu dynamicznego dla parametru

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    Dispatcher.InvokeAsync(() =>
        {
            textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
        })
);

Kod klienta programu Silverlight dla metody wywoływanej z serwera z parametrem przy użyciu obiektu dynamicznego dla parametru

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    // Context is a reference to SynchronizationContext.Current
    Context.Post(delegate
    {
        textBox.Text += string.Format("Stock update for {0} new price {1}\n", stock.Symbol, stock.Price);
    }, null)
);

Kod klienta aplikacji konsoli dla metody wywoływanej z serwera z parametrem przy użyciu obiektu dynamicznego dla parametru

stockTickerHubProxy.On("UpdateStockPrice", stock => 
    Console.WriteLine("Symbol {0} Price {1}", stock.Symbol, stock.Price));