Revisiting Microsoft Forms: WebForms

This is the first of several reflections on Microsoft’s original forms solutions for .NET. In this post, I want to look back at ASP.NET WebForms, or more specifically System.Web and the Page life cycle. In hindsight, I think there were some really good ideas that were just hard to understand clearly given the dominance of OO, TDD, and DDD that were at the rising to the height of popularity while WebForms was the primary ASP.NET solution.

Continue reading
Advertisement

Working with Non-Compliant OWIN Middleware

Microsoft.Owin, a.k.a. Katana, provides a number of very useful abstractions for working with OWIN. These types are optional but greatly ease the construction of applications and middleware, especially security middleware. The Katana team did a great job of ensuring their implementations work well with Microsoft.Owin as well as the standard OWIN MidFunc described below. However, not all third-party middleware implementations followed the conventions set forth in the Katana team’s implementations. To be fair, OWIN only standardized the middleware signature earlier this year, and the spec is still a work in progress.

At some point in the last year, I discovered the HttpMessageHandlerAdapter was not, in fact, OWIN compliant. I learned from the Web API team they would not be able to fix the problem without introducing breaking changes, so I came up with an adapter that should work with most implementations based on OwinMiddleware that didn’t expose the OWIN MidFunc.

The solution is rather simple, and the Katana source code provides one of the necessary pieces in its AppFuncTransition class. The adapter wraps the OwinMiddleware-based implementation and exposes the OWIN MidFunc signature. After creating the adapter specifically for HttpMessageHandlerAdapter, I created a generic version I think should work for any OwinMiddleware. (Examples in both C# and F#.)


using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using AppFunc = Func<IDictionary<string, obj>, Task>;
using MidFunc = Func<AppFunc, AppFunc>;
public class MidFuncType
{
private readonly AppFunc next;
public MidFuncType(AppFunc next)
{
this.next = next;
}
public Task Invoke(IDictionary<string, obj> environment)
{
// invoke the middleware, call `next`, etc.
// return the `Task`
return Task.FromResult<obj>(null) :> Task
}
}


open System
open System.Collections.Generic
open System.Threading.Tasks
type AppFunc = Func<IDictionary<string, obj>, Task>
type MidFunc = Func<AppFunc, AppFunc>
type MidFuncType(next: AppFunc) =
// set up the middleware
member this.Invoke(environment: IDictionary<string, obj>) : Task =
// invoke the middleware, call `next`, etc.
// return the `Task`
Task.FromResult<obj>(null) :> Task


using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Owin;
using System.Web.Http.Owin;
using AppFunc = Func<IDictionary<string, obj>, Task>
/// See https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin/Infrastructure/AppFuncTransition.cs
internal sealed class AppFuncTransition : OwinMiddleware
: base(null)
{
private readonly AppFunc next;
public AppFuncTransition(next: AppFunc)
{
this.next = next;
}
public Task Invoke(IOwinContext context)
{
// TODO: check for null
return this.next(context.Environment)
}
}
/// Explicit wrapper for HttpMessageHandlerAdapter
public class OwinMessageHandlerMiddleware
{
private readonly OwinMiddleware next;
OwinMessageHandlerMiddleware(AppFunc next, HttpMessageHandlerAdapterOptions /* I think this is the right name */ options)
{
var nextKatana = new AppFuncTransition(next);
this.next = new HttpMessageHandlerAdapter(nextKatana, options);
}
public Task Invoke(IDictionary<string, obj> environment)
{
// TODO: check for null
var context = new OwinContext(environment);
return next(context);
}
}
// This can be made generic:
/// Generic OwinMiddleware adapter
public abstract class OwinMiddlewareAdapter
{
private readonly OwinMiddleware next;
protected OwinMiddlewareAdapter(AppFunc next, Func<OwinMiddleware, OwinMiddleware> factory)
{
var nextKatana = new AppFuncTransition(next);
this.next = factory(nextKatana);
}
public Task Invoke(IDictionary<string, obj> environment)
{
// TODO: check for null
var context = new OwinContext(environment)
return next(context)
}
}
/// HttpMessageHandlerAdapter using the Generic OwinMiddleware adapter
public class OwinMessageHandlerMiddlewareAdapter : OwinMiddlewareAdapter
{
public OwinMessageHandlerMiddlewareAdapter(AppFunc next, HttpMessageHandlerAdapterOptions /* I think this is the right name */ options)
: base(next, m => new HttpMessageHandlerAdapter(m, options))
{
}
}


open System
open System.Collections.Generic
open System.Threading.Tasks
open Microsoft.Owin
open System.Web.Http.Owin
type AppFunc = Func<IDictionary<string, obj>, Task>
/// See https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin/Infrastructure/AppFuncTransition.cs
[<Sealed>]
type AppFuncTransition(next: AppFunc) =
inherit OwinMiddleware(null)
default x.Invoke(context: IOwinContext) =
// TODO: check for null
next.Invoke(context.Environment)
/// Explicit wrapper for HttpMessageHandlerAdapter
type OwinMessageHandlerMiddleware(next: AppFunc, options) =
let nextKatana = AppFuncTransition(next) :> OwinMiddleware
let webApiKatana = new HttpMessageHandlerAdapter(nextKatana, options)
member x.Invoke(environment: IDictionary<string, obj>) =
// TODO: check for null
let context = new OwinContext(environment)
webApiKatana.Invoke(context)
// This can be made generic:
/// Generic OwinMiddleware adapter
type OwinMiddlewareAdapter(next: AppFunc, factory: Func<OwinMiddleware, OwinMiddleware>) =
let nextKatana = AppFuncTransition(next) :> OwinMiddleware
let middlewareKatana = factory.Invoke(nextKatana)
member x.Invoke(environment: IDictionary<string, obj>) =
// TODO: check for null
let context = new OwinContext(environment)
middlewareKatana.Invoke(context)
/// HttpMessageHandlerAdapter using the Generic OwinMiddleware adapter
type OwinMessageHandlerMiddlewareAdapter(next: AppFunc, options) =
inherit OwinMiddlewareAdapter(next, (fun m -> new HttpMessageHandlerAdapter(m, options) :> _))

I hope that helps someone else. If there’s interest, I can package this up and place it on NuGet, though it seems a lot of effort for something so small. The source code above is released under the Apache 2 license, in keeping with the use of AppFuncTransition used above from the Katana source.

Here’s another question related to Frank What should…

Here’s another question related to Frank: What should I do about converting existing platforms’ request and response types? I had originally planned on creating my own Request and Response types, but the cost to convert back and forth may or may not be worth it. I either have to create the conversions or a different set of operators per platform.

Functional programming really lends itself to the either, but the latter is a bit more exciting. Why? Take a look at Mauricio’s latest post on Figment. He’s refactored to the Reader monad. Let’s say Frank uses the Reader and Writer monads as a public API for managing web applications. I could then allow developers to use Figment as their implementation on top of ASP.NET and build additional adapters for WebSharper, WCF, OWIN, etc. Frank would then provide a simple, functional, DSL for routing and composing web applications, even using components built on different platforms… which has been the goal all along.

The best benefit, imho, is that developers already familiar with various request/response abstractions can continue using those abstractions. I don’t provide you with yet another HTTP abstraction. This is a significant departure from all other web frameworks of which I know. I suppose the benefit is balanced against the ease of building the adapter using the monad. Time to put functional programming to the test. I am quite certain that functional programming will win.

I haven’t had a lot of time recently…

I haven’t had a lot of time recently to do much with OWIN, WCF Web API, Frack, Frank, or any of the projects I’ve been working on lately. I’m staring to pick back up on Frack, which will be undergoing some heavy refactoring, mostly for performance.

I’m also going to be finishing out the HTTP parser (finally). The big hold up so far has been trying to figure out how to do it in pieces and keep track of entire messages. Instead, I’m just going to go the old-fashioned route of expecting a complete message and parsing from beginning to end. (I should have started there.)

Frank will get a complete rewrite. Why? At this point, I’ve almost completely forgotten how or why I did some things. That’s never a good sign. It’s also a lot more complex than I was ever intending. I might arrive at some similarities, but I think a rewrite will serve it well.

In the meantime, I’ve been working on porting some sites to WebSharper. I love it. The only things I’m trying to work out are how to pull in markdown and .fsx files to render content for a lightweight git-based cms. I’m also trying to see how this might run on top of Frack.

I’m off to Boise Code Camp this weekend…

I’m off to Boise Code Camp this weekend to present on F# on the Web. No slides, just code. I’ll be talking about Frack, Frank, and WebSharper, as well as noting Dave Thomas’ F# High Performance Sockets library.

In case you are interested, Frack is available as a download from CodeBetter’s TeamCity site. Frank will be joining shortly.

Another OWIN call is scheduled for this weekend, at which point I’m likely to pick up that thread again or just move on to discussing Frack and Frank.

Middleware in the WCF Web APIs

In the last post I noted that the next post would describe middleware. For those unfamiliar with projects like WSGI and Rack, middleware is a module that wraps an application with additional functionality, such as logging, and is itself an application. Middlewares can add operations to the incoming request, the outgoing response, or wrap the entire process.

In the WCF Web APIs, the Channel model fulfills this role. Those are as yet unreleased in the current bits. However, the Processor pipeline offers another option. No, it doesn’t quite fit the definition above, but Processors allow you to add functionality to an app, providing a similar, if not the same outcome. Included in the current bits are an abstract MediaTypeProcessor, PlainTextProcessor, HtmlProcessor, XmlProcessor, and JsonProcesor. These can be hooked up through configuration to match an Accept header to perform conneg. Thus, your app can return any object, and the processor(s) will intercept and take care of serializing the outgoing response. Handy.

If you’ve been following other posts related to the WCF Web APIs, you’ll have likely come across Glenn Block’s roundup post that included Steve Michelotti’s post on rendering with the Razor view engine and Christian Weyer’s post describing how to configure JSON.NET as the default JSON serializer. Both are excellent examples of processors. With Christian’s permission, his JSON.NET processors, JsonNetProcessor and BsonSerialiser, were added to the WCF HTTP Contrib project.

I was recently wishing to use NHaml and thought about taking Steve’s excellent example as a basic framework. Then I took a look at Dotan Nahum’s Nina project and discovered something even better. Nina includes a view engine abstraction layer, similar in principle to Ryan Tomayko’s tilt library for Ruby. (You can find my initial efforts at extracting the view engine library on my fork.) Now, instead of supporting just one view engine, you can render using any of several supported view engines! Razor, Spark, NHaml, and NDjango are currently supported.

Here’s the code for the ViewEngineProcessor. You’ll notice I had to extend the MediaTypeProcessor with a generic version in order to work with the view engine api. It makes wiring things up a little messier, but nothing a clever container couldn’t handle. More work to come there.


view raw

gistfile2.txt

hosted with ❤ by GitHub


using System;
using System.Collections.Generic;
using System.ServiceModel.Description;
using Microsoft.ServiceModel.Http;
using Nina.ViewEngines;
namespace Http.Formatters
{
public class ViewEngineProcessor<T> : GenericMediaTypeProcessor<T>
{
private static readonly IDictionary<string, ITemplate> _cache = new Dictionary<string, ITemplate>();
private readonly string _basePath;
public ViewEngineProcessor(HttpOperationDescription operation, MediaTypeProcessorMode mode, string basePath = "Views/")
: base(operation, mode)
{
_basePath = basePath;
}
public override IEnumerable<string> SupportedMediaTypes
{
get
{
yield return "text/html";
//yield return "application/xhtml+xml";
}
}
public override object ReadFromStream(System.IO.Stream stream, System.Net.Http.HttpRequestMessage request)
{
throw new NotImplementedException();
}
public override void WriteToStream(T instance, System.IO.Stream stream, System.Net.Http.HttpRequestMessage request)
{
ITemplate template;
string templateName = _basePath + typeof(T).Name;
Type modelType = instance.GetType();
if (Nina.Configuration.Configure.IsDevelopment || !_cache.TryGetValue(templateName, out template))
{
template = Nina.Configuration.Configure.Views.Engine.Compile<T>(templateName);
_cache[templateName] = template;
}
using (var sw = new System.IO.StreamWriter(stream.PreventClose()))
{
template.Render(sw, instance);
sw.Flush();
}
}
}
}

All this is available in the WCF HTTP Contrib project. I’m sure it will develop into something a bit nicer as we progress. Also, I want to cover channels at some point, as they will offer a nicer composition mechanism for things like security, general logging, and other common middleware patterns found in the projects mentioned above.

Have you tried the WCF Web APIs? If so, please leave the team some feedback. They’d love to hear from you. Check out the contrib project while you’re at it. Want to see something in particular? File a case or contribute. And thank Darrel Miller for setting it up!

*[conneg]: content negotiation

A New Web for .NET

A number of things have been happening these last few years in the .NET community in relation to the Web. Specifically, OpenRasta and FubuMvc demonstrated 1) new approaches to web development in a static-typed world and 2) that other developers were growing tired of the existing options. Since then a host of new micro-frameworks, generally inspired by the Ruby dynamic duo of Rack and Sinatra, have popped up on github. In addition, several new server options have begun cropping up, most notably Kayak and Manos de Mono, both of which use an event loop a la node.js and primarily targeting Mono.

