Skip to content

Add your own interfaces

Ian Battersby edited this page Sep 11, 2013 · 2 revisions

Simple.Web handlers implement interfaces, either to ask for information from the request, or to indicate that they will supply specific information to the response. For example, the IRequireAuthentication interface tells the framework that the user must be logged in, and adds a CurrentUser property to the handler which the framework will set if the user is authenticated. If they're not, they'll be redirected to the login page.

This system is extensible, so that it is easy to add your own interfaces and the code to hook them up. The built-in behaviours are nearly all based on the same system, so your extensions are treated no differently to the core functionality. As an example, here is some code to get the raw query-string from the URI, if you needed that sort of thing:

Code

[RequestBehavior(typeof(SetQueryString))]
public interface IQueryString
{
    public IDictionary<string,string[]> QueryString { get; set; }
}

public static class SetQueryString
{
    public static void Impl(IQueryString handler, IContext context)
    {
        handler.QueryString = context.Request.QueryString;
    }
}

Explanation

So, the RequestBehavior attribute is applied to the interface to say it's part of the handler-setup phase of the request lifecycle, and you supply the type of the implementation class.

The implementation class should be public and static, with a public static method called Impl, which takes an instance of the interface as its first parameter, and an IContext as its second.

The Impl method can return either void or bool; if its return type is bool and the method returns false, the request lifecycle is stopped at that point.

As well as RequestBehavior, there are ResponseBehavior and OutputBehavior attributes. The way they are all called is as follows:

  • RequestBehavior implementations;
  • Handler's primary method (e.g. Get, Post, etc.)
  • ResponseBehavior implementations;
  • OutputBehavior implementations.

The only things that happen outside of this extensible pipeline are cookie handling (which don't use interfaces) and redirection (which happens before ResponseBehavior, if a Redirect-y status is returned).

To get a better idea of how this all works, you can check out the Behaviors namespace in the core code.

Advice

Try to use this extensible pipeline to maintain the separation between IContext, IRequest and IResponse and the actual application code in your handlers. As soon as you introduce a dependency on any of those interfaces, you're into Mocking Hell, which is exactly what this whole system is trying to avoid.