首页 > 编程语言 >在asp

在asp

时间:2024-05-23 21:30:51浏览次数:12  
标签:asp SparepartsChangeEventHandler connection code var public channel

在asp.net中完成服务间实时通信

写在开头:

最近遇到这样一个需求:在企业微信(webform)中完成出库入库操作,web后台管理(asp.net core + vue2)界面实时更新库存

最开始,我想的是前端通过短轮询方案,这样并不需要对后端进行任何的改动,简单粗暴。

可想一想,还有更好的解决方案吗,前端绑一个监听事件,触发完成页面更新操作,可是这样的好像对用户也不太友好,同时,如果有很多地方出现这种需求,那会对服务器带来额外的负载。

将库存变化看作是一个事件,然后企业微信端通知到web后端,再由web后端通知给前端,改变相关值即可,不需进行查询。

所以采用rabbitmq完成事件反馈,通过signalr完成实时通信,也就是下图这样

具体实现

1.企业微信端发送事件:

 //
var factory = new ConnectionFactory()
 {
     HostName = "服务器ip",
     UserName = "admin",
     Password = "123456",
     VirtualHost = "/"
 };
 _connection = factory.CreateConnection();
 _channel = _connection.CreateModel();
 _channel.ExchangeDeclare("SparepartsChangeEvent",
                      ExchangeType.Direct,
                       true, false, null);
 var sendedEvent = new SparepartsChangeEvent(SparepartsType.OutStock, code, count, Factory);
 var json = JsonConvert.SerializeObject(sendedEvent);
 var body = Encoding.UTF8.GetBytes(json);
 _channel.BasicPublish(exchange: "SparepartsChangeEvent",
                       routingKey: routekey,
                       basicProperties: null,
                       body: body);

2.web后端创建集线器:

public class SparepartsHub:Hub
{
    public async Task SendSparepartsChangeMessage(string user,string  code,int count,int type)
    {
        await Clients.All.SendAsync("ReceiveSparepartsChangeMessage", user, code, count,type);
    }
}

3.事件处理:

public class SparepartsChangeEventHandler
{
    private readonly IHubContext<SparepartsHub> _hubContext;
    private readonly IConfiguration _configuration;
    private string routeKey = "DP06";
    public SparepartsChangeEventHandler(IHubContext<SparepartsHub> hubContext,IConfiguration configuration)
    {
        _hubContext = hubContext;
        _configuration = configuration;
    }
    public async Task SendMsg()
    {
        var factory = new ConnectionFactory()
        {
            HostName = "服务器ip",
            UserName = "admin",
            Password = "123456",//此处建议放入配置文件
            VirtualHost = "/"
        };
            routeKey = _configuration["RouteKey:SparepartsChange"];//将routekey放入配置文件
        if(routeKey == null)
        {
            await Task.CompletedTask;
            return;
        }
        using (var connection = factory.CreateConnection())
        using (var channel = connection.CreateModel())
        {
            channel.QueueDeclare(queue: "SparepartsChangeEventHandler",
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
            channel.QueueBind(queue: "SparepartsChangeEventHandler", exchange: "SparepartsChangeEvent", routingKey: routeKey);
            var consumer = new EventingBasicConsumer(channel);
            consumer.Received += async (model, ea) =>
            {
                var body = ea.Body.ToArray();
                SparepartsChangeEvent scEvent = JsonConvert.DeserializeObject<SparepartsChangeEvent>(Encoding.UTF8.GetString(body));
                await Console.Out.WriteLineAsync(JsonConvert.SerializeObject(_hubContext));

                if (_hubContext.Clients != null)
                {
                    await _hubContext.Clients.All.SendAsync("ReceiveSparepartsChangeMessage", scEvent.Factory, scEvent.Code, scEvent.Count,scEvent.Type);
                }

            };
            channel.BasicConsume(queue: "SparepartsChangeEventHandler",
                                 autoAck: true,
                                 consumer: consumer);
            Console.ReadLine();

        }
    }
}

4.starup类配置:

services.AddSingleton<SparepartsHub>();
services.AddSingleton<SparepartsChangeEventHandler>();//依赖注入

var sparepartsChangeEventHandler = app.ApplicationServices.GetRequiredService<SparepartsChangeEventHandler>();
Task.Run(() => sparepartsChangeEventHandler.SendMsg());
//获取服务调用方法,需要另外开一个线程

如果前端signalr提示跨域问题,在此处配置:

 app.UseEndpoints(endpoints =>
 {
     endpoints.MapHub<SparepartsHub>("/sparepartsHub").RequireCors(t => t.WithOrigins(new string[] { "http://前端ip:端口号" }).AllowAnyMethod().AllowAnyHeader().AllowCredentials()); ;
     endpoints.MapControllers();
 });

5.前端:

init() {
      const connection = new signalR.HubConnectionBuilder()
        .withUrl("http://后端ip:端口号/SparepartsHub", {})
        .configureLogging(signalR.LogLevel.Error)
        .build();
      connection.on("ReceiveSparepartsChangeMessage", (factory,code,count,type) => {
        console.log(factory+'-'+code+'-'+count+'-'+type)
        console.log(code)
        let connectIndex=this.dataSource.findIndex(a=>a.bjbh==code)
        console.log(connectIndex)
        if(connectIndex==-1)
          return;
        if(type==0){
          this.dataSource[connectIndex].nowStock += count;
        }else{
          this.dataSource[connectIndex].nowStock -= count;
        }
        console.log()
      });
      connection.start(this.dataSource)
    .then(() => {
        connection.invoke("SendSparepartsChangeMessage", "Alice", "Hello from Vue!",1,0);
    })
    .catch(error => {
        console.error(error);
    });
    },
  },
  created(){
    this.init()
  }

