Pipeline Pipeline - 1 year ago 114
C# Question

Owin Websockets - Understanding IOwinContext and WebSocketAccept

Reading through here and looking at the example here:

I am trying to understand actually what the WebSocketAccept actually does. I know that WebSocketAccept is:

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

and is used in this manner:

public void Configuration(IAppBuilder app)

// 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);

So what is accept() actuallyt doing? Is it calling the Func<> property of the WebSocketAccept and a method WebSocketEcho is defined? WebSocketEcho is defined as:

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

So where does the websocketContext come from? What if we wanted to pass this further down the pipeline once we have identified it is a web socket request?

Answer Source

What is WebSocketAccept?

WebSocketAccept is a using alias


using Foo.Bar
using MyBar = Fee.Bar

Here we are using Bar from 2 different namespaces, but we alias the 2nd one with 'MyBar' so we can differentiate between the two.

Why use an alias as WebSocketAccept?

The alias in this case is just a convenience, so that you don't have to type the whole thing, which means that instead of writing the whole name when using it, you can use the alias instead.

Understanding WebSocketAccept

If we look closer we see that the type is:

Action<A, B>

This means that it is essentially a function that does not return and takes 2 arguments, in C# lambda:

(A, B) => { }

We see that the 1st argument (A) is: IDictionary<string, object>, which is also known as the Owin environment.

The 2nd argument is (B) is: Func<C, D> which means that it is a function that takes a C and returns a D. In C# lambda:

(C) => { return D; }

We then need to dive into the 1st argument (C) of the 2nd argument (B). And we see that it takes an Owin environment and returns a Task.

What is accept?

accept tries to extract the parameters from the IOwinContext and map them to the WebSocketAccept type.

If it can't extract them it is null and we proceed to the next middleware.

Otherwise it was a websocket request and we call the function that takes 2 parameters (WebSocketAccept), as we discussed above (Action<A, B>).

The first parameter being an ordinary dictionary, which contains the websocket accept parameters.

The second parameter being a function that takes a dictionary and returns a task.

This function is called by someone else, what the code does, is pass the callback function along to the caller.

The caller then calls the function with the correct argument. Because the caller knows the signature of the function. The function is called AFTER accepting the websocket connection request. Hence the comment callback.

What if we wanted to pass this further down the pipeline once we have identified it is a web socket request?

Well in the example, the callback function is WebSocketEcho but essentially you could pass in any function, that satisfies the function signature of:

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

The takeaway is that you don't call the function, the function is called for you. You specify that after negotiating the web socket request connection, you decide what happens.

The WebSocketEcho function is called once for every client, and loops until the client chooses to close the connection. Meanwhile it echo back whatever it receives.

Disclaimer: I too am just trying to wrap my head around web sockets and owin, but I wanted to share my findings for posterity, since no one had answered your question. I welcome any corrections.

I noticed with my own experiment, that if you return from the callback function that the websocketContext connection will be Aborted. Meaning you can't send/receive messages on the connection if you pass the websocketContext around after ending the callback.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download