In the .NET space the overwhelming majority of web projects are built with ASP.NET in one form or another.
But there are alternatives. Alternatives that offer other approaches, and supports other ways of thinking.Alternatives that are open source. Altenratives that run on Mono.
Maybe one of those alternatives is the better fit for your next project - except if you don't know about them you will never know. In this code heavy talk I'll show the same sample application in the four Open Source .NET web frameworks FubuMVC, OpenRasta, Nancy and Frank.
You will not become an expert at anything by attending this talk - but you may discover just the right web framework for your next project.
1. Four Other .NET Web Frameworks in Less Than an Hour
Christian Horsdal
@chr_horsdal
http://horsdal.blogspot.com/
2. Who Am I?
Lead Software Architect @ Mjølner Informatics
Husband and Father
Some who enjoys
Clean code
TDD‟ing
When ‟GF wins
Simplicity
Whisky
3
3. Why?
There are alternatives to ASP.NET
Know them!
Style matters
Tradeoffs, tradeoffs, tradeoffs
Conventions <-> explicitness
DRY <-> separation of concerns
Abstract <-> concrete
4
4. Why?
Run anywhere
IoC/DI to the bone
Embrace HTTP
OSS and community driven
5
5. What will you learn?
A taste of some alternatives
FubuMVC
OpenRasta
Nancy
Frank
6
7. FubuMVC – At a glance
One Model In One Model Out
Aka OMIOMO
Aka Russian Doll
Convention over Configuration
Really cool built-in diagnostics
Everything is POCOs
8
9. FubuMVC – ShortUrl – Serving the FORM
public class HomeController
{
public HomeController(UrlStore urlStore)
{
this.urlStore = urlStore;
}
@model ShortUrlInFubuMvc.HomeViewModel
public HomeViewModel get_home() @{
{ Layout = null;
return new HomeViewModel(); }
}
<!DOCTYPE html>
… <html>
} <body>
<form method="post" action="home">
public class HomeViewModel { } <label>Url: </label>
<input type="text" name="url"/>
<input type="submit"
value="shorten"/>
</form>
10 </body>
10. FubuMVC – ShortUrl – POST the FORM
public UrlShorteningViewModel post_home(UrlShorteningModel input)
{
var shortenedUrl = input.Url.GetHashCode().ToString();
urlStore.SaveUrl(input.Url, shortenedUrl);
return new UrlShorteningViewModel
{
Host = "localhost:51862",
HashCode = shortenedUrl
};
}
public class UrlShorteningModel
{
public string Url { get; set; }
}
public class UrlShorteningViewModel
{
public string Host { get; set; }
11 public string HashCode { get; set; }
11. FubuMVC – ShortUrl - Redirecting
public FubuContinuation get_Url(ShortenedUrlModel input)
{
var longUrl = urlStore.GetUrlFor(input.Url) ?? "/notfound/";
return FubuContinuation.RedirectTo(longUrl);
}
public class ShortenedUrlModel
{
public string Url { get; set; }
}
12
12. OpenRasta– At a glance
Three things:
Resources
Handlers
Codecs
Automatic conneg
Everything is POCOs
13
13. OpenRasta – Shorturl Overview
Resource:
“/”
“/{shortenedUrl}”
Home
GET “/” POST “/” GET “/42”
Handler
HomeHandler
“Codecs” Home resource
WebForms viewengine HomeHandler
Form data
14
14. OpenRasta– ShortUrl – Serving the FORM
public class HomeHandler
{
public HomeHandler(IRequest request, UrlStore urlStore)
{
public class Configuration : IConfigurationSource
this.request = request;
{
this.urlStore = urlStore;
public void Configure()
}
{
using (OpenRastaConfiguration.Manual)
public Home Get()
{
{
ResourceSpace.Has
return new Home();
.ResourcesOfType<Home>()
}
.AtUri("/").And.AtUri("/home")
…
.And.AtUri("/{shortenedUrl}")
}
.HandledBy<HomeHandler>()
.RenderedByAspx("~/Views/Home.aspx");
public class Home
{
public string LongUrl { get; set; }
ResourceSpace.Uses
public string ShortUrl { get; set; }
.Resolver.AddDependencyInstance<UrlStore>
public string Host { get; set; }
}
}
15
}
15. OpenRasta– ShortUrl – POST the FORM
public Home Post(Home input)
{
input.ShortUrl = input.LongUrl.GetHashCode().ToString();
input.Host = request.Uri.Host + ":" + request.Uri.Port;
urlStore.SaveUrl(input.LongUrl, input.ShortUrl);
return input;
}
16
16. OpenRasta– ShortUrl - Redirecting
public OperationResult Get(string shortenedUrl)
{
var longUrl = urlStore.GetUrlFor(shortenedUrl);
if (longUrl != null)
return new OperationResult.SeeOther
{
RedirectLocation = new Uri(longUrl)
};
else
return new OperationResult.NotFound();
}
17
17. Nancy– At a glance
Lightweight, low ceremony
Just works
But easily swappable
DSLs
Built in diagnostics
Testability is first class
18
18. Nancy – Shorturl Overview
Modules
ShortUrlModule
Routes
Get[“/”]
Post[“/”]
Get[“/{shortenedUrl}”] HTTP
Routes
Handler
Response
request function
A lambda for each
19
19. Nancy– ShortUrl – Serving the FORM
public class ShortUrlModule : NancyModule
{
public ShortUrlModule(UrlStore urlStore)
{
Get["/"] = _ => View["index.html"];
…
}
…
} <!DOCTYPE html>
<html>
<body>
<form method="post" action="home">
<label>Url: </label>
<input type="text" name="url"/>
<input type="submit"
value="shorten"/>
</form>
</body>
</html>
20
20. Nancy– ShortUrl – POST the FORM
public class ShortUrlModule : NancyModule
{
public ShortUrlModule(UrlStore urlStore)
{
Get["/"] = _ => View["index.html"];
Post["/"] = _ => ShortenUrl(urlStore);
…
}
private Response ShortenUrl(UrlStore urlStore)
{
string longUrl = Request.Form.url;
var shortUrl = longUrl.GetHashCode().ToString();
urlStore.SaveUrl(longUrl, shortUrl);
return View["shortened_url", new { Request.Headers.Host, ShortUrl = shortUrl }];
}
…
}
21
22. Frank– At a glance
F#
Bare bones approach to HTTP services
Leverage WebAPI
Compositional
23
23. Frank– ShortUrl – Serving the FORM
let urlShortenerView = @"<!doctype html><meta charset=utf-8>
<title>Hello</title>
<p>Hello, world!
<form action=""/"" method=""post"" enctype=""multipart/form-data"">
<input type=""input"" name=""longUrl"" value=""long url"">
<input type=""submit"">"
let urlShortenerForm request = async {
return respond HttpStatusCode.OK
(new StringContent(urlShortenerView,
System.Text.Encoding.UTF8, "text/html"))
<| ``Content-Type`` "text/html"
}
24
24. Frank– ShortUrl – POST the FORM
let createShortUrl (request: HttpRequestMessage) = async {
let! value = request.Content.AsyncReadAsMultipart()
let longUrl = value.FirstDispositionNameOrDefault("longUrl")
.ReadAsStringAsync().Result;
let urlKey = longUrl.GetHashCode().ToString()
urlStore.Add(urlKey, longUrl)
let shortUrl = baseUri + "/" + longUrl.GetHashCode().ToString()
return respond HttpStatusCode.OK
(new StringContent(shortUrlCreatedView(shortUrl),
System.Text.Encoding.UTF8, "text/html"))
<| ``Content-Type`` "text/html"
}
25
25. Frank– ShortUrl - Redirecting
let getShortUrl (request: HttpRequestMessage) = async {
let urlKey = request
.RequestUri
.Segments.[request.RequestUri.Segments.Length - 1]
let longUrl = urlStore.[urlKey]
return respond HttpStatusCode.Redirect
(new EmptyContent())
<| Location (new Uri(longUrl))
}
let rootResource = routeResource "/" [ get urlShortenerForm <|> post createShortUrl ]
let redirectReource = routeResource "/{shortUrl}" [ get getShortUrl ]
let app = merge [ rootResource; redirectReource ]
let config = new HttpSelfHostConfiguration(baseUri)
config.Register app
26
26. Why, again?
There are alternatives to ASP.NET
Know them!
Style matters
Tradeoffs, tradeoffs, tradeoffs
27
27. What might you have learned?
A taste of some altenatives
FubuMVC
OMIOMU
OpenRasta
Resources, Handlers, Codecs
Nancy
DSL
Frank
F#
28