OWIN — Open Web Server Interface for .NET, v1.0 Draft 3

Contents

Overview

This document defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple "middleware" modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

Definition

The OWIN interface is expressed as a single raw .NET delegate (the application delegate).

Action<
    // an environment dictionary containing server and request data
    IDictionary<string, object>, 
    
    // response callback
    Action<string, Dictionary<string, IList<string>>, IEnumerable<object>>,
    
    // error callback
    Action<Exception>
>

In this document, an OWIN-compatible web server is referred to as a "host", and an instance of the above delegate is referred to as an "application". Broadly speaking, hosts invoke applications (providing as arguments an environment dictionary, and response and error callbacks), and the application either provides a response to the host by invoking the response callback with response information, or indicates an error by invoking the error callback with an exception. How an application is provided to a host is outside the scope of this specification and must be documented by the host implementor.

Because OWIN is defined in terms of a raw delegate, there is no need for an assembly called "OWIN.dll" or similar. Implementing either the host or application side the OWIN spec does not introduce a dependency to a project.

Application Delegate

An application delegate takes an environment, a response callback, and an error callback. When an application delegate is invoked, it must invoke either the response callback or the error callback exactly once, or throw an exception. A callback provided to an application by a host must not throw an exception.

Environment Dictionary

When a host invokes an application delegate, it provides an environment dictionary which represents the request the application is to process. The environment dictionary also provides additional context to the application. An environment dictionary must be mutable and must contain the following keys whose values must be non-null unless otherwise specified below:

In addition to these keys, the host, application, or user may add arbitrary data associated with the request to the environment dictionary.

Response Callback

The response callback of the application delegate takes three arguments of type string, Dictionary<string, IList<string>>, and IEnumerable<object>>. These arguments together represent an HTTP response generated by an application.

The first argument to the response callback must be a string which contains the integer status of the response followed by a space and a reason phrase without a newline (e.g., "200 OK"). All characters in the status string provided by an application should be within the ASCII codepage.

The second argument to the response callback must be a mutable dictionary representing the headers to be sent with the request. The keys must be header names without ':' or whitespace. Values must be IList<string> objects containing the corresponding header value strings, without newlines. If the list object for a header name contains multiple elements, the host must write a header name-value line with that name once for each value in the list. All characters in header name and value strings should be within the ASCII codepage.

The third argument to the response callback must be a instance of IEnumerable<object> which represents the body data (the response enumerable), or null if the response does not include a body. Each item in the response enumerable may be of one of the following types (the response item types):

Hosts must write both byte[] and ArraySegment<byte> to the underlying transport as raw data. FileInfo must cause the host to write the named file to the underlying transport. How relative file paths are resolved is outside the scope of this specification and must be documented by the host implementor.

An item of the type Action<Action<object>,Action<Exception>> (an asynchronous response delegate) allows applications to provide the next item asynchronously. The semantics of this delegate are the same as that of the application delegate and the request body delegate—the host must provide non-null result and exception callbacks to the delegate, and when the delegate is invoked, the application must invoke either the result or exception callback exactly once. A host must invoke an asynchronous response delegate exactly once, and the callbacks it provides must not throw exceptions. The application may invoke the result callback with objects of any of the response item types.

In the interest of extensibility, a response enumerable may contain items whose types are not among the response item types listed above, and hosts may support additional response item types and define corresponding behaviors. If a host does not recognize the type of an object contained in the response enumerable, it may ignore the object and continue enumerating.

Hosts must enumerate the enumerable to completion (i.e., until MoveNext returns false) or until an exception is thrown by MoveNext() or the Current property. After all of the items have been enumerated or if an exception occurs during enumeration, the host must call Dispose on the enumerator.

Paths

Hosts may have the ability to map application objects to some base path. For example, a host might have an application delegate configured to respond to requests beginning with "/my-app", in which case it must set the value of "Owin.BaseUri" in the environment dictionary to "/my-app". If this host receives a request for "/my-app/foo", the Owin.RequestUri value of the environment dictionary provided to the application configured to respond at "/my-app" must be "/foo". The value of "Owin.BaseUri" may be an empty string and must not end with a trailing slash; the value of the "Owin.RequestUri" property must not be an empty string and must start with a slash.

Error Handling

Application Errors

An application might generate an exception in the following places:

An application should attempt to trap its own internal errors and generate an appropriate (possibly 500-level) response rather than propagating an exception up to the host.

After an application provides a response, if the response enumerable is non-null, the host should attempt to enumerate at least one item from the response enumerable before writing the response headers to the underlying transport. If the enumeration of the first item results in an error, the host will be able to generate a 500-level response. Otherwise, the application has caught as many of its internal errors as possible and host can begin the response without further buffering. If an exception is thrown by the application while enumerating subsequent items from the response body enumerable, the host may write a textual description of the error to the underlying transport, and/or close the connection.

Host Errors

A host might generate exceptions in the following places:

An exception generated in either of these places may indicate that the client has closed or dropped the connection, or another transport-layer error has occurred. The application should perform any post-mortem logic it needs to, and must propagate the exception back to the host through one of the sites described in Application Errors.

Example

Acknowledgments

This specification draws heavily on the wonderful PEP 333 (WSGI). Many thanks to everyone participating in the discussion at .NET HTTP Abstractions, and in particular: