Open Web Interface for .NET (OWIN) ------------------------------------------------------------------------- Running OWIN middleware in the ASP.NET pipeline "dependencies": { "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Owin": "1.0.0" }, public Task OwinHello(IDictionary<string, object> environment) { string responseText = "Hello World via OWIN"; byte[] responseBytes = Encoding.UTF8.GetBytes(responseText); // OWIN Environment Keys: http://owin.org/spec/spec/owin-1.0.0.html var responseStream = (Stream)environment["owin.ResponseBody"]; var responseHeaders = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"]; responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) }; responseHeaders["Content-Type"] = new string[] { "text/plain" }; return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); } public void Configure(IApplicationBuilder app) { app.UseOwin(pipeline => { pipeline(next => OwinHello); }); } app.UseOwin(pipeline => { pipeline(next => { // do something before return OwinHello; // do something after }); }); ------------------------------------------------------------------------------------------------- Using ASP.NET Hosting on an OWIN-based server using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Owin; using Microsoft.Extensions.Options; using Nowin; namespace NowinSample { public class NowinServer : IServer { private INowinServer _nowinServer; private ServerBuilder _builder; public IFeatureCollection Features { get; } = new FeatureCollection(); public NowinServer(IOptions<ServerBuilder> options) { Features.Set<IServerAddressesFeature>(new ServerAddressesFeature()); _builder = options.Value; } public void Start<TContext>(IHttpApplication<TContext> application) { // Note that this example does not take into account of Nowin's "server.OnSendingHeaders" callback. // Ideally we should ensure this method is fired before disposing the context. Func<IDictionary<string, object>, Task> appFunc = async env => { // The reason for 2 level of wrapping is because the OwinFeatureCollection isn't mutable // so features can't be added var features = new FeatureCollection(new OwinFeatureCollection(env)); var context = application.CreateContext(features); try { await application.ProcessRequestAsync(context); } catch (Exception ex) { application.DisposeContext(context, ex); throw; } application.DisposeContext(context, null); }; // Add the web socket adapter so we can turn OWIN websockets into ASP.NET Core compatible web sockets. // The calling pattern is a bit different appFunc = OwinWebSocketAcceptAdapter.AdaptWebSockets(appFunc); // Get the server addresses var address = Features.Get<IServerAddressesFeature>().Addresses.First(); var uri = new Uri(address); var port = uri.Port; IPAddress ip; if (!IPAddress.TryParse(uri.Host, out ip)) { ip = IPAddress.Loopback; } _nowinServer = _builder.SetAddress(ip) .SetPort(port) .SetOwinApp(appFunc) .Build(); _nowinServer.Start(); } public void Dispose() { _nowinServer?.Dispose(); } } } using System; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.Extensions.DependencyInjection; using Nowin; using NowinSample; namespace Microsoft.AspNetCore.Hosting { public static class NowinWebHostBuilderExtensions { public static IWebHostBuilder UseNowin(this IWebHostBuilder builder) { return builder.ConfigureServices(services => { services.AddSingleton<IServer, NowinServer>(); }); } public static IWebHostBuilder UseNowin(this IWebHostBuilder builder, Action<ServerBuilder> configure) { builder.ConfigureServices(services => { services.Configure(configure); }); return builder.UseNowin(); } } } using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; namespace NowinSample { public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseNowin() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); } } } ------------------------------------------------------------------------------ Run ASP.NET Core on an OWIN-based server and use its WebSockets support public class Startup { public void Configure(IApplicationBuilder app) { app.Use(async (context, next) => { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); await EchoWebSocket(webSocket); } else { await next(); } }); app.Run(context => { return context.Response.WriteAsync("Hello World"); }); } private async Task EchoWebSocket(WebSocket webSocket) { byte[] buffer = new byte[1024]; WebSocketReceiveResult received = await webSocket.ReceiveAsync( new ArraySegment<byte>(buffer), CancellationToken.None); while (!webSocket.CloseStatus.HasValue) { // Echo anything we receive await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, received.Count), received.MessageType, received.EndOfMessage, CancellationToken.None); received = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); } await webSocket.CloseAsync(webSocket.CloseStatus.Value, webSocket.CloseStatusDescription, CancellationToken.None); } } } ------------------------------------------------------------------------------------------------ OWIN keys Request Data (OWIN v1.0.0) Key Value (type) Description owin.RequestScheme String owin.RequestMethod String owin.RequestPathBase String owin.RequestPath String owin.RequestQueryString String owin.RequestProtocol String owin.RequestHeaders IDictionary<string,string[]> owin.RequestBody Stream Request Data (OWIN v1.1.0) Key Value (type) Description owin.RequestId String Optional Response Data (OWIN v1.0.0) Key Value (type) Description owin.ResponseStatusCode int Optional owin.ResponseReasonPhrase String Optional owin.ResponseHeaders IDictionary<string,string[]> owin.ResponseBody Stream Other Data (OWIN v1.0.0) Key Value (type) Description owin.CallCancelled CancellationToken owin.Version String Common Keys Key Value (type) Description ssl.ClientCertificate X509Certificate ssl.LoadClientCertAsync Func<Task> server.RemoteIpAddress String server.RemotePort String server.LocalIpAddress String server.LocalPort String server.IsLocal bool server.OnSendingHeaders Action<Action<object>,object> SendFiles v0.3.0 Key Value (type) Description sendfile.SendAsync See delegate signature Per Request Opaque v0.3.0 Key Value (type) Description opaque.Version String opaque.Upgrade OpaqueUpgrade See delegate signature opaque.Stream Stream opaque.CallCancelled CancellationToken WebSocket v0.3.0 Key Value (type) Description websocket.Version String websocket.Accept WebSocketAccept See delegate signature. websocket.AcceptAlt Non-spec websocket.SubProtocol String See RFC6455 Section 4.2.2 Step 5.5 websocket.SendAsync WebSocketSendAsync See delegate signature. websocket.ReceiveAsync WebSocketReceiveAsync See delegate signature. websocket.CloseAsync WebSocketCloseAsync See delegate signature. websocket.CallCancelled CancellationToken websocket.ClientCloseStatus int Optional websocket.ClientCloseDescription String Optional