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

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

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

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

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

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

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

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

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

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

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

Общие сведения

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

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

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

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

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

Установите пакет 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 прокси-серверы центра создаются вручную, поэтому SignalR предполагает, что вы будете использовать любой концентратор, для чего создается прокси-сервер.

В примере кода используется 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 не включен в этот список, так как он используется только браузерами.

Сведения о том, как проверка метод транспорта в коде сервера, см. в статье Руководство по API Центров SignalR ASP.NET — Сервер . Как получить сведения о клиенте из свойства 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();
}

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

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

[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 (.NET для Магазина Windows). Примеры приложений 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.
  • 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);
}

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

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

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