руководство по API ASP.NET SignalR Hubs — клиент .NET (C#)

Предупреждение

Эта документация не подходит для последней версии SignalR. Взгляните на ASP.NET Core SignalR.

В этом документе приведены общие сведения об использовании API Центров для SignalR версии 2 в клиентах .NET, таких как Магазин Windows (WinRT), WPF, Silverlight и консольные приложения.

API Центров SignalR позволяет выполнять удаленные вызовы процедур с сервера к подключенным клиентам и от клиентов к серверу. В коде сервера определяются методы, которые могут вызываться клиентами, и вы вызываете методы, которые выполняются на клиенте. В клиентском коде определяются методы, которые могут вызываться с сервера, и вы вызываете методы, которые выполняются на сервере. SignalR берет на себя всю организацию связи между клиентом и сервером.

SignalR также предлагает API нижнего уровня с именем "Постоянные подключения". Общие сведения о SignalR, Центрах и постоянных подключениях или руководстве по созданию полного приложения SignalR см. в разделе "Начало работы".

Версии программного обеспечения, используемые в этом разделе

Предыдущие версии этого раздела

Сведения о более ранних версиях SignalR см. в разделе SignalR более ранних версий.

Вопросы и комментарии

Оставьте отзыв о том, как вам понравилось это руководство и что, по вашему мнению, мы можем улучшить в комментариях в нижней части страницы. Если у вас есть вопросы, которые не связаны напрямую с руководством, их можно опубликовать на форуме ASP.NET SignalR или StackOverflow.com.

Обзор

Этот документ содержит следующие разделы:

Примеры клиентских проектов .NET см. в следующих ресурсах:

Документацию по программе серверов или клиентов JavaScript см. в следующих ресурсах:

Ссылки на разделы справки API относятся к версии API .NET 4.5. Если вы используете .NET 4, ознакомьтесь с версией .NET 4 раздела API.

Настройка клиента

Установите пакет NuGet Microsoft.AspNet.SignalR.Client (а не пакет Microsoft.AspNet.SignalR ). Этот пакет поддерживает winRT, Silverlight, WPF, консольное приложение и клиенты Windows Phone для .NET 4 и .NET 4.5.

Если версия SignalR, которую у вас есть на клиенте, отличается от версии, которая есть на сервере, SignalR часто может адаптироваться к разнице. Например, сервер под управлением SignalR версии 2 будет поддерживать клиентов с установленными 1.1.x, а также клиентов с установленными версиями 2. Если разница между версией на сервере и версией на клиенте слишком велика, или если клиент является более новым, чем сервер, SignalR создает InvalidOperationException исключение при попытке установить подключение. Сообщение об ошибке — "You are using a version of the client that isn't compatible with the server. Client version X.X, server version X.X".

Как установить подключение

Прежде чем установить подключение, необходимо создать HubConnection объект и создать прокси-сервер. Чтобы установить соединение, вызовите метод Start на объекте HubConnection.

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();
}

Замечание

Для клиентов JavaScript необходимо зарегистрировать по крайней мере один обработчик событий перед вызовом Start метода для установления подключения. Это не обязательно для клиентов .NET. Для клиентов JavaScript созданный прокси-код автоматически создает прокси-серверы для всех центров, существующих на сервере, и регистрация обработчика заключается в том, как вы указываете, какие центры клиент намерен использовать. Но для клиента .NET вы создаете прокси-серверы Hub вручную, так что SignalR предполагает, что вы будете использовать любой Hub, для которого создаете прокси-сервер.

Пример кода использует URL-адрес "/signalr" по умолчанию для подключения к службе SignalR. Сведения о том, как указать другой базовый URL-адрес, см. в ASP.NET руководстве по API Центров SignalR — сервер — URL-адрес /signalr.

Метод Start выполняется асинхронно. Чтобы убедиться, что последующие строки кода не выполняются до тех пор, пока не будет установлено подключение, используйте await в асинхронном методе ASP.NET 4.5 или .Wait() синхронном методе. Не используйте .Wait() в клиенте WinRT.

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

Подключения между доменами от клиентов Silverlight

Сведения о том, как включить междоменные подключения от клиентов Silverlight, см. в статье "Предоставление доступа к службе через границы домена".

Настройка подключения

Перед установкой подключения можно указать любой из следующих параметров:

  • Ограничение одновременных подключений.
  • Параметры строки запроса.
  • Метод транспорта.
  • HTTP-заголовки.
  • Сертификаты клиента.

Как задать максимальное число одновременных подключений в клиентах WPF

В клиентах WPF может потребоваться увеличить максимальное число одновременных подключений из значения по умолчанию 2. Рекомендуемое значение равно 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();
}

