修改部分用户的传出消息

Modify outgoing messages for a subset of users

是否可以为部分用户修改外发消息?

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

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

我正在努力研究如何最好地做到这一点。我以为我已经通过使用 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 problems 并且,在重新阅读以上内容时,我意识到我可能正在展示自己。

我们正在考虑将 SignalR 设置为通用 "event notification" 机制,供使用各种内部应用程序的员工使用,并最终让我们的供应商和客户也可以访问。

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

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

回答第一个问题:不,我不认为您可以通过修改其内容的方式来干扰广播消息,具体取决于所寻址的用户(也就是说从集线器的角度来看)。

根据集线器中提供的机制,我认为唯一的方法是跟踪连接 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);

我知道这不是一种优雅的方式。我什至宁愿考虑我在评论中建议的组名称约定,但我很高兴讨论或听到您已经考虑过这个问题。

也许您应该使用成员身份提供程序和角色提供程序,并根据使用 'RoleProvider.IsUserInRole' 的订阅者角色修改消息。