修改用户子集的传出消息

本文关键字:消息 用户 子集 修改 | 更新日期: 2023-09-27 18:00:37

是否可以修改用户子集的传出消息?

我现在只是在做原型,但最终的计划是,我们将有两层(或更多)用户连接到同一个集线器。集线器基本上只是重新广播客户端想要发送的任何消息。

较高级别的用户应该可以看到所有消息。较低级别的用户不应该看到所有消息,而应该看到某些消息的编辑版本。

我正在想办法做到最好。我以为我用HubPipelineModule:找到了答案

using Microsoft.AspNet.SignalR.Hubs;
namespace WebApplication9
{
    public class MsgFilter : HubPipelineModule
    {
        protected override bool OnBeforeOutgoing(IHubOutgoingInvokerContext context)
        {
            if (context.Invocation.Method == "pong")
            {
                if (((string)context.Invocation.Args[0]).Equals("goodbye"))
                {
                    context.Invocation.Args[0] = "this message has been suppressed for the good of the people";
                }
            }
            return base.OnBeforeOutgoing(context);
        }
    }
}

(最终,过滤将需要确定有关连接用户的信息,但我还没有做到)

已在Startup:期间安装

using Microsoft.AspNet.SignalR;
using Owin;
namespace WebApplication9
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
            GlobalHost.HubPipeline.AddModule(new MsgFilter());
        }
    }
}

集线器看起来像:

using Microsoft.AspNet.SignalR;
namespace WebApplication9
{
    public class PingHub : Hub
    {
        public void Send(dynamic message)
        {
            Clients.All.pong(message);
        }
    }
}

(这最终将转移到特定组内的广播,而不是转移到所有客户端)

然后,我在MVC控制器的视图中有以下代码:

@model dynamic
@{
  ViewBag.Title = "title";
}
<h2>title</h2>
<input id="message" type="text" />
<input id="send" name="send" value="Send" type="button" />
<div id="messages"></div>
@section scripts
{
<script src="~/Scripts/jquery.signalR-2.2.0.js"></script>
<script src="~/signalr/hubs"></script>
<script>
  $(function () {
    // Reference the auto-generated proxy for the hub.  
    var ping = $.connection.pingHub;
    // Create a function that the hub can call back to display messages.
    ping.client.pong = function (message) {
      // Add the message to the page. 
      $('#messages').append('<li>' + htmlEncode(message) + '</li>');
    };
    // Start the connection.
    $.connection.hub.start().done(function () {
      $('#send').click(function () {
        // Call the Send method on the hub. 
        ping.server.send($('#message').val());
        // Clear text box and reset focus for next comment. 
        $('#message').val('').focus();
      });
    });
  });
  // This optional function html-encodes messages for display in the page.
  function htmlEncode(value) {
    var encodedValue = $('<div />').text(value).html();
    return encodedValue;
  }
</script>
}

(控制器方法本身只是Return View();

但是,当我启动两个浏览器,在其中一个浏览器中输入一条消息并按Send时,我希望OnBeforeOutgoing中的代码被调用两次,每次连接一次。事实并非如此,它只被调用一次。

问题

因此,这似乎是实现过滤器的错误位置,该过滤器将影响一个连接,而不是另一个。

我的理解错了吗?我应该使用不同的扩展点吗?


工具集:

VS 2012,清空ASP.NET应用程序,然后安装以下程序包:

<packages>
  <package id="Antlr" version="3.4.1.9004" targetFramework="net45" />
  <package id="bootstrap" version="3.0.0" targetFramework="net45" />
  <package id="jQuery" version="2.1.4" targetFramework="net45" />
  <package id="jQuery.Validation" version="1.13.1" targetFramework="net45" />
  <package id="Microsoft.AspNet.Mvc" version="5.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.SignalR" version="2.2.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.SignalR.Core" version="2.2.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.SignalR.JS" version="2.2.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.SignalR.SystemWeb" version="2.2.0" targetFramework="net45" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.1" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.0.0" targetFramework="net45" />
  <package id="Microsoft.Owin" version="2.1.0" targetFramework="net45" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="2.1.0" targetFramework="net45" />
  <package id="Microsoft.Owin.Security" version="2.1.0" targetFramework="net45" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
  <package id="Modernizr" version="2.6.2" targetFramework="net45" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
  <package id="Owin" version="1.0" targetFramework="net45" />
  <package id="WebGrease" version="1.5.2" targetFramework="net45" />
</packages>

当人们提出XY问题时,我总是抱怨,重读以上内容后,我意识到我自己可能也在提出XY问题。

我们正在考虑将SignalR设置为一种通用的"事件通知"机制,既适用于使用各种内部应用程序的员工,也适用于我们的供应商和客户。

大多数活动都涉及个人客户,因此计划是让人们访问特定客户的账户,加入以该客户参考号命名的小组。然后,当任何人对该客户进行更改时,他们将向该组发布事件。

然而,并非发生在客户账户上的所有活动都必须对外部各方可见(客户本身或我们的供应商——这些是否需要相同的访问规则尚未决定)。此外,并非所有附加到事件的信息都必须发布(例如,在内部,我们可能需要知道员工"Joe Blogs"刚刚做了X,但我们可能想将其更改为"Joe(客户服务)",以免泄露员工的个人信息)

修改用户子集的传出消息

回答第一个问题:不,我不认为你可以根据被寻址的用户来修改广播消息的内容(从集线器的角度来看)。

根据集线器中提供的机制,我认为唯一的方法是跟踪连接ID,然后使用带有排除的连接ID(外部用户)列表的组调用来只寻址特定用户。这是在不知道在特定情况下处理连接和重新连接有多难的情况下说的。

连接后的每个用户都会被添加到集合中,但前提是他在内部用户中。然后,内部用户需要调用一个额外的服务器方法,在该方法中,他需要获得从排除列表中删除的授权(从客户端触发的额外授权)。

[Authorize]
public void RegisterAsTeamMember()
{
      if (!IDs.Any(u => u == Context.ConnectionId))
      {
           IDs.Remove(Context.ConnectionId);
      }
}

向项目的所有成员广播消息将导致:

Clients.Group("[customer]").broadcastMessage(name, message);

如果是独占消息:

Clients.Group("[customer]", excludedIds.ToArray()).broadcastMessage(name, message);

我知道这不是一种优雅的方式。我甚至宁愿考虑我在评论中建议的团体名称惯例,但我很高兴与您讨论或听到您已经考虑过这一点。

也许您应该使用membershipprovider和角色提供程序,并使用"roleprovider.IsUserInRole"根据订阅者角色修改消息。