1 2 3 4 5 6 7 8 9 10 | public void Configuration(IAppBuilder app) { // Configure WebApi var config = new HttpConfiguration(); config.Routes.MapHttpRoute( "API Default" , "api/{controller}/{id}" , new { id = RouteParameter.Optional }); app.UseWebApi(config); // Configure SignalR app.MapHubs(); } |
1 2 3 4 5 | public IAppBuilder Use( object middleware, params object [] args) { this ._middleware.Add(AppBuilder.ToMiddlewareFactory(middleware, args)); return (IAppBuilder) this ; } |
Microsoft.Owin.Diagnostics
The package Microsoft.Owin.Diagnostics contains one useful feature catching and displaying exceptions. For sure this shouldn't happen, but when it would be nice to know about. But as always you should consider to use it only during development.To switch it on, simply add the following line at the beginning of Startup.Configuration():
1 | app.UseShowExceptions(); |
Another feature in Microsoft.Owin.Diagnostics is
1 | app.UseTestPage(); |
But anyway, this feature is useful only in hello world status. Later I would prefer to get HTTP 404 instead of this message.
Microsoft.Owin.StaticFiles
Like most of the other OWIN packages, also Microsoft.Owin.StaticFiles is in prerelease status. But this package is special, you even cannot find it in NuGet. To install it, you need to enter the following command in the Package Manager Console:1 | Install-Package Microsoft.Owin.StaticFiles -Version 0.20-alpha-20220-88 -Pre |
You can get the nightly builds from a separate feed: http://www.myget.org/f/Katana.
After adding the package, just add one line to Startup.Configuration():
1 | app.UseStaticFiles( "StaticFiles" ); |
When you start the project, you can fire up the browser and enter http://localhost:8080/test.htm (without specifying the StaticFiles folder), and you get simply the page back.
Logging OWIN requests
Sometimes it would be interesting to see the incoming requests in a trace. This can be achieved with a custom feature. The constructor is quite simple. It just stores the reference to the next feature:1 2 3 4 5 6 7 8 | private readonly Func<IDictionary< string , object >, Task> _next; public Logger(Func<IDictionary< string , object >, Task> next) { if (next == null ) throw new ArgumentNullException( "next" ); _next = next; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public Task Invoke(IDictionary< string , object > environment) { string method = GetValueFromEnvironment(environment, OwinConstants.RequestMethod); string path = GetValueFromEnvironment(environment, OwinConstants.RequestPath); Console.WriteLine( "Entry\t{0}\t{1}" , method, path); Stopwatch stopWatch = Stopwatch.StartNew(); return _next(environment).ContinueWith(t => { Console.WriteLine( "Exit\t{0}\t{1}\t{2}\t{3}\t{4}" , method, path, stopWatch.ElapsedMilliseconds, GetValueFromEnvironment(environment, OwinConstants.ResponseStatusCode), GetValueFromEnvironment(environment, OwinConstants.ResponseReasonPhrase)); return t; }); } |
GetValueFromEnvironment is only a little helper, since in some cases the environment dictionary does not contains all values:
1 2 3 4 5 6 | private static string GetValueFromEnvironment(IDictionary< string , object > environment, string key) { object value; environment.TryGetValue(key, out value); return Convert.ToString(value, CultureInfo.InvariantCulture); } |
1 | app.Use( typeof (Logger)); |
Logging the Request Body
With POST requests, it can be very handy to log also the request body. For this, you have only to extend the Invoke method a little bit:1 2 3 4 5 6 7 | string requestBody; Stream stream = (Stream)environment[OwinConstants.RequestBody]; using (StreamReader sr = new StreamReader(stream)) { requestBody = sr.ReadToEnd(); } environment[OwinConstants.RequestBody] = new MemoryStream(Encoding.UTF8.GetBytes(requestBody)); |
Fortunately, this is no big issue: just replace the old stream with a new MemoryStream. For sure, this is not good idea with big request bodies. In such a case you will need a more sophisticated solution. But normally, it should be good enough. Moreover, you can use it only during development. In production you can disable it by configuration, par example.
Logging SignalR
With the Logger from above, you get a nice logging of the several SignalR requests (when it uses LongPolling instead of WebSockets):1 2 3 4 5 6 7 8 9 10 | 10:51:18,181 11 Entry GET /signalr/negotiate 10:51:18,263 8 Exit GET /signalr/negotiate 82 10:51:18,271 11 Entry GET /signalr/ping 10:51:18,275 8 Exit GET /signalr/ping 4 10:51:18,540 11 Entry GET /signalr/connect 10:53:08,806 14 Exit GET /signalr/connect 110260 10:53:08,826 11 Entry GET /signalr/poll 10:54:58,960 15 Exit GET /signalr/poll 110128 10:54:58,969 11 Entry GET /signalr/poll 10:56:49,136 12 Exit GET /signalr/poll 110161 |
You can also see that all requests (at least in this example) are handled by the same thread (11). But the response is created by other threads (8, 14, 15 and 12).
Summary
It is quite easy to add additional features to an OWIN host. And it is also not too hard to implement own features. Drawbacks of the whole stuff are (hopefully only at the moment):- the beta status of some packages
- the lack of documentation
You can find the source code at GitHub: https://github.com/Ritzlgrmft/OwinConfiguration.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.