Some honest and unedited notes from my ‘scrapbook’, on work and life.

I want to join you or you join me, because..

  • Consultancy – I can feel knowledgable and rewarded but I don’t feel invested
  • Contracting – You had to hire me because you can’t manage your business, bad start
  • Evangelism – Nearly but no cigar, travel isn’t right for me at the moment
  • Partners – This is for me, but I want to work ‘with’ you and not ‘for’ you

We should be equally invested in the vision..

  • Products – We should focus and build something to continued success
  • Invested – Shares are nice but let’s be truly invested, even after 1 day it’s our company

Our health should is all of our responsibility..

  • We are what we eat – Lets encourage each other to eat well and nutritionally
  • Healthy Body Healthy Mind – Our business works best when we are fit & healthy
  • Hammock time – We should encourage ourselves to take breaks and balance life

Support each other whilst we do our best work..

  • Flexible working – Let us work when we can do our best work, and still love our families
  • Coffee Me Good – When we have access to good caffine (refreshments) we are fuelled
  • Free & Easy – We work best when we’re comfortable, sneakers & jeans, comfy chair, whatever!
  • Home or Away – Location isn’t important, apart from it being best for our work
  • Tools – Let us choose our own tools in which we practice our craft

In summary;

If you want us to do our best work together, to enjoy it and share our passion with each other, be innovative and create something amazing:

.. PARTNER ME, INVEST US, SUPPORT OUR DREAM, LET’S HAVE FUN!

PS. Did you notice not once did I mention financial renumeration, I only just realised.

TL;DR Self-indulgent post about how I am finally going to kick Windows out the door.

The last couple of weeks have been rather strange. I’ve moved from a position of living with Windows in my day job to detesting every morselized key-stroke I have to make in our soul sapping co-existence. Let me make one thing clear about this post however, I’m not leaving .NET, but I am leaving Windows.

Problem

I’ve been enamored with C# and .NET since sitting inside Microsofts’ HQ being shown their upcoming new language. When Macs started to appear in our household around 2004, and satisfying previous fraternization with Linux, I started to move back to C and onto PHP for a new business venture.

Since then and through my on-going polyglot adventures I’ve used many more languages, and even the odd framework, but .NET remains the most commercially viable for clients, with only golang and Kotlin now making inroads. I’d hoped Mono would save the day, but there’s always a price to be paid for salvation.

Salvation

I’ve plugged away with Mono for many years in an effort to reach my Holy Grail, but when Xamarin became focused on mobile and away from ‘Mono on the server’ progress stagnated and faith in Mono as a viable commercial alternative suffered greatly.

Many of us continue to plug away ensuring Mono compatibility in our software, contributing to community efforts, even to Microsoft, but I foresee for C# and .NET to survive there needs to be a colossal shift – from Microsoft.

Cometh

I’ve petitioned Miguel de Icaza to help the community without success. The truth is that their business is rightly focused on their own vision, and that’s mobile. The interest in .NET and C# succeeding now ironically seems to sit with Microsoft, and so I believe it is them who should take Mono under their wing, and make .NET cross-platform.

I propose this as viable because I believe so much of their developer base (and dare I say the innovative and talented developers) are shifting away to such an extent this is now THEIR salvation. Growing popularity of JVM and natively compiled languages mean C# and .NET will ultimately suffer, and so will Windows and its products.

So there, I said it ;–)

Massive thanks from Mark and I for the overwhelming support from contributors in this release. In case you missed it we also moved our TeamCity CI server to simpleci.org which boasts lots more power.

Support multiple query string values with the same key

Support for deserialization of multiple querystring values of the same key into an IEnumerable. We have some further optimisation work to do but glad to see it now supported. Thanks @tapmantwo for your pull-request!

Windsor IoC support (.NET only)

Castle Windsor IoC container now supported. We have unfortunately not yet been able to fill-in the missing blanks in Mono but it is available for .NET nonetheless. Thanks @mickdelaney!

Dispose() not called on Handler:IDisposable

Thanks to @jjvdangelo for spotting Dispose() wasn’t being called on Handler:IDisposable.

Fixed Cookie handling in Pipeline

Mark addressed some issues with cookie handling in the pipeline with his usual voodoo.

Media Type Handler Updates

Awesome work by @EddieGarmon on media-type handling introducing bespoke serialization (to/from wire format), also yielding significant performance gains for XML and JSON. For more details check out Eddies’ blog.

Exciting to see a flurry of activity on the Simple.Web repository including some awesome pull-requests. Managing these has however reminded me how hard it is the keep a clean commit history, and more so how important it is to clearly communicate your expectations to contributors.

Good

So what IMHO makes a good pull-request?

  • Changes have not been made against the master branch
  • Commits are made against a new branch used for pull-request
  • Branches are named appropriately (e.g. feature-X, fix-Y)
  • Only contains commits directly relating to the change
  • Concise description of changes and it’s motivation
  • Branch has been rebased often and not merged
  • Contains tests that confidently verifies functionality
  • Commits are squashed into as few commits as appropriate
  • Commit messages written in the imperative (e.g. “Implement” vs “Implemented”)
  • When PR merged new changes are made against a new branch

