视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Asp.Net Core使用SignalR进行服务间调用方法示例
2020-11-27 22:34:40 责编:小采
文档


网上查询过很多关于ASP.NET core使用SignalR的简单例子,但是大部分都是简易聊天功能,今天心血来潮就搞了个使用SignalR进行服务间调用的简单DEMO。

至于SignalR是什么我就不多说了,微软官方文档也不少。

第一步新建项目

所有VS开发第一步都是新建一个解决方案哈,这里我就不多介绍如何新建项目啦~~

  • 开发环境,VS2017,.NET CORE 2.1
  • 新建两个asp.net core项目 
  • 如此简单的操作大家都懂的

    注入SignalR

    在被调用的服务端的Startup.cs中注入SignalR 在asp.net core2.1中已经默认包含了SignalR的库,直接在 ConfigureServices 方法中添加如下代码:

    services.AddSignalR().AddMessagePackProtocol()

    AddMessagePackProtocol() 表示启用 MessagePack 支持在服务器上

    新建一个继承Hub类的类

    public class ServerHub : Hub
    {
     }

    里面可以实现需要被客户端执行的方法。

    配置Hub连接URL

    Startup.csConfigure 添加下面代码

    app.UseSignalR(routes =>
    {
    
     routes.MapHub<ServerHub>("/myserver");
    
    });

    添加服务

    新建一个Services文件夹,添加我们的服务接口和接口实现类。

    public interface IMyService
    
    {
    
     Task<string> SayHello();
    
     Task Sleep();
    
    }
    
    public class MyService : IMyService
    
    {
    
     public async Task<string> SayHello()
    
     {
    
     return await Task.Factory.StartNew(() => "Hello");
    
     }
    
     public async Task Sleep()
    
     {
    
     await Task.Delay(3000); 
    
     }
    
    }

    在Startup.cs中的 ConfigureServices 方法中进行依赖注入,注意需要在 AddSignalR() 之前注入。

    services.AddScoped<IMyService, MyService>();

    在ServerHub添加依赖注入

    在ServerHub中添加如下代码

    private readonly IServiceProvider _serviceProvider;
    
     public ServerHub(IServiceProvider serviceProvider)
    
     {
    
     _serviceProvider = serviceProvider;
    
     }

    因为我们需要使用到依赖注入获取指定Service,所以只注入 IServiceProvider ,使用 IServiceProvider 动态获取服务接口。

    使用反射动态获取服务接口并执行指定方法

    为了可以动态的选择服务并且执行服务相应的方法,我们使用反射来动态获取。 这里我们添加两个方法,一个有返回值,一个没有返回值

    public async Task<dynamic> Excute(string serverName,string functionName,object[] parameters)
    
    {
    
     return await Task.Factory.StartNew(() =>
    
     {
    
     var type = Type.GetType(serverName);
    
     var service = _serviceProvider.GetRequiredService(type);
    
     var method = type.GetMethod(functionName);
    
     var resultTask = method.Invoke(service, new object[] { }) as Task;
    
     dynamic result = resultTask.GetType().GetProperty("Result").GetValue(resultTask, null);
    
     return result;
    
     });
    
    }
    
     
    
    public async Task ExcuteWithoutResult(string serverName, string functionName, object[] parameters)
    
    {
    
     var type = Type.GetType(serverName);
    
     var service = _serviceProvider.GetRequiredService(type);
    
     var method = type.GetMethod(functionName);
    
     var resultTask = method.Invoke(service, new object[] { }) as Task;
    
     await resultTask;
    
     var msg = "task done";
    
     await Clients.Caller.SendAsync("callback",msg);
    
    }

    方法中传入三个参数

  • serverName:服务接口名称(完整的命名空间)
  • functionName:方法的名称
  • parameters: 方法所需的参数
  • 1.使用Type.GetType(serverName)获取服务接口的Type。
    2.使用_serviceProvider.GetRequiredService(type)从依赖注入中获取对应服务。
    3.使用type.GetMethod(functionName)获取需要执行的方法。
    4.执行方法method.Invoke(service, new object[] { })

    由于我们的服务是异步方法, method.Invoke() 返回的是一个 object 对象,所以在将 method.Invoke() 返回类型转为 Task 类型。

    resultTask.GetType().GetProperty("Result").GetValue(resultTask, null) 是通过反射获取 TaskResult 属性来回去相应的返回结果。

    因为我们不知道方法返回的 Task 中返回的结果类型是什么,所以我们依旧使用反射来获取 Task 的结果并使用 dynamic 接收。

    无返回值的我们使用 Clients.Caller.SendAsync() 在任务处理结束后给调用方返回一条消息。

    在调用方添加一个SingalRClient类

    public class SignalRClient
    
    {
    
     private readonly HubConnection connection;
    
     public SignalRClient()
    
     {
    
     connection = new HubConnectionBuilder()
    
     .WithUrl("http://localhost:5000/myserver")
    
     .AddMessagePackProtocol()
    
     .Build();
    
     
    
     connection.Closed += async (error) =>
    
     {
    
     await Task.Delay(new Random().Next(0, 5) * 1000);
    
     await connection.StartAsync();
    
     };
    
     InitOnMethod();
    
     connection.StartAsync().ConfigureAwait(false).GetAwaiter().GetResult();
    
     }
    
    }

    在构造函数中初始化SignalR连接

    WithUrl("http://localhost:5000/myserver") 是连接被调用方的URL

    AddMessagePackProtocol() 是使用快速和精简的二进制序列化格式进行传输。 在 connection.Closed 加入连接关闭事件,关闭后自动重新连接。 InitOnMethod 初始化服务方回调的监听事件

    private void InitOnMethod()
    
    {
    
     connection.On<string>("callback",(msg)=> {
    
     Console.WriteLine($"------------{msg}----------");
    
     });
    
    }

    connection.StartAsync() 启动连接。

    添加两个请求服务端的方法

    一个有返回值,一个无返回值。

    public async Task<dynamic> RequestServer1()
    {
     var result = await connection.InvokeAsync<dynamic>("Excute", "SignalRServer1.Services.IMyService", "SayHello",new object[] { });
     return result;
    }
    
    public async Task RequestWithoutResult()
    {
    
     await connection.SendAsync("ExcuteWithoutResult", "SignalRServer1.Services.IMyService", "Sleep", new object[] { });
    
    }

    需要返回值的我们使用 connection.InvokeAsync() 方法

    不需要返回值的我们使用 connection.SendAsync() 方法

    将SignalRClient以单例形式注册依赖注入

    Startup.cs 中的 ConfigureServices 方法中添加 services.AddSingleton<SignalRClient>()

    使用SignalRClient请求服务

    在控制器中将SignalRClient注入

    private readonly SignalRClient _signalRClient;
    
     
    
    public ValuesController(SignalRClient signalRClient)
    
    {
    
     _signalRClient = signalRClient;
    
    }
    
    // GET api/values
    
    [HttpGet]
    
    public async Task<ActionResult<IEnumerable<string>>> Get()
    
    {
    
     var str = await _signalRClient.RequestServer1().ConfigureAwait(false);
    
     await _signalRClient.RequestWithoutResult().ConfigureAwait(false);
    
     return new string[] { str };
    
    }

    在请求中同时调用一个有返回值,一个无返回值的方法。无返回值的方法在任务执行完后执行一个回调。

    启动服务

     

     

    可以看到服务调用已经成功 task done是我们无返回值调用那个方法中接收到回调时的输出.

    connection.On<string>("callback",(msg)=> {
    
     Console.WriteLine($"------------{msg}----------");
    
     });

    下载本文
    显示全文
    专题