Owin Websockets - 了解 IOwinContext 和 WebSocketAccept

Owin Websockets - Understanding IOwinContext and WebSocketAccept

通读here and looking at the example here

我试图了解 WebSocketAccept 实际上做了什么。我知道 WebSocketAccept 是:

using WebSocketAccept =
    Action
    <
        IDictionary<string, object>, // WebSocket Accept parameters
        Func // WebSocketFunc callback
        <
            IDictionary<string, object>, // WebSocket environment
            Task // Complete
        >
    >;

并以这种方式使用:

public void Configuration(IAppBuilder app)
    {
        app.Use(UpgradeToWebSockets);
        app.UseWelcomePage();
    }

    // Run once per request
    private Task UpgradeToWebSockets(IOwinContext context, Func<Task> next)
    {
        WebSocketAccept accept = context.Get<WebSocketAccept>("websocket.Accept");
        if (accept == null)
        {
            // Not a websocket request
            return next();
        }

        accept(null, WebSocketEcho);

        return Task.FromResult<object>(null);
    }

那么 accept() 实际上在做什么?是不是调用了WebSocketAccept的Func<> 属性,定义了一个方法WebSocketEcho? WebSocketEcho 定义为:

  private async Task WebSocketEcho(IDictionary<string, object> websocketContext)

那么websocketContext是从哪里来的呢?如果我们想在确定这是一个 Web 套接字请求后将其进一步传递到管道中怎么办?

什么是 WebSocketAccept?

WebSocketAccept 是一个 using alias

示例:

...
using Foo.Bar
using MyBar = Fee.Bar
...

这里我们使用来自 2 个不同命名空间的 Bar,但我们将第二个命名空间命名为“MyBar”,这样我们就可以区分两者。

为什么使用别名作为 WebSocketAccept?

本例中的别名只是为了方便,这样您就不必键入整个名称,这意味着您可以使用别名代替而不是在使用时写全名。

了解 WebSocketAccept

如果我们仔细观察,我们会发现类型是:

Action<A, B>

这意味着它本质上是一个函数,在 C# lambda 中,return 并接受 2 个参数:

(A, B) => { }

我们看到第一个参数(A)是:IDictionary<string, object>,也就是Owin环境。

第二个参数是 (B) 是:Func<C, D> 这意味着它是一个接受 C 和 return 的函数 D。在 C# lambda 中:

(C) => { return D; }

然后我们需要深入研究第二个参数 (B) 的第一个参数 (C)。我们看到它需要一个 Owin 环境和 returns a Task.

什么是接受?

accept 尝试从 IOwinContext 中提取参数并将它们映射到 WebSocketAccept 类型。

如果无法提取它们,那就是null,我们继续下一个中间件。

否则它是一个 websocket 请求,我们调用带有 2 个参数的函数 (WebSocketAccept),正如我们上面所讨论的 (Action<A, B>)。

第一个参数是一个普通的字典,里面包含了websocket接受的参数。

第二个参数是一个接受字典的函数,return是一个任务。

此函数被其他人调用,代码所做的是将回调函数传递给调用者。

调用者随后使用正确的参数调用该函数。因为调用者知道函数的签名。该函数在接受 websocket 连接请求后被调用。因此评论回调。

一旦我们确定它是一个网络套接字请求,如果我们想将它进一步传递到管道中怎么办?

在这个例子中,回调函数是 WebSocketEcho 但基本上你可以传入任何满足函数签名的函数:

Task MyCallbackFunction(IDictionary<string, object> context)
{
    // Do something
    return Task.FromResult(0);
}

要点是你不调用函数,函数是为你调用的。您指定在协商 Web 套接字请求连接后,您决定会发生什么。

WebSocketEcho函数对每个客户端调用一次,循环直到客户端选择关闭连接。同时它会回显它收到的任何内容。

免责声明:我也只是想围绕 web sockets 和 owin,但我想为后代分享我的发现,因为没有人回答你的问题。欢迎大家指正。

编辑
我在自己的实验中注意到,如果您从回调函数 return websocketContext 连接将被 Aborted。这意味着如果您在结束回调后传递 websocketContext,则无法在连接上发送 send/receive 消息。

更新
上次我尝试在 Windows 2008 R2 IIS 7.5 服务器上使用它时,我无法让 websocket 工作。然后根据这个: - IIS 7.5 服务器不支持 websockets。
这意味着如果您的应用程序托管在 IIS 7.5 中,它将无法拥有 websockets。

然后我想了一个可能的解决办法:

  1. 使用单独的应用程序,例如处理 websocket 请求的服务程序(在 IIS 之外)。
  2. 使用反向代理将请求映射到服务应用程序

这对我来说太麻烦了,这让我暂时搁置了实施 websocket...