.NET HTTP Abstractions
01 December 2010
Note: OWIN has evolved significantly since this post. Please consult the latest specification. – bvanderveen, 6 January 2011
For the past few days, I’ve been furiously posting on the .NET HTTP Abstractions Google Group, where a .NET “clone” of WSGI is taking shape. Although I started working on something like WSGI toward the end of October, I had all but given up due to perceived lack of interest. Naturally, I was very excited to see the discussion on .NET HTTP Abstractions taking shape. Ryan Riley, Sebastien Lambla, and myself have been particularly actively hashing out the details of a new specification we’re tentatively calling Open Web Interface for .NET, or OWIN. Ryan has been keeping a GitHub repo in sync with the discussion.
The interface is really nice and minimal. A few details might change, but here’s where we are now:
public interface IApplication
{
IAsyncResult BeginInvoke(IRequest request,
AsyncCallback callback, object state);
IResponse EndInvoke(IAsyncResult result);
}
public interface IRequest
{
IDictionary<string, object> Items { get; }
string Method { get; }
string Uri { get; }
IDictionary<string, IEnumerable<string>> Headers { get; }
IAsyncResult BeginReadBody(byte[] buffer, int offset, int count,
AsyncCallback callback, object state);
int EndReadBody(IAsyncResult result);
}
public interface IResponse
{
string Status { get; }
IDictionary<string, IEnumerable<string>> Headers { get; }
IEnumerable GetBody();
}
Architecturally, this is a pretty significant departure from WSGI and Rack, due to the statically-typed nature of C#. Personally, I think it’s an improvement. The request is represented explicitly by a concise interface rather than a big dictionary, and gone are the ugly CGI-style variables required to access request headers. Response objects are simply returned by applications, which is a lot cleaner than WSGI’s approach, which requires applications to call start_response
for the header data and the return an enumerable for the body data. Additionally, the whole thing is fully asynchronous, which we’re hoping will bolster performance, and saves on some of the awkward implementation consequences of WSGI surrounding threading and response buffering.
A few quick points:
- Environment-specific data (probably including base path, though this is still being discussed) is stored in
IRequest.Items
. - Header dictionary values are
IEnumerable<string>
to support headers which may appear multiple times, such asSet-Cookie
. - The
IEnumerable
returned byIResponse.GetBody()
can contain different types of objects that host implementation can handle in different ways. None of these are set in stone, but for example, aFileInfo
might be served using the OS’ file-sending support, or aTask<byte[]>
might represent an asynchronously-fetched buffer of bytes. The possibilities here are exciting.
We’ve opted to keep the interface compatible all the way back to .NET 2.0, but it wouldn’t be difficult to write extensions which would make it easy to use even in something as bleeding-edge as the C# Async CTP.
In the next few days, I hope to start drafting a more formal specification as we nail down remaining details. Many thanks to everyone who has contributed to the discussion! We’ve got a hell of a lot of firepower behind this thing and I’m very excited to see where it goes.
Tweet Follow @bvanderveen