Дополнительные сведения см. в разделе ServicePointManager.DefaultConnectionLimit.

Указание параметров строки запроса

Если вы хотите отправить данные на сервер при подключении клиента, можно добавить параметры строки запроса в объект подключения. В следующем примере показано, как задать параметр строки запроса в клиентском коде.

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

В следующем примере показано, как считывать параметр строки запроса в коде сервера.

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

Указание метода транспорта

В рамках процесса подключения клиент SignalR обычно ведет переговоры с сервером, чтобы определить лучший транспорт, поддерживаемый как сервером, так и клиентом. Если вы уже знаете, какой транспорт вы хотите использовать, можно обойти этот процесс согласования. Чтобы указать метод транспорта, передайте объект транспорта в метод Start. В следующем примере показано, как указать метод транспорта в клиентском коде.

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());
}

Пространство имен Microsoft.AspNet.SignalR.Client.Transports содержит следующие классы, которые можно использовать для указания транспорта.

  • LongPollingTransport
  • ServerSentEventsTransport
  • WebSocketTransport (доступно только в том случае, если сервер и клиент используют .NET 4.5.)
  • AutoTransport (автоматически выбирает лучший транспорт, поддерживаемый как клиентом, так и сервером. Это транспорт по умолчанию. Передача этого транспорта в метод Start имеет тот же эффект, как если бы ничего не передавалось.)

Транспорт ForeverFrame не включен в этот список, так как он используется только браузерами.

Сведения о том, как проверить метод транспорта в коде сервера, см. в ASP.NET руководстве по API Центров SignalR — Сервер. Получение сведений о клиенте из свойства Context. Дополнительные сведения о транспорте и резервных механизмах см. в статье "Введение в SignalR - транспорты и резервные механизмы".

Указание заголовков HTTP

Чтобы задать заголовки HTTP, используйте Headers свойство объекта подключения. В следующем примере показано, как добавить заголовок 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();

Как указывать сертификаты клиента

Чтобы добавить сертификаты клиента, используйте AddClientCertificate метод объекта подключения.

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();

Как создать прокси-сервер хаба

Чтобы определить методы на клиенте, которые концентратор может вызвать с сервера, и вызывать методы концентратора на сервере, создайте прокси для концентратора, вызвав CreateHubProxy на объекте подключения. Строка, которую вы передаете в CreateHubProxy, — это имя класса концентратора или имя, указанное атрибутом HubName, если он использовался на сервере. Сопоставление имен производится без учета регистра.

Класс концентратора на сервере

public class StockTickerHub : Hub

Создание прокси-сервера клиента для класса 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();
}

Если вы добавляете атрибут HubName к классу Hub, используйте это имя.

Класс концентратора на сервере

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

Создание прокси-сервера клиента для класса 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();
}

При многократном вызове HubConnection.CreateHubProxy одного и того же объекта вы получите один и тот же hubNameкэшированный IHubProxy объект.

Как определить методы на клиенте для вызова сервером

Чтобы определить метод, который может вызвать сервер, используйте метод прокси-сервера On для регистрации обработчика событий.

Сопоставление имен методов выполняется без учета регистра. Например, Clients.All.UpdateStockPrice на сервере будет выполняться updateStockPrice, updatestockprice или UpdateStockPrice на клиенте.

Разные клиентские платформы имеют разные требования к написанию кода метода для обновления пользовательского интерфейса. Ниже приведены примеры для клиентов WinRT (Магазин Windows .NET). Примеры приложений WPF, Silverlight и консольного приложения приведены в отдельном разделе далее в этом разделе.

Методы без параметров

Если метод, с которым вы работаете, не имеет параметров, используйте неуниверсальную перегрузку метода On.

Код сервера вызывает метод клиента без параметров

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

Клиентский код WinRT для метода, вызываемого с сервера без параметров (см. примеры WPF и Silverlight далее в этом разделе).

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();
}

Методы с параметрами, указание типов параметров

Если метод, который вы обрабатываете, имеет параметры, укажите типы параметров в качестве универсальных типов On метода. Существуют универсальные перегрузки On метода, позволяющие указать до 8 параметров (4 на Windows Phone 7). В следующем примере один параметр отправляется методу UpdateStockPrice .

Вызов клиентского метода кода сервера с параметром

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

Класс Stock, используемый для параметра

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

Код клиента WinRT для метода, вызываемого с сервера с параметром (см. примеры WPF и Silverlight далее в этом разделе).

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)
);

Методы с параметрами, указание динамических объектов для параметров

В качестве альтернативы указанию параметров в качестве универсальных типов On метода можно указать параметры как динамические объекты:

Вызов клиентского метода кода сервера с параметром

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

Класс Stock, используемый для параметра

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

