【SignalR学习系列】8. SignalR Hubs Api 详解(.Net C# 客户端)

建立一个 SignalR 连接

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

配置 SignalR 连接

在 WPF 客户端里设置连接的最大值

复制代码
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();
复制代码

设置 Query String 参数

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

读取 query string

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

指定传输协议

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

可以指定以下四种方式

  • LongPollingTransport
  • ServerSentEventsTransport
  • WebSocketTransport (只有在 server and client 都使用 .NET 4.5的情况下才能使用)
  • AutoTransport(自动选择)

指定 Http Header 

复制代码
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();
复制代码

指定 Client 证书

复制代码
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();
复制代码

创建 Hub proxy

服务端

public class StockTickerHub : Hub

客户端

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 的值来调用。

服务端

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

客户端

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

如果使用 HubName 多次调用 HubConnection.CreateHubProxy,那么会得到缓存的相同的 IHubProxy 对象。

如何定义在 Server 端调用的 Client 方法

无参方法

Server 端

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

客户端

复制代码
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();
复制代码

有参指定参数类型

Sever 端

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

用作参数的 Stock 类

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

客户端代码

复制代码
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)
);
复制代码

有参,指定动态类型

server 端

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

用作参数的 Stock 类

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

客户端代码

复制代码
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)
);
复制代码

移除Handler

复制代码
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();
复制代码

从客户端调用服务端方法

使用 HubProxy 的 Invoke 方法来调用服务端的方法。

服务端方法没有返回值

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

客户端调用服务器没有返回值的方法

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

服务端方法有返回值,并且有一个复杂类型的参数

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

客户端调用有返回值和复杂类型参数的方法,.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);
}

如何处理连接的生命周期事件

SignalR 提供了下述你可以捕获的生命周期事件。

  • received: 当任何数据通过连接获取到的时候执行。可以得到数据。
  • connectionSlow: 当客户端检测到缓慢或者不流畅的连接的时候执行。 
  • reconnecting: 当潜在的协议重新开始连接的时候执行。 
  • reconnected: 当潜在的协议以及重新建立连接的时候执行。
  • stateChanged: 当连接的状态发生改变的时候执行。可以提供一个旧的和新的状态(Connecting, Connected, Reconnecting, 或者 Disconnected)。
  • Closed: 当连接中断以后执行。
hubConnection.ConnectionSlow += () => Console.WriteLine("Connection problems.");

捕获异常

如果你不在服务端明确地打开详细错误信息,那么SignalR只会列出一些简单的错误信息,你可以通过下面的代码开启详细错误信息记录。

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

给 connection 对象添加一个 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);
}
复制代码

开启客户端日志

复制代码
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();
复制代码

参考链接:

https://docs.microsoft.com/zh-cn/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-net-client

 
分类:  SignalR

建立一个 SignalR 连接

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

配置 SignalR 连接

在 WPF 客户端里设置连接的最大值

复制代码
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();
复制代码

设置 Query String 参数

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

读取 query string

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

指定传输协议

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

可以指定以下四种方式

  • LongPollingTransport
  • ServerSentEventsTransport
  • WebSocketTransport (只有在 server and client 都使用 .NET 4.5的情况下才能使用)
  • AutoTransport(自动选择)

指定 Http Header 

复制代码
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();
复制代码

指定 Client 证书

复制代码
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();
复制代码

创建 Hub proxy

服务端

public class StockTickerHub : Hub

客户端

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 的值来调用。

服务端

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

客户端

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

如果使用 HubName 多次调用 HubConnection.CreateHubProxy,那么会得到缓存的相同的 IHubProxy 对象。

如何定义在 Server 端调用的 Client 方法

无参方法

Server 端

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

客户端

复制代码
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();
复制代码

有参指定参数类型

Sever 端

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

用作参数的 Stock 类

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

客户端代码

复制代码
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)
);
复制代码

有参,指定动态类型

server 端

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

用作参数的 Stock 类

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

客户端代码

复制代码
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)
);
复制代码

移除Handler

复制代码
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();
复制代码

从客户端调用服务端方法

使用 HubProxy 的 Invoke 方法来调用服务端的方法。

服务端方法没有返回值

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

客户端调用服务器没有返回值的方法

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

服务端方法有返回值,并且有一个复杂类型的参数

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

客户端调用有返回值和复杂类型参数的方法,.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);
}

如何处理连接的生命周期事件

SignalR 提供了下述你可以捕获的生命周期事件。

  • received: 当任何数据通过连接获取到的时候执行。可以得到数据。
  • connectionSlow: 当客户端检测到缓慢或者不流畅的连接的时候执行。 
  • reconnecting: 当潜在的协议重新开始连接的时候执行。 
  • reconnected: 当潜在的协议以及重新建立连接的时候执行。
  • stateChanged: 当连接的状态发生改变的时候执行。可以提供一个旧的和新的状态(Connecting, Connected, Reconnecting, 或者 Disconnected)。
  • Closed: 当连接中断以后执行。
hubConnection.ConnectionSlow += () => Console.WriteLine("Connection problems.");

捕获异常

如果你不在服务端明确地打开详细错误信息,那么SignalR只会列出一些简单的错误信息,你可以通过下面的代码开启详细错误信息记录。

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

给 connection 对象添加一个 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);
}
复制代码

开启客户端日志

复制代码
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();
复制代码

参考链接:

https://docs.microsoft.com/zh-cn/aspnet/signalr/overview/guide-to-the-api/hubs-api-guide-net-client

猜你喜欢

转载自www.cnblogs.com/webenh/p/9560492.html