写在最后

我希望rabbitmq发布事件后,web后端根据事件可以自动调用某个EventHandler方法,就像这样:

public class SparepartsChangeEventHandler
{
    private readonly ILogger<SparepartsChangeEvent> _logger;
    public SparepartsChangeEventHandler(ILogger<SparepartsChangeEventHandler> logger)
    {
        _logger = logger;
    }
    public Task Receive()
    {
        _logger.LogInformation($"Received SparepartsChangeEvent 事件");
        return Task.CompletedTask;
    }
}

这样使代码更具有可扩展性及可读性,业务与业务之间有更好的隔离。

标签:asp,SparepartsChangeEventHandler,connection,code,var,public,channel
From: https://www.cnblogs.com/ssz0312/p/18209389

相关文章

  • Asp .Net Core 系列:集成 CAP + RabbitMQ + MySQL(含幂等性)
    简介官网:https://cap.dotnetcore.xyz/CAP是什么?是一个EventBus,同时也是一个在微服务或者SOA系统中解决分布式事务问题的一个框架。它有助于创建可扩展,可靠并且易于更改的微服务系统。什么是EventBus?事件总线是一种机制,它允许不同的组件彼此通信而不彼此了解。组件可以......
  • ASP.NET Web应用程序创建的webservice接口如何在postman里测试调用
    ASMX中的方法 启动项目浏览器展示的页面如下 点击ReceiveOrder,展示该方法的请求和响应示例 在postman中输入以下信息 选择raw--xml,粘贴浏览器中的SOAP1.1或者SOAP1.2中的请求示例 点击Send按钮发生请求 SOAP1.1以下是SOAP1.1请求和响应示例。所显示的占位......
  • Asp-Net-Core开发笔记:使用原生的接口限流功能
    前言之前介绍过使用AspNetCoreRateLimit组件来实现接口限流从.Net7开始,AspNetCore开始内置限流组件,当时我们的项目还在.Net6所以只能用第三方的现在都升级到.Net8了,当然是得来试试这个原生组件体验后:配置使用都比较简单,不过功能也没有AspNetCoreRateLimit那么灵活......
  • Asp-Net-Core开发笔记:给SwaggerUI加上登录保护功能
    前言#在SwaggerUI中加入登录验证,是我很早前就做过的,不过之前的做法总感觉有点硬编码,最近.Net8增加了一个新特性:调用MapSwagger().RequireAuthorization来保护SwaggerUI,但官方的这个功能又像半成品一样,只能使用postmancurl之类的工具带上Authorizationheader来请......
  • Asp-Net-Core开发笔记:使用ActionFilterAttribute实现非侵入式的参数校验
    前言#在现代应用开发中,确保API的安全性和可靠性至关重要。面向切面编程(AOP)通过将横切关注点(如验证、日志记录、异常处理)与核心业务逻辑分离,极大地提升了代码的模块化和可维护性。在ASP.NETCore中,利用ActionFilterAttribute可以方便地实现AOP的理念,能够以简洁、高效的方式进行......
  • C# webform 在aspx页面调用aspx.cs页面的方法
    前台代码--调用后台的GetEcharts1方法,并传入三个参数startDateValue,ipEndDate,ddlTypeValue<inputtype="button"id="loadExce2l"value="查看"onclick="loadEcharts()"/>functionloadEcharts(){console.log(19999999999)......
  • RASP
    背景和介绍RASP(RuntimeApplicationSelfProtection,RASP)是一种安全解决方案,用于对特定应用提供个性化防护。它利用对应用内部数据和状态的洞察和观测,使其能够在该应用运行时,识别出可能被其他解决方案所忽视的威胁。RASP工作原理RASP封装并防护一个特定的应用程序,而不是通......
  • OWASP-Hackademic-Challenges
    1.靶场安装靶场下载:https://code.google.com/archive/p/owasp-hackademic-challenges/downloads在phpstudy中搭建即可访问页面:2.OWASPHackademicChallenge–Challenge12.1.解题点击链接,进入靶场页面上没有什么有用的消息,查看页面源代码(Ctrl+U)可以找到不同显示页......
  • ASP.NET Core应用程序7:使用视图组件
      视图组件是类,为支持分部视图或者在父视图中注入少量Html或Json数据提供了应用程序逻辑。1准备工作  Models文件夹中添加City.cs类和CitiesData类,为CitiesData添加服务。publicclassCity{publicstringName{get;set;}publicstringCo......
  • 在 ASP.NET Core 中使用托管服务实现后台任务
    在ASP.NETCore中,后台任务作为托管服务实现。托管服务是一个类,具有实现 IHostedService 接口的后台任务逻辑。本文提供了三个托管服务示例:在计时器上运行的后台任务。激活有作用域的服务的托管服务。有作用域的服务可使用依赖项注入(DI)。按顺序运行的已排队后台任务......