Example

#master> git fetch upstream/master              (alternatively you could ..
#master> git rebase upstream/master                just 'git pull --rebase')
#master> git checkout -b feature-owinsupport
#feature-owinsupport>

   ... 8 commits ...

#feature-owinsupport> git checkout master
#master> git fetch upstream/master
#master> git rebase upstream/master
#master> git checkout -b fix-issue290
#fix-issue290>

   ... 1 commit ...

#fix-issue290> git fetch upstream/master         (make sure nothing has ..
#fix-issue290> git rebase upstream/master           come in since)
#fix-issue290>

   ... Make pull-request on GitHub to master ...

#fix-issue290> git checkout feature-owinsupport
#feature-owinsupport>

   ... 2 more commits ....

#feature-owinsupport> git fetch upstream/master         (make sure nothing has ..
#feature-owinsupport> git rebase upstream/master           come in since)
#feature-owinsupport> git rebase -i HEAD~10             (squash my commits)

   ... pick the 1st commit, squash the rest ....
   ... edit the description when prompted to ONLY "Implement support for OWIN 1.0."

#feature-owinsupport> git push origin feature-owinsupport

   ... Make pull-request on GitHub to master ...

#feature-owinsupport> git checkout master

   ... Pull-request has since been merged ...

#master> git fetch upstream/master                      (yours changes will ..
#master> git rebase upstream/master                       now be in master)

    ... House-keeping (optional) ...

#master> git push origin :feature-owinsupport           (remove your remote branch)
#master> git branch -D feature-owinsupport              (if you are sure they're merged)

I have used fetch/rebase (or git pull --rebase) in the #master branch examples above. You could of course do a ‘merge’ with git pull on master given it should only ever have to fast-forward.

Of course there are instances where the apparently easy process above isn’t so easy, including the example of making further changes to a branch already pull-requested, or working with repository owners on an upstream branch. Please do ask “what should I do if … ?” questions in the comments below.

Support

We obviously want your pull-requests to be merged smoothly as possible, and want to help you know if once merged it’s not going to break anything, and so the Simple CI server (which anyone can log into as guest) automatically;

  • Builds your pull-request in isolation, on Mono and .NET, running all tests
  • Builds a merged version of your pull-request in isolation, on Mono and .NET, running all tests

This allows all of us to know if your PR behaves as expected, and will continue to do so once merged.

That’s all for now folks! :–)

OWIN middleware

Having already blogged about Simple.Web’s OWIN and Katana support I’d like to concentrate on the exciting bit – the middleware! First, one quick note of clarification;

OWIN is a standard interface specification born into the community by Benjamin van der Veen ~2010 to provide a common “glue” between server, and framework or module. Katana is Microsoft’s own implementation of an OWIN-compatible web server with accompanying set of modules.

OWIN is gaining traction in the .NET community with exciting alternatives on the horizon; however for the purposes of this post I’m going to stick with Katana and it’s middleware modules given my confidence around stability of the mono-compatible branch and nuget feed I maintain with Dale at @monkeysquareorg.

Middleware

When we talk about “middleware” we are really talking about modules that provide functionality to your request pipeline. Not only does this promote good separation and usability, it gives opportunity to request handling and pipeline composition.

The ability to interface a module, or a framework like Simple.Web, into the pipeline is supported by a delegate as defined in the OWIN interface specification.

1
2
3
using AppFunc = Func<
        IDictionary<string, object>, // Environment
        Task>; // Done

IDictionary<string, object> contains environment data relating to the request, outgoing response, and server state. Futhermore modules can add their own keys that can then be consumed by subsequent modules in the chain. The module must return a Task that eventually completes or throws an Exception.

Composition

Below is a fantastical example of how you could compose modules.

OWIN +
     |- Custom Tracer // Custom module for tracing
     |
     |- Error Handling // Renders intercepted exceptions (prettily)
     |
     |- Cross-Origin (CORS) // Handles cross-origin resource sharing
     |
     |- Authentication // Authenticates the incoming request
     |
     |- Static-file Serving // Serve any static files
     |
     `- Custom Routing
         |
         |- Simple.Web application // Serve pages with Simple.Web
         |
         |- NancyFX application // Serve pages with NancyFX
         |
         `- IIS pass-through** // Pass requests to IIS backend

And YES! I really just did mix Simple.Web, NancyFX, and IIS in the same pipeline ;–)

Example

For simplicity I’m leaving out the Authentication and IIS pass-through from our fantastical example above.

