2. Welcome to Houston TechFest
⢠Please turn off all electronic devices or set them to vibrate.
⢠If you must take a phone call, please do so in the lobby so as not
to disturb others.
⢠Thanks to our Diamond Sponsors:
Thank you for being a part of the
9th Annual Houston TechFest!
3. 2
Please Leave Feedback During Q&A
If you leave session
feedback and provide
contact information in
the survey, you will be
qualified for a prize
Scan the QR Code to
the right or go to
http://bit.ly/1K1Hvi5
4. 3
Ryan Riley
⢠Engineer at Tachyus
⢠OWIN Management Committee
⢠ASPInsider
⢠Visual F# MVP
⢠Leads Community for F#
5. 4
Click to edit Master title style
Why OWIN?
Open Web Interface for .NET
6. 5
Click to edit Master title style
Problem: Desire for Fast and
Light-weight Frameworks and
Servers
ASP.NET was âtoo heavyâ
IIS was âtoo slowâ
ASP.NET was coupled to IIS
Hard to do REST
7. 6
Solutions
⢠Boat
⢠Figment
⢠Fracture
⢠Frank
⢠FubuMVC
⢠KayakHTTP
⢠NancyFx
⢠Nina
⢠NRack
⢠OpenRasta
⢠Suave
⢠WCF Web API (later ASP.NET Web API)
⢠Among others
8. 7
Click to edit Master title style
Problem: Repetition
Sinatra in .NET
ASP.NET adapters
Self-host adapters (esp. HttpListener)
10. 9
September 7, 2010
Iâve noticed a trend recently in projects each of us has worked/is
working on and wondered if we might be willing to pool our
resources.... If you are interested in working together, please let me
know.... Iâm sure we could agree on a common platform for our efforts.
- Email from Ryan Riley (Frank) to
Benjamin van der Veen (KayakHTTP),
Mauricio Scheffer (Figment), and
Scott Koon (Boat)
11. 10
September 27, 2010
Benjamin van der Veen submits first draft of interfaces
public interface IHttpResponder {
IObservable<IHttpServerResponse> Respond(
IHttpServerRequest request,
IDictionary<string, object> context
);
}
public interface IHttpServerRequest {
HttpRequestLine RequestLine { get; }
IDictionary<string, string> Headers { get; }
IObservable<ArraySegment<byte>> GetBodyChunk();
}
public interface IHttpServerResponse {
HttpStatusLine StatusLine { get; }
IDictionary<string, string> Headers { get; }
string BodyFile { get; }
IObservable<ArraySegment<byte>> GetBodyChunk();
}
12. 11
November 29, 2010
Scott Koon creates .NET HTTP Abstractions
⢠Now called OWIN Working Group
⢠https://groups.google.com/forum/#!forum/
net-http-abstractions
13. 12
Click to edit Master title style
Problem: Opinions and Existing
Implementations
16. 15
Progress!
⢠Name: Open Web Interface for .NET (OWIN)
⢠Began writing specification
⢠BHAG: run ASP.NET MVC on top
17. 16
Click to edit Master title style
Problem: Trouble in Paradise
18. 17
Solutions
Factions
⢠Which interfaces / types?
⢠Require a library dependency?
⢠OOP vs FP
⢠Static vs Dynamic typing
Solutions
⢠Only types from the FCL
⢠No library dependency
⢠Delegates +
⢠IDictionary<string, object>
19. 18
Click to edit Master title style
Problem: How to represent async
access to the message body?
20. 19
Proposed Solution #1: System.IO.Stream
⢠Considered âtoo heavyâ as an interface
⢠Async access considered âtoo slowâ due to APM model
⢠Rejected
21. 20
Proposed Solution #2: System.IObservable<T>
⢠Concerned about back-pressure
⢠Required library dependency for .NET 3.5
⢠Rejected
22. 21
Proposed Solution #3: Task
⢠Required (then new) .NET 4.0
⢠Some contributors had an established .NET 3.5 user base
⢠Rejected
36. 35
Using AppFunc
using System.IO;
using System.Text;
using Headers = IDictionary<string, string[]>;
var app = AppFunc(env =>
{
var bytes = Encoding.UTF8.GetBytes("Hello, OWIN!");
var length = bytes.Length.ToString();
var headers = (Headers)env.["owin.ResponseHeaders"];
headers.Add("Content-Type", new[] { "text/plain" });
headers.Add("Content-Length", new[] { length });
var stream = (Stream)env.["owin.ResponseBody"];
return stream.WriteAsync(bytes, 0, bytes.Length);
});
37. 36
Flexibility: AppFunc as a Class
public class MyApp
{
public Task Invoke(Environment env)
{
var bytes = Encoding.UTF8.GetBytes("Hello, OWIN!");
var length = bytes.Length.ToString();
var headers = (Headers)env.["owin.ResponseHeaders"];
headers.Add("Content-Type", new[] { "text/plain" });
headers.Add("Content-Length", new[] { length });
var stream = (Stream)env.["owin.ResponseBody"];
return stream.WriteAsync(bytes, 0, bytes.Length);
}
}
38. 37
Flexibility: AppFunc as a Method
public class MyApps
{
public Task MyApp1(Environment env)
{
// uses state from MyApps
}
public static Task MyApp2(Environment env)
{
// does not use MyAppsâ state
}
}
39. 38
AppFunc Composition
public static class Logging
{
public static Task LogBefore(Environment env) { /**/ }
public static Task LogAfter(Environment env) { /**/ }
public static ???? Log(????)
{
LogBefore(env);
// call something else, but how?
LogAfter(env);
}
}
40. 39
Middleware
using MidFunc = Func<AppFunc, AppFunc>;
public static class Logging
{
public static Task LogBefore(Environment env) { /**/ }
public static Task LogAfter(Environment env) { /**/ }
public static AppFunc Log(AppFunc next)
{
return async env => {
LogBefore(env);
await next(env);
LogAfter(env);
};
}
}
41. 40
Middleware as a Class
public class Logging
{
AppFunc next;
public Logging(AppFunc next)
{
this.next = next;
}
static Task LogBefore(Environment env) { /**/ }
static Task LogAfter(Environment env) { /**/ }
public async Task Invoke(Environment env)
{
LogBefore(env);
await this.next(env);
LogAfter(env);
}
}
42. 41
OO AppFunc Composition
public class Startup
{
private readonly AppFunc composed;
public Startup(AppFunc next)
{
this.composed = Logging.Log(next);
}
public Task Invoke(Environment env)
{
return this.composed(env);
}
}
43. 42
Functional AppFunc Composition
public static class Startup
{
static readonly AppFunc next = ...;
static readonly AppFunc composed = Logging.Log(next);
public static Task Invoke(Environment env)
{
return Startup.composed(env);
}
}
50. 49
Put It All Together
// Using Microsoft.Owin
public class Startup {
public void Configuration(IAppBuilder app) {
app.Properties["host.AppName"] = "composed app";
app.UseCors(Cors.CorsOptions.AllowAll)
.MapSignalR()
.UseWebApi(new HttpConfiguration())
.UseNancy();
}
}
51. 50
Artifact: owin.dll
⢠Originally intended to provide the delegate signatures
⢠IAppBuilder was later added and left as the only interface
⢠IAppBuilder was not specâd and had no connection to AppFunc
public interface IAppBuilder
{
IDictionary<string, object> Properties { get; }
IAppBuilder Use(object middleware, params object[] args);
object Build(Type returnType);
IAppBuilder New();
}
53. 52
OWIN Management Committee
⢠Established governance model
⢠Converted specs to Markdown (https://github.com/owin/owin)
⢠GitHub Issues to submit and vote on changes
(https://github.com/owin/owin/issues)
54. 53
Formalized Middleware Signature
⢠Specification in draft
using MidFunc = Func<AppFunc, AppFunc>
using MidFactory =
Func<
IDictionary<string, object>, // startup properties
MidFunc // outer Middleware
>
using BuildFunc = Action<MidFactory>
60. 59
Dynamic Pipeline
⢠Techniques used by Damian Hickey and Sebastian Lambla
⢠Middleware builds and executes its own pipeline
⢠Can change during runtime
⢠See an example
64. 63
Get Involved!
⢠Submit your feedback on the specs
⢠Help us with governance
⢠Propose and vote on next steps
⢠http://owin.org/
⢠https://github.com/owin/owin/issues
⢠http://groups.google.com/group/net-http-abstractions
65. Please Leave Feedback During Q&A
If you leave session
feedback and provide
contact information in
the survey, you will be
qualified for a prize
Scan the QR Code to
the right or go to
http://bit.ly/1K1Hvi5
A Problem / Solution review of the evolution of the Open Web Interface for .NET
In order to understand why we created OWIN, you have to put yourself back into 2010.
Ruby on Rails, introduced in 2005, made MVC very popular by 2007-2008.
Rack, Sinatra, and similar efforts appeared in other platforms simultaneously.
ASP.NET MVC came out in the Spring of 2009.
NuGet wasnât released until late fall of 2010.
WebForms was still the dominant platform for web apps.
WCF was the go-to for web services.
Both MVC and WebForms were tied to IIS.
Throughout 2010, many solutions appeared, both in terms of optional frameworks and servers.
Nearly all the frameworks created targeted something similar to Rubyâs Sinatra.
Nearly all had mostly identical adapters for running their framework on ASP.NET / IIS, HttpListener, and/or other servers.
http://despair.com/products/collaboration
Solution: collaboration!
Collaboration is always a good idea, so long as others collaborate with you and use your ideas.
Since so many had already created solutions and started growing a following, they were understandably hesitant to just drop what they had and adopt some common solution.
We had to agree on what we could share and how we could share it.
Sebastian Lambla proposed the name âOWIN,â and it stuck.
Lou de Jardin and Benjamin van der Veen started writing the spec under the guidance of Jason Sirota.
We actually had a decent organization around all this effort early on, including support from MonkeySpace coordinator Dale Ragan.
We decided we would also attempt to lift MVC off ASP.NET and get it running on OWIN as our BHAG.
Conference sessions were scheduled, and implementations began to appear as proposals for adoption.
Since most everyone had by this time developed their own context, request, and response types that they very much liked and had built around, no one really wanted to budge and agree on a standard set of interfaces. The existing HttpContext, HttpRequest, and HttpResponse types from ASP.NET played into this, as well, as most of us realized we would probably get something wrong and then have to renegotiate over how to version the shared library. A few, prominent voices pushed hard for avoiding a shared library, and rather than lose them, we agreed to go without a shared library. As you might expect, this greatly limited our type options.
Many ask about the reason for selecting delegates and an un-typed dictionary. To understand, you must remember the context of the time. IronPython and IronRuby were still in active development by Microsoft, and several of the early contributors to OWIN came from those language communities. We perceived the use of the dictionary would better map to those languages existing interfaces (Rack / Python) and had a general idea that we would like to try to make it easy to adapt tools like Rack and WSGI implementations to work with OWIN. Further, the use of a dictionary satisfied the requirement to use FCL types and allowed for further iteration in the future by changing only the spec and not the implementations. We thought this also better supported and encouraged use of feature detection â which was needed anyway to take advantage of server-specific features â rather than relying on forced type constraints.
As for the delegates, a delegate may represent a class with a constructor and a single method, and we found this sufficient for our needs. Some suggested such things as Church-encoding to map to actual types, but the majority felt this was too complicated to use in the spec and that should such a thing be wanted, it could be layered on top.
The last decision came down to how to represent asynchronous access to request and response streams.
Rack and WSGI had by this time recognized this was very nice to have but had already committed to synchronous access and had to adopt work-arounds.
We wanted to address this head on, but we we had a long deliberation as to how to do so.
Image from âThe Reality of a Developer's Life - in GIFs, Of Courseâ (http://server.dzone.com/articles/reality-developers-life-gifs)
Wait a minute. Didnât we say we didnât want a dependency library? Gate became a sort of relied upon library for using the Delegate of Doom, though some managed to build their own implementations.
NOTE: Gate became the basis for Microsoftâs Katana (Microsoft.Owin) library(-ies).
Image from âThe Reality of a Developer's Life - in GIFs, Of Courseâ (http://server.dzone.com/articles/reality-developers-life-gifs)
Wait a minute. Didnât we say we didnât want a dependency library? Gate became a sort of relied upon library for using the Delegate of Doom, though some managed to build their own implementations.
NOTE: Gate became the basis for Microsoftâs Katana (Microsoft.Owin) library(-ies).
https://groups.google.com/d/msg/net-http-abstractions/Cbvy2x27Few/Oor2UwA0W1wJ
Explained
There are ways to run a single-tap web framework on a double-tap owin pipeline, but they all boil down to buffering write data.... Increased complexity, more memory to hold the body until the fwk returns, and cpu spent copying that data⌠Plus for fully synchronous web frameworks it means every response body will be entirely buffered because thereâs no way for the server to deliver the output stream until the initial call returns. ... itâs pretty extreme compared to just passing the serverâs output stream and a response header idictionary in the original call.
Running a double-tap framework on a single-tap pipeline by comparison is easy â the adapter just calls framework then calls its callback with the output stream.
https://groups.google.com/d/msg/net-http-abstractions/Cbvy2x27Few/Oor2UwA0W1wJ
Explained
There are ways to run a single-tap web framework on a double-tap owin pipeline, but they all boil down to buffering write data.... Increased complexity, more memory to hold the body until the fwk returns, and cpu spent copying that data⌠Plus for fully synchronous web frameworks it means every response body will be entirely buffered because thereâs no way for the server to deliver the output stream until the initial call returns. ... itâs pretty extreme compared to just passing the serverâs output stream and a response header idictionary in the original call.
Running a double-tap framework on a single-tap pipeline by comparison is easy â the adapter just calls framework then calls its callback with the output stream.
Wait, how did Task suddenly reappear?
By this time, most everyone still involved had upgraded to .NET 4.0 or at least no longer cared about supporting .NET 3.5.
August 22, 2012, coincidentally the birthdate of my youngest daughter.
The last two were added in the 1.0.1 draft.
* More on dynamic execution graphs later.
IAppBuilder was meant as a discovery mechanism. No one wrote a spec for the interface, so implementations varied, some adding lifecycle semantics that conflicted with other implementations. At present, this interface is deprecated though still available on NuGet and available for use by original implementations.
Early in the development of vNext, things looked really good for OWIN. vNext appeared to build on the work of Katana. However, something happened along the way to shift the direction of vNext away from OWIN.
The good news is ASP.NET 5 still supports OWIN, though itâs more a bolt-on than a first-class citizen. OWINâs simplicity, on the other hand, ensures it should work just fine on DNX, though you will need to build out host / server support if you donât want to run through ASP.NET.
As noted earlier, IAppBuilder appeared without anyone really noticing it. However, it quickly took center stage and shifted the focus off the goals of OWIN and onto a particular discovery and composition model that had never really been discussed.
IAppBuilderâs acceptance of Object as its input to its Use member caused most of the problems. We didnât think we needed to define Middleware at the outset because several of us thought the composition model so obvious. IAppBuilder obstructed the clarity and shifted the focus of middleware to a lesser form of use in which middleware stood in line and handled or ignored an OWIN environment until one of them completed the Task. While quite ingenious and useful, this became the standard pattern. Only later did some really useful patterns for graph-based routing, dynamic pipeline composition, and more finally emerge.
In any case, Middleware has been both a challenge and one of the most exciting aspects of OWIN. Examples follow.
All of the above are perfectly valid and further highlight the flexibility of OWIN.