HttpListener
)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.
Benjamin van der Veen proposed the first set 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();
} |
Scott Koon creates .NET HTTP Abstractions
https://groups.google.com/forum/#!forum/net-http-abstractions
IDictionary<string, object>
to the rescue!
Stream
IObservable<T>
Task<T>
Accepted!
public delegate void AppDelegate(
IDictionary<string, object> env,
ResultDelegate result,
Action<Exception> fault);
public delegate void ResultDelegate(
string status,
IDictionary<string, IEnumerable<string>> headers,
BodyDelegate body);
public delegate void BodyDelegate(
Func<ArraySegment<byte>, bool> write,
Func<Action, bool> flush,
Action<Exception> end,
CancellationToken cancellationToken); |
"Delegate of Doom" proved too difficult for most
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.
using AppFunc = Func<IDitionary<string, object>, Task> |
Task
?Specified type aliases removed, but IAppBuilder
remains:
public interface IAppBuilder
{
IDictionary<string, object> Properties { get; }
IAppBuilder Use(object middleware, params object[] args);
object Build(Type returnType);
IAppBuilder New();
} |
public class Startup {
public void Configuration(IAppBuilder app) {
app.Properties["host.AppName"] = "composed app";
app.UseCors(Cors.CorsOptions.AllowAll)
.UseWebApi(new HttpConfiguration())
.MapHubs("signalr", new HubConfiguration())
.UseNancy();
}
} |
(with apologies to Rupert Holmes)
(verse 1)
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.
September 27, 2010
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();
} |
(chorus)
(Just like the cool kids)
(verse 2)
IDictionary<string, object>
(chorus)
Stream
s were considered "too heavy";IObservable<T>
too newTask
required a framework versionpublic delegate void AppDelegate(
IDictionary<string, object> env,
ResultDelegate result,
Action<Exception> fault);
public delegate void ResultDelegate(
string status,
IDictionary<string, IEnumerable<string>> headers,
BodyDelegate body);
public delegate void BodyDelegate(
Func<ArraySegment<byte>, bool> write,
Func<Action, bool> flush,
Action<Exception> end,
CancellationToken cancellationToken); |
(verse 3)
(chorus)
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.
using AppFunc = Func<IDitionary<string, object>, Task> |
Task
?(verse 4)
(chorus)
.Use
and .Map
extensions,