Microsoft has not be sitting idly by either. The WCF team is working on a new Web API to provide WCF developers simpler, more direct control over HTTP services. This is no slouch effort either. In fact, aside from OpenRasta, it may be the most thorough HTTP implementation available.

While exciting on their own, the best news, imho, is the .NET HTTP Abstractions group, started by Scott Koon. This group has been working on a standard, currently called Open Web Interface for .NET, or OWIN. It’s intent is to define a common interface by which any application can talk to any server. The idea comes from the Web Server Gateway Interface (Python) and Rack. The primary difference in this and other similar specs is the inclusion of asynchronous network I/O as a primary concern. Discussions are still underway and include nearly all of the developers of the aforementioned projects, as well as some members of the ASP.NET team.

If you are a F# fanboy, such as myself, you will be happy to know that F# is not silent in this space. WebSharper is now in its second iteration, and my own projects, Frack and Frank, are making nice headway. Frack is now a web server, similar in spirit to node.js. Frank is, as the name implies, a Sinatra-inspired clone that takes cues from the Haskell Snap framework. If you are interested in parsing and agent-based development, you’ll find more examples of how F# handles these things as these two projects progress.

Expect to find more posts (shock!) coming soon describing in more detail the WCF Web APIs, OWIN, Frack, Frank, and more. In the meantime, join the discussion on the .NET HTTP Abstractions group!