我想知道我是否可以将SignalR消息直接添加到SignalR SQL背板(来自SQL),因此我不必使用SignalR客户端来执行此操作。
我的情况是我有一个SQL Service Broker队列的激活存储过程,当它触发时,我想向SignalR客户端发送一条消息。目前,我必须在单独的进程中从SQL Service Broker接收消息,然后立即使用SignalR集线器重新发送消息。
我希望我的激活存储过程基本上将消息直接移到SignalR SQL背板上。
答案 0 :(得分:1)
Yes and no. I set up a small experiment on my localhost to determine if possible - and it is, if formatted properly.
Now, a word on the [SignalR]
schema. It generates three tables:
[SignalR].[Messages_0]
--this holds a list of all messages with the columns of
--[PayloadId], [Payload], and [InsertedOn]
[SignalR].[Messages_0_Id]
--this holds one record of one field - the last Id value in the [Messages_0] table
[SignalR].[Scehma]
--No idea what this is for; it's a 1 column (SchemaVersion) 1 record (value of 1) table
Right, so, I duplicated the last column except I incremented the PayloadId
(for the new record and in [Messages_0_Id]
and put in GETDATE()
as the value for InsertedOn
. Immediately after adding the record, a new message came into the connected client. Note that PayloadId
is not an identity column, so you must manually increment it, and you must copy that incremented value into the only record in [Messages_0_Id]
, otherwise your signalr clients will be unable to connect due to Signalr SQL errors.
Now, the trick is populating the [Payload] column properly. A quick look at the table shows that it's probably binary serialized. I'm no expert at SQL, but I'm pretty sure doing a binary serialization is up there in difficulty. If I'm right, this is the source code for the binary serialization, located inside Microsoft.AspNet.SignalR.Messaging.ScaleoutMessage
:
public byte[] ToBytes()
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryWriter binaryWriter = new BinaryWriter((Stream) memoryStream);
binaryWriter.Write(this.Messages.Count);
for (int index = 0; index < this.Messages.Count; ++index)
this.Messages[index].WriteTo((Stream) memoryStream);
binaryWriter.Write(this.ServerCreationTime.Ticks);
return memoryStream.ToArray();
}
}
With WriteTo
:
public void WriteTo(Stream stream)
{
BinaryWriter binaryWriter = new BinaryWriter(stream);
string source = this.Source;
binaryWriter.Write(source);
string key = this.Key;
binaryWriter.Write(key);
int count1 = this.Value.Count;
binaryWriter.Write(count1);
ArraySegment<byte> arraySegment = this.Value;
byte[] array = arraySegment.Array;
arraySegment = this.Value;
int offset = arraySegment.Offset;
arraySegment = this.Value;
int count2 = arraySegment.Count;
binaryWriter.Write(array, offset, count2);
string str1 = this.CommandId ?? string.Empty;
binaryWriter.Write(str1);
int num1 = this.WaitForAck ? 1 : 0;
binaryWriter.Write(num1 != 0);
int num2 = this.IsAck ? 1 : 0;
binaryWriter.Write(num2 != 0);
string str2 = this.Filter ?? string.Empty;
binaryWriter.Write(str2);
}
So, re-implementing that in a stored procedure with pure SQL will be near impossible. If you need to do it on the SQL Server, I suggest using SQL CLR functions. One thing to mention, though - It's easy enough to use a class library, but if you want to reduce hassle over the long term, I'd suggest creating a SQL Server project in Visual Studio. This will allow you to automagically deploy CLR functions with much more ease than manually re-copying the latest class library to the SQL Server. This page talks more about how to do that.
答案 1 :(得分:0)
我受到这篇文章的启发,并在 SQL 存储过程中编写了一个版本。做工非常流畅,并不难。
我之前没有对 varbinary 做过很多工作 - 但是 SQL Server 使它非常容易使用,您只需将这些部分添加在一起即可。上面 James Haug 给出的格式是准确的。大多数字符串只是“长度为字节,然后是字符串内容”(字符串内容只是转换(varbinary,string))。异常字符串是有效负载,它是“长度为 int32 然后是字符串内容”。数字以“最低有效字节在前”写出。我不确定您是否可以在本机进行这样的转换 - 我发现自己将其编写为递归函数很容易(类似于 numToBinary(val,bytesRemaining)... 返回 varbinary)。
如果你走这条路,我还是会先写一个解析器(用 .NET 或其他非 SQL 语言),然后在 SignalR 本身生成的一些数据包上测试它。这为您提供了一个更好的地方来解决 SQL 中的问题 - 并了解有效负载包的正确格式以及其他格式。