Код клиента WinRT для метода, вызываемого с сервера с параметром, с помощью динамического объекта для параметра (см. примеры WPF и Silverlight далее в этом разделе).

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)
);

Как удалить обработчик

Чтобы удалить обработчик, вызовите его Dispose метод.

Клиентский код для метода, вызываемого с сервера

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)
);

Клиентский код для удаления обработчика

updateStockPriceHandler.Dispose();

Как вызвать методы сервера из клиента

Чтобы вызвать метод на сервере, используйте Invoke метод на прокси-сервере Концентратора.

Если метод сервера не имеет возвращаемого значения, используйте не обобщённую перегрузку метода Invoke.

Код сервера для метода, не имеющего возвращаемого значения

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

Клиентский код, вызывающий метод, не имеющий возвращаемого значения

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

Если метод сервера имеет возвращаемое значение, укажите тип возвращаемого значения в качестве универсального Invoke типа метода.

Код сервера для метода с возвращаемым значением и принимает сложный параметр типа

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

Класс Stock, используемый для параметра и возвращаемого значения

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

Клиентский код, вызывающий метод с возвращаемым значением и принимающее сложный параметр типа, в асинхронном методе 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);
}

Клиентский код, вызывающий метод, имеющий возвращаемое значение, и принимает сложный параметр типа в синхронном методе.

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);
}

Метод Invoke выполняется асинхронно и возвращает Task объект. Если вы не укажете await или .Wait(), следующая строка кода будет выполняться до завершения выполнения метода, вызываемого вами.

Как обрабатывать события жизненного цикла подключения

SignalR предоставляет следующие события времени существования подключения, которые можно обрабатывать:

  • Received: возникает при получении любых данных на соединении. Предоставляет полученные данные.
  • ConnectionSlow: возникает, когда клиент обнаруживает медленное соединение или частые разрывы подключения.
  • Reconnecting: возникает при начале повторного подключения базового транспорта.
  • Reconnected: возникает при повторном подключении базового транспорта.
  • StateChanged: вызывается при изменении состояния подключения. Предоставляет старое состояние и новое состояние. Сведения о значениях состояния подключения см. в ConnectionState Enumeration.
  • Closed: возникает при отключении подключения.

Например, если вы хотите отобразить предупреждения об ошибках, которые не являются критическими, но вызывают периодические проблемы с подключением, такие как замедление или частый разрыв связи, обработайте ConnectionSlow событие.

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

Дополнительные сведения см. в разделе "Понимание и обработка событий жизненного цикла подключения в SignalR".

Обработка ошибок

Если на сервере нет явного включения подробных сообщений об ошибках, объект исключения, возвращаемый SignalR после ошибки, содержит минимальные сведения об ошибке. Например, если вызов newContosoChatMessage завершается сбоем, сообщение об ошибке в объекте ошибки содержит "There was an error invoking Hub method 'contosoChatHub.newContosoChatMessage'." Отправка подробных сообщений об ошибках клиентам в рабочей среде не рекомендуется по соображениям безопасности, но если вы хотите включить подробные сообщения об ошибках для устранения неполадок, используйте следующий код на сервере.

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

Для обработки ошибок, которые вызывает SignalR, можно добавить обработчик события для Error объекта подключения.

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

Для обработки ошибок при вызове методов заключите код в блок 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);
}

Как включить ведение журнала на стороне клиента

Чтобы включить ведение журнала на стороне клиента, задайте TraceLevelTraceWriter свойства объекта подключения.

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();
}

Примеры кода приложения WPF, Silverlight и консольного приложения для клиентских методов, которые сервер может вызывать

Примеры кода, показанные ранее для определения клиентских методов, которые сервер может вызывать, применимы к клиентам WinRT. В следующих примерах показан эквивалентный код для клиентов приложений WPF, Silverlight и консольного приложения.

Методы без параметров

Клиентский код WPF для метода, вызываемого с сервера без параметров

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

Клиентский код Silverlight для метода, вызываемого с сервера без параметров

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

Код клиента консольного приложения для метода, вызываемого с сервера без параметров

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

Методы с параметрами, указание типов параметров

Клиентский код WPF для метода, вызываемого с сервера с параметром

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

Клиентский код Silverlight для метода, вызываемого с сервера с параметром

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)
);

Код клиента консольного приложения для метода, вызываемого с сервера с параметром

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

Методы с параметрами, указание динамических объектов для параметров

Клиентский код WPF для метода, вызываемого с сервера с параметром, с помощью динамического объекта для параметра

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

Клиентский код Silverlight для метода, вызываемого с сервера с параметром, с помощью динамического объекта для параметра

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)
);

Код клиента консольного приложения для метода, вызываемого с сервера с параметром, с помощью динамического объекта для параметра

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