[Bootstrap] Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
namespace OwinMiddleware
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Threading.Tasks;

    using Microsoft.Owin.Cors;

    using Nancy;
    using Nancy.Owin;

    using Owin;

    using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;

    internal class Program
    {
        private static void Main(string[] args)
        {
            new Simple.Web.Hosting.Self.OwinSelfHost(
                builder =>
                {
                    builder.Use(typeof(CustomTracer));

                    builder.UseErrorPage();

                    builder.UseCors(CorsOptions.AllowAll);

                    builder.UseStaticFiles("/static", "static");

                    // Let's hack a custom routing module
                    builder.Use(
                        new Func<AppFunc, AppFunc>(
                            ignoreNextApp => (env =>
                                {
                                    var requestPath = (string)env["owin.RequestPath"];

                                    // Normally we'd just do `builder.UseSimpleWeb()`
                                    if (requestPath.StartsWith("/simple"))
                                        return Simple.Web.Application.Run(env);

                                    // Normally we'd just do `builder.UseNancy()`
                                    if (requestPath.StartsWith("/nancy"))
                                        return new NancyOwinHost(ignoreNextApp, new NancyOptions()).Invoke(env);

                                    var tcs = new TaskCompletionSource<object>();
                                    tcs.TrySetException(new Exception("Something went wrong!"));

                                    return tcs.Task;
                                })));
                }).Run();
        }
    }

    public class CustomTracer
    {
        private readonly AppFunc next;

        public CustomTracer(AppFunc next)
        {
            this.next = next;
        }

        public Task Invoke(IDictionary<string, object> env)
        {
            var requestPath = (string)env["owin.RequestPath"];

            Trace.WriteLine(
                string.Format("Received request for: {0}", requestPath));

            // We must pass-through onto the next module
            return this.next(env);
        }
    }
}
[Static Page] static\Stuff.html
1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>I am staticly served!</title>
</head>
<body>
    <h1>Welcome to an OWIN statically served page :-)</h1>
</body>
</html>
[Simple.Web] SimpleIndex.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace OwinMiddleware
{
    using Simple.Web;
    using Simple.Web.Behaviors;

    [UriTemplate("/simple")]
    public class SimpleIndex : IGet, IOutput<RawHtml>
    {
        public Status Get()
        {
            return 200;
        }

        public RawHtml Output { get { return "<h1>Hello from Simple.Web!</h1>"; } }
    }
}

Note The NancyFx integration shown here requires their next release (v0.20) which I believe is imminent. In the meantime use their bleeding edge feed.

[NancyFX] NancyIndex.cs
1
2
3
4
5
6
7
8
9
10
namespace OwinMiddleware
{
    public class SimpleModule : Nancy.NancyModule
    {
        public SimpleModule()
        {
            Get["/nancy"] = _ => "<h1>Hello from Nancy!</h1>";
        }
    }
}

Thanks!

This brings me to the end of this blog series on Simple.Web. I’m confident you too agree Mark Rendle has created something beautifully simple and elegantly powerful, whilst remaining unopinionated in its usage.

.. And that really is all for now folks! :–)

Hypermedia as the engine of application state (HATEOAS)

In the previous posts we have looked at how Simple.Web can help us to build web applications, and more specifically those that are ReST-focused. Without wanting to involve myself in the ‘What is ReST?’ debate it is without doubt there is a Holy Grail – and that is Level 3 of the Richardson Maturity Model.

Hyperlinks

In Resource Handling I stated “a resource is state and methods in your applications’ domain that you have chosen to expose”. The key element to HATEOAS is methods, which in the world of HTTP are usually represented as hyperlinks; it is this we will use to drive the client and in the process loosen the coupling of client to server.

Hyperlinks can be categorised as follows;

  • Root – Available without a predetermined path
  • Link – Indicates a path from the current state
  • Canonical – Denotes definitive location of the state

Let’s take a contrived example path;

Root +
     |
     `- Customers List *
                       |
                       `- Customer Detail

Each of the above steps is a resource with one or more URIs. For each customer listed in the returned state there is a method to retrieve customer detail. If that method is presented as an hyperlink, together with it’s relation to the resource, it can drive the client – act as the engine.

Example

Note In the examples below I’ve used custom vendor mime-types to demonstrate they are supported. I should state this is discouraged by the HTTP spec. If you are considering using custom mime-types in your application you might want to investigate using media parameters instead.

A simple example of HATEOAS could be an AngularJS SPA application consuming resources as follows;

  • Present root hyerlinks as application options to the user

  • Use hyperlink URI of rel=“customers” to display customer list

  • Use hyperlink URI of rel=“self” to display details

You will notice I am using the link “rel” (relation) to identify the hyperlink. This means that any custom “rel” is tightly coupled from client to server and thus changing it means breaking your API. Using a canonical rel of “self” where appropriate solves this and allows for usage with Put, Patch, or Delete.

Support

To help with the above scenarios Simple.Web offers the following class-level attributes;

  • [Root]

    • Rel – Relation to the resource state
    • Title – Display name/description
    • Type – Custom mime-type
  • [LinksFrom(Type, URI)]

    • Type – C# Type that this can be linked from
    • URI – URI, and optionally path segments, of the generated link
    • Rel – Relation to the resource state
    • Title – Display name/description
    • Type – Custom mime-type
  • [Canonical(Type, URI)]

    • Type – C# Type that this can be linked from
    • URI – URI (and optionally path segments) of the generated link

Example

[Bootstrap] Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
namespace HATEOAS
{
    using System;
    using System.Collections.Generic;

    using HATEOAS.Customer;

    public static class TestData
    {
        public static readonly IEnumerable<CustomerModel> Customers = new[]
                              {
                                  new CustomerModel
                                      {
                                          CustomerUid = new Guid("fa63d776-9dab-4755-a27a-b0690e3f7be3"),
                                          Forename = "James",
                                          Surname = "Bond",
                                          DateOfBirth = new DateTime(1920, 11, 11),
                                          Gender = "Male"
                                      },
                                  new CustomerModel
                                      {
                                          CustomerUid = new Guid("d5afee73-1229-46d9-8fc4-a6e7ecd8f014"),
                                          Forename = "Pussy",
                                          Surname = "Galore",
                                          DateOfBirth = new DateTime(1925, 08, 22),
                                          Gender = "Female"
                                      }
                              };
    }

    internal class Program
    {
        public static Type[] EnforceTypesFor = { typeof(Simple.Web.JsonNet.JsonMediaTypeHandler) };

        private static void Main(string[] args)
        {
            new Simple.Web.Hosting.Self.OwinSelfHost().Run();
        }
    }
}
[Root Links] GetEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespace HATEOAS
{
    using System.Collections.Generic;

    using Simple.Web;
    using Simple.Web.Behaviors;
    using Simple.Web.Links;

    [UriTemplate("/")]
    public class GetEndpoint : IGet, IOutput<IEnumerable<Link>>
    {
        public Status Get()
        {
            this.Output = LinkHelper.GetRootLinks();

            return 200;
        }

        public IEnumerable<Link> Output { get; private set; }
    }
}
[Customer List Model] CustomersModel.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
namespace HATEOAS.Customers
{
    using System;

    public class CustomersModel
    {
        public Guid CustomerUid { get; set; }

        public string Forename { get; set; }

        public string Surname { get; set; }
    }
}
[Customer List] GetEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
namespace HATEOAS.Customers
{
    using System.Collections.Generic;
    using System.Linq;

    using Simple.Web;
    using Simple.Web.Behaviors;
    using Simple.Web.Links;

    [UriTemplate("/customers")]
    [Root(Rel = "customers", Title = "Customer List", Type = "application/vnd.polygotadventures.list.customer")]
    public class GetEndpoint : IGet, IOutput<IEnumerable<CustomersModel>>
    {
        public Status Get()
        {
            this.Output = TestData.Customers.Select(c => new CustomersModel
                                                             {
                                                                 CustomerUid = c.CustomerUid,
                                                                 Forename = c.Forename,
                                                                 Surname = c.Surname
                                                             });

            return 200;
        }

        public IEnumerable<CustomersModel> Output { get; private set; }
    }
}
[Customer Detail Model] CustomerModel.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace HATEOAS.Customer
{
    using System;

    public class CustomerModel
    {
        public Guid CustomerUid { get; set; }

        public string Forename { get; set; }

        public string Surname { get; set; }

        public DateTime DateOfBirth { get; set; }

        public string Gender { get; set; }
    }
}
[Customer Detail] GetEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
namespace HATEOAS.Customer
{
    using System;
    using System.Linq;
    using Simple.Web;
    using Simple.Web.Behaviors;
    using Simple.Web.Links;

    [UriTemplate("/customer/{CustomerUid}")]
    [Canonical(typeof(Customers.CustomersModel), Title = "Customer Detail", Type = "application/vnd.polygotadventures.customer")]
    public class GetEndpoint : IGet, IOutput<CustomerModel>
    {
        public Status Get()
        {
            this.Output = TestData.Customers
                .Select(c => new CustomerModel
                    {
                        CustomerUid = c.CustomerUid,
                        Forename = c.Forename,
                        Surname = c.Surname,
                        DateOfBirth = c.DateOfBirth,
                        Gender = c.Gender
                    })
                .FirstOrDefault(c => c.CustomerUid == this.CustomerUid);

            return 200;
        }

        public Guid CustomerUid { get; set; }

        public CustomerModel Output { get; private set; }
    }
}

Canonical vs LinksFrom

I have used [Canonical] above which has a default rel of “self”. You can also use [LinksFrom] should this better meet intent, such as supporting transitional commands via POST operations, for example;

[Customer Termination] PostEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace HATEOAS.Customer
{
    using System;
    using Simple.Web;
    using Simple.Web.Links;

    [UriTemplate("/customer/{CustomerUid}/terminate")]
    [LinksFrom(typeof(Customers.CustomersModel), Rel = "customer.terminate")]
    public class PostEndpoint : IPost
    {
        public Status Post()
        {
           ...
        }
    }
}

Note Automatic link serialization is currently only supported in Simple.Web.JsonNet and Simple.Web.Xml, and not Simple.Web.JsonFx.

For more detail check out the Simple.Web API documentation.

That’s all for now folks! :–)

Content negotiation

I’ve mentioned one of the key ingredients of a ReST API is “representation”. It is likely the representation sent back to the client is an abstract of the actual resource exposed. Furthermore the content of the representation will need to be encoded and in a format the client can consume, it will need to be negotiated.

Negotiate

Fortunately HTTP/1.1 provides us with headers to enable the negotiation between client and server.

Request
1
2
3
GET /customers HTTP/1.1
Accept: text/html
Accept-Charset: utf-8

When receiving a request Simple.Web will invoke the appropriate media-type handler for that requested.

Handle

Simple.Web supports content negotiation using available media-type handlers. The following media-type handlers are available as NuGet packages;

Media type handlers are discovered by identifying class-level attribute MediaTypes which also denote it’s supported MIME type(s). You are therefore able to add your own handlers with ease.

Example media-type handler
1
2
3
4
[MediaTypes(MediaType.Html, MediaType.XHtml)]
public class RazorHtmlMediaTypeHandler : IMediaTypeHandler
{
}

Respond

Response
1
2
3
4
5
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<html>
  ...
</html>

If no matching handler is available Simple.Web will respond 415 Unsupported media type.

Razor

Simple.Web.Razor allows association of a view with a model, a handler, or both. Properties of any associated model or handler are exposed to the view, avoiding the need for an ambiguous view-bag. Should you wish to share data between layouts and sections without polluting your model or handler then ViewBag is available.

[GET] GetEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
namespace ContentNegotiation.Customers
{
  using System;

  using Simple.Web;
  using Simple.Web.Behaviors;

  [UriTemplate("/customers")]
  public class GetEndpoint : IGet, IOutput<IEnumerable<CustomersModel>>
  {
    private ICustomersQuery customerQuery;

    public GetEndpoint(ICustomersQuery customersQuery)
    {
      this.queryCustomers = queryCustomers;
    }

    public string Title { get; set; }

    public IEnumerable<CustomersModel> Customers { get; set; }

    public Status Get()
    {
      this.Title = "Customer list as of " + DateTime.Now.ToLongDateString();
      this.Customers = this.customersQuery.Execute();

      return 200;
    }
  }
}
Customers.cshtml (model)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@model IEnumerable<ContentNegotiation.Customers.CustomersModel>

<!DOCTYPE html>
<html>
  <body>
    <table>
      <thead>
        <th>
          <td>Forename</td>
          <td>Surname</td>
        </th>
      </thead>
      <tbody>
        @foreach (var customer in @Model) {
          <tr>
            <td>@customer.Forename</td>
            <td>@customer.Surname</td>
          </tr>
        }
      </tobdy>
    </table>
  </body>
</html>
Customers.cshtml (handler)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@handler ContentNegotiation.Customers.GetEndpoint

<!DOCTYPE html>
<html>
  <body>
    <h1>Welcome to @Handler.Title</h1>
    <table>
      <thead>
        <th>
          <td>Forename</td>
          <td>Surname</td>
        </th>
      </thead>
      <tbody>
        @foreach (var customer in @Handler.Customers) {
        <tr>
          <td>@customer.Forename</td>
          <td>@customer.Surname</td>
        </tr>
        }
      </tobdy>
    </table>
  </body>
</html>
Customers.cshtml (handler & model)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@handler ContentNegotiation.Customer.GetEndpoint
@model IEnumerable<ContentNegotiation.Customers.CustomersModel>

<!DOCTYPE html>
<html>
  <body>
    <h1>Welcome to @Handler.Title</h1>
    <table>
      <thead>
        <th>
          <td>Forename</td>
          <td>Surname</td>
        </th>
      </thead>
      <tbody>
        @foreach (var customer in @Model) {
        <tr>
          <td>@customer.Forename</td>
          <td>@customer.Surname</td>
        </tr>
        }
      </tobdy>
    </table>
  </body>
</html>

Discovery

I mentioned above that media-type handlers were “discovered” at runtime; to be exact they are imported from the AppDomain. To ensure the Type’s of media-type handlers in referenced assemblies are included I recommend a code reference that CodeAnalysis won’t think better for you.

You can do this using an IoC container (of which Simple.Web supports Autofac, Ninject, and StructureMap) to scan the appropriate assemblies, alternatively reference the assemblies at compile-time. For example;

Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ContentNegotiation
{
  using System;

  internal class MainClass
  {
    public static Type[] EnforceReferencesFor = {
      typeof(Simple.Web.JsonNet.JsonMediaTypeHandler),
      typeof(Simple.Web.Xml.XmlMediaTypeHandler)
    };

    private static void Main (string[] args)
    {
      new Simple.Web.Hosting.Self.OwinSelfHost().Run();
    }
  }
}

This also has the added benefit that if you bootstrap the self-hosting from another assembly (e.g. acceptance tests) no direct references to Simple.Web or it’s dependencies will be required.

Sidenote If you know a better way round this nasty smell I’d love to hear it!

That’s all for now folks! :–)

Resource handling

Before we kick-off and talk about resource handling in Simple.Web let’s be clear what a “resource” is.

“A resource can be essentially any coherent and meaningful concept that may be addressed. A representation of a resource is typically a document that captures the current or intended state of a resource.”Wikipedia

A resource is not a URI, which is just a locator for a resource. Neither is a resource a representation, such as JSON, XML or HTML. And a resource is not the verb used to interact with your application, which are HTTP definitions. A resource is state and methods in your applications’ domain that you have chosen to expose.

In summary; you design the resource and Simple.Web will handle the rest.

Identifying a resource

Simple.Web uses the class-level attribute UriTemplate to locate and route an incoming request. You are able to apply the attribute any number of times, and you can optionally inherit from a base class.

Customers.cshttp://localhost:3333/customers
1
2
3
4
5
6
7
8
9
10
11
namespace ResourceHandling
{
  using System;

  using Simple.Web;

  [UriTemplate("/customers", inheritFromBaseClass: false)]
  public class Customers
  {
  }
}

Querying

What happen’s if we need to query our resource? We have two options;

  • Path segments
  • Querystring
Path Segmentshttp://localhost:3333/customer/e430ed07-6c4c-4cb8-ba8b-65523797530a
1
2
3
4
5
6
7
8
9
10
11
12
namespace ResourceHandling
{
  using System;

  using Simple.Web;

  [UriTemplate("/customer/{CustomerUid}")]
  public class Customer
  {
      public Guid CustomerUid { get; set; }
  }
}
QueryStringhttp://localhost:3333/customers?forename=john&surname=brown
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace ResourceHandling
{
  using System;

  using Simple.Web;

  [UriTemplate("/customers")]
  public class Customers
  {
      public string Forename { get; set; }

      public string Surname { get; set; }
  }
}

Methods

We now have a means for Simple.Web to route an incoming request to the correct resource, but we need to define the appropriate HTTP method for the operation we are supporting on this resource.

Sidenote: Using the correct HTTP method is a core principal of a ReST API, it should reflect the nature of the operation against the resource in conjunction with it’s Uniform Resource Identifier (URI).

Simple.Web supports the following HTTP definitions;

  • Delete
  • Get
  • Head
  • Patch
  • Post
  • Put

Note: Simple.Web favours composition over inheritence as a core principal of it’s design. To infer usage, and take advantage of strong-typing, Simple.Web provides a series of interfaces that are used to automagically wire-up your application at runtime. This also has the advantage of not polluting your unit tests with inherited behaviour, thus enforcing the unit test boundary.

I am going to use IGet to retrieve a customer and IPost to create a new customer. I am also organising my classes into namespaces that represent the ‘customer’ resource.

[GET] GetEndpoint.cshttp://localhost:3333/customer/e430ed07-6c4c-4cb8-ba8b-65523797530a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace ResourceHandling.Customer
{
  using System;

  using Simple.Web;

  [UriTemplate("/customer/{CustomerUid}")]
  public class GetEndpoint : IGet
  {
    public Guid CustomerUid { get; set; }

    public Status Get()
    {
      // Locate the customer by this.CustomerUid
      // and return the appropriate status code
      throw new NotImplementedException();
    }
  }
}
[POST] PostEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ResourceHandling.Customer
{
  using System;

  using Simple.Web;

  [UriTemplate("/customer")]
  public class PostEndpoint : IPost
  {
    public Status Post()
    {
      // Need to create a customer and return appropriate
      // status code, although I don't yet have the data!
      throw new NotImplementedException();
    }
  }
}

Sidenote: Async is fully supported throughout Simple.Web, simply append “Async” to the method interface, for example IGetAsync, IPostAsync, etc.

State

You will realise we are building the various elements that sit around our resource but that we are missing the state that will be (a) represented back to the client, and (b) received into our application. As before Simple.Web uses interfaces to infer usage, this time “Behaviors” IOutput<> and IInput<>.

CustomerModel.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
namespace ResourceHandling.Customer
{
  using System;

  public class CustomerModel
  {
    public Guid CustomerUid { get; set; }

    public string Forename { get; set; }

    public string Surname { get; set; }
  }
}
[GET] GetEndpoint.cshttp://localhost:3333/customer/e430ed07-6c4c-4cb8-ba8b-65523797530a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
namespace ResourceHandling.Customer
{
  using System;

  using Simple.Web;
  using Simple.Web.Behaviors;

  [UriTemplate("/customer/{CustomerUid}")]
  public class GetEndpoint : IGet, IOutput<CustomerModel>
  {
    private ICustomerQuery customerQuery;

    public GetEndpoint(ICustomerQuery customerQuery)
    {
      this.customerQuery = customerQuery;
    }

    public Guid CustomerUid { get; set; }

    public CustomerModel Customer { get; set; }

    public Status Get()
    {
      // Locate the customer by this.CustomerUid
      this.Customer = this.customerQuery.Execute(this.CustomerUid);

      // We still need to return a status code
      throw new NotImplementedException();
    }
  }
}
[POST] PostEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace ResourceHandling.Customer
{
  using System;

  using Simple.Web;
  using Simple.Web.Behaviors;

  [UriTemplate("/customer")]
  public class PostEndpoint : IPost, IInput<CustomerModel>
  {
    private ICustomerCommand customerCommand;

    public PostEndpoint(ICustomerCommand customerCommand)
    {
      this.customerCommand = customerCommand;
    }

    public CustomerModel Customer { get; set; }

    public Status Post()
    {
      // Need to create this.CustomerUid
      this.customerCommand.Execute(this.Customer);

      // We still need to return an **appropriate** status code
      throw new NotImplementedException();
    }
  }
}

Status

We need to send back an HTTP status code. Simple.Web provides an implicit cast from Status to Int32 so we can simply return the status code (e.g. 200 = OK), alternatively use the static helper fields.

[GET] GetEndpoint.cshttp://localhost:3333/customer/e430ed07-6c4c-4cb8-ba8b-65523797530a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
namespace ResourceHandling.Customer
{
  using System;

  using Simple.Web;
  using Simple.Web.Behaviors;

  [UriTemplate("/customer/{CustomerUid}")]
  public class GetEndpoint : IGet, IOutput<CustomerModel>
  {
    private ICustomerQuery customerQuery;

    public GetEndpoint(ICustomerQuery customerQuery)
    {
      this.customerQuery = customerQuery;
    }

    public Guid CustomerUid { get; set; }

    public CustomerModel Customer { get; set; }

    public Status Get()
    {
      // Locate the customer by this.CustomerUid
      this.Customer = this.customerQuery.Execute(this.CustomerUid);

      // Return 200 OK using Simple.Web's status helper
      return Status.OK;
    }
  }
}
[POST] PostEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace ResourceHandling.Customer
{
  using System;

  using Simple.Web;
  using Simple.Web.Behaviors;

  [UriTemplate("/customer")]
  public class PostEndpoint : IPost, IInput<CustomerModel>
  {
    private ICustomerCommand customerCommand;

    public PostEndpoint(ICustomerCommand customerCommand)
    {
      this.customerCommand = customerCommand;
    }

    public CustomerModel Customer { get; set; }

    public Status Post()
    {
      // Need to create or update this.CustomerUid
      this.customerCommand.Execute(this.Customer);

      // We should return 201 (Created) and we'll lose the status helper ;-)
      return 201;
    }
  }
}

Representation

I haven’t talked about how your resource state is represented back to the client (the “Re” in ReST); this will be the subject of the next blog post Content Negotiation.

That’s all for now folks! :–)

Getting started

Simple.Web is intended to be exactly that – Simple! Let’s see how easy it is to get started.

1. Create a new Console Project

Let’s create a console project to bootstrap our example. I’m using MonoDevelop here to show Simple.Web is just as fantastic on Mono as .NET. If you also want to use MonoDevelop then I’d recommend installing the NuGet add-in.

2. Install NuGet packages

I’m going to pick the new self-hosting package, it will bring in all the dependencies I need.

Note: As Katana v2 is only available as a pre-release package Simple.Web.Hosting.Self depends on a custom NuGet source; furthermore a custom RTM build of ‘dev’ branch ensuring mono-compatibility. To use Simple.Web.Hosting.Self add https://www.myget.org/F/katana-mono to your available package sources.

3. Bootstrap

Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
namespace GettingStarted
{
  using System;

  internal class MainClass
  {
    private static void Main (string[] args)
    {
      new Simple.Web.Hosting.Self.OwinSelfHost().Run();
    }
  }
}

4. Create a resource

For the sake of simplicity I have chosen not to return a model (and thus use content negotiation) and instead inherit Simple.Web “OutputBehaviour” IOutput<RawHtml> that will simple render the contents of the string into the response stream; together with a 200 OK HTTP response code we’re done!

GetIndex.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace GettingStarted
{
  using System;

  using Simple.Web;
  using Simple.Web.Behaviors;

  [UriTemplate("/")]
  public class GetIndex : IGet, IOutput<RawHtml>
  {
    public Status Get ()
    {
      this.Output = "<h1>Hello from Simple.Web!</h1>";

      return 200;
    }

    public RawHtml Output { get; set; }
  }
}

5. Run & Browse

Let’s hit F5/CMD-Enter to run and browse to the default address of http://localhost:3333.

Too Simple? Bit disappointed? Sorry about that ;–)

In the 0.9 release of Simple.Web we announced improved support for running Simple.Web with an OWIN-compatible web-server, particular focus on compatibility with the upcoming release of Katana v2. We also introduced a new self-hosting package aimed at reducing boiler-plate code associated with bootstrapping.

ON A SIDE NOTE

OWIN is a standard interface specification born into the community by Benjamin van der Veen ~2010 to provide a common “glue” between server, and framework or module. Katana is Microsoft’s own implementation of an OWIN-compatible web server with accompanying set of modules.

OWIN Compatibility

Simple.Web was built around OWIN and it’s delegate method signature, but it relied on it’s sister projects Fix and Flux for assurance. With the emergence of viable server alternatives (such as Katana) we found areas for improvement, mainly where interpretation of the specification could result in an incompatibility.

Not strictly part of the specification the community has grown towards a set of common conventions:

Builder helpers

It’s common for extension methods to be provided to reduce boilerplate code and complexity. In the case of Simple.Web we have introduced UseSimpleWeb().

Previously
1
2
3
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;

app.Use(new Func<AppFunc, AppFunc>(ignoreNextApp => (AppFunc)Simple.Web.Application.Run);
Now
1
app.UseSimpleWeb();

Startup.Configuration

OWIN-compatible servers often scan for a Startup class with a Configuration method as an application entry point. To reduce boilerplate code we have introduced Simple.Web.OwinSupport.OwinStartupBase.

Minimal
1
public class Startup : OwinStartupBase { }
AppBuilder
1
2
3
4
5
6
7
8
public class Startup : OwinStartupBase
{
    public Startup() : base(builder => {
      builder.UseErrorPage();
      builder.UseWelcomePage("/owin");
      builder.UseSimpleWeb();
    });
}

Katana Compatibility

Katana supports different approaches for hosting your application. We have built a set of sample projects to illustrate SimpleWeb’s compatibility. Find below some example code snippets.

Self-Hosting

To reduce boiler-plate code when bootstraping your server from a console project we have introduced a new self-hosting package that uses Katana v2.

Minimal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace OwinConsoleHost
{
    using System;

    using Simple.Web.Hosting.Self;

    internal class Program
    {
        private static void Main(string[] args)
        {
            new OwinSelfHost().Run();
        }
    }
}
Options
1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace OwinConsoleHost
{
    using System;

    using Simple.Web.Hosting.Self;

    internal class Program
    {
        private static void Main(string[] args)
        {
            new OwinSelfHost().Run("localhost", port: 3333, ssl: false);
        }
    }
}
AppBuilder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace OwinConsoleHost
{
    using System;

    using Simple.Web.Hosting.Self;

    internal class Program
    {
        private static void Main(string[] args)
        {
          new OwinSelfHost(
                builder =>
                    {
                        builder.UseErrorPage();
                        builder.UseSimpleWeb();
                    })
                    .Run();
        }
    }
}
Custom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
namespace OwinConsoleHost
{
    using System;

    using Simple.Web.Hosting.Self;

    internal class Program
    {
        private static void Main(string[] args)
        {
            var host = new OwinSelfHost();

            using (host.Start(hostname: "localhost", port: 3333, ssl: false))
            {
                Console.WriteLine("Listening at http://localhost:3333. Press CTRL-C to stop.");

                Console.CancelKeyPress += (sender, eventArgs) => Console.WriteLine("Stopping.");

                while (true)
                {
                }
            }
        }
    }
}

Library (using OwinHost.exe)

You can contain your application within a library project (assembly) and use Katanas’ OwinHost.exe to bootstrap it. The easiest way to do this is by adding NuGet package OwinHost-mono to your solution.

Startup.cs
1
2
3
4
5
6
7
8
9
10
[assembly: Microsoft.Owin.OwinStartup(typeof(OwinWebHost.Startup))]

namespace OwinWebHost
{
    using Simple.Web.OwinSupport;

    public class Startup : OwinStartupBase
    {
    }
}

To enable F5 run from Visual Studio you will need to add a StartAction to the bottom of your csproj file:

.csproj
1
2
3
4
  <PropertyGroup>
    <StartAction>Program</StartAction>
    <StartProgram>$(ProjectDir)../packages/OwinHost-mono.2.0.0-rtw-20815-004/tools/OwinHost.exe</StartProgram>
  </PropertyGroup>

Note You need to make sure your output path does not contain the project configuration (e.g. “debug”) as OwinHost.exe doesn’t like it. I have raised this with the Katana team but without resolution.

Web Application

Support for Web Application project types comes via web.config and Microsoft.Owin.OwinStartup assembly attribute. Your web application will run on top of SystemWeb, including interactive debugging.

Startup.cs
1
2
3
4
5
6
7
8
9
10
[assembly: Microsoft.Owin.OwinStartup(typeof(OwinWebHost.Startup))]

namespace OwinWebHost
{
    using Simple.Web.OwinSupport;

    public class Startup : OwinStartupBase
    {
    }
}

web.config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?xml version="1.0"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <appSettings>
    <add key="owin:Configuration" value="KatanaWebApplication2.Startup.Configuration, KatanaWebApplication2" />
    <add key="owin:SetCurrentDirectory" value="true" />
    <add key="webpages:Enabled" value="false" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpHandlers>
      <clear />
      <add verb="*" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb" />
    </httpHandlers>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
      <remove name="RewriteModule" />
      <remove name="OutputCache" />
      <remove name="Session" />
      <remove name="WindowsAuthentication" />
      <remove name="FormsAuthentication" />
      <remove name="DefaultAuthentication" />
      <remove name="RoleManager" />
      <remove name="UrlAuthorization" />
      <remove name="FileAuthorization" />
      <remove name="AnonymousIdentification" />
      <remove name="Profile" />
      <remove name="UrlMappingsModule" />
      <remove name="ServiceModel-4.0" />
      <remove name="UrlRoutingModule-4.0" />
      <remove name="ScriptModule-4.0" />
    </modules>
    <handlers>
      <clear />
      <add name="Owin" verb="*" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb" />
    </handlers>
    <security>
      <requestFiltering allowDoubleEscaping="true" allowHighBitCharacters="true">
        <fileExtensions allowUnlisted="true">
          <clear />
        </fileExtensions>
        <hiddenSegments>
          <clear />
        </hiddenSegments>
        <verbs allowUnlisted="true" />
      </requestFiltering>
    </security>
  </system.webServer>
</configuration>

That’s all for now folks! :–)