Date post: | 24-May-2015 |
Category: |
Technology |
Upload: | resources-global-professionals |
View: | 3,838 times |
Download: | 0 times |
Thanks to our AWESOME sponsors!
A Minimalist’s Attempt at Building a Distributed Application
David Hoerster
Simplist’sControl Freak’s
About Me
C# MVP (Since April 2011)
Sr. Director of Web Solutions at RGP
Conference Director for Pittsburgh TechFest
Co-Founder of BrainCredits (braincredits.com)
Past President of Pittsburgh .NET Users Group and organizer of recent Pittsburgh Code Camps and other Tech Events
Twitter - @DavidHoerster
Blog – http://geekswithblogs.net/DavidHoerster
Email – [email protected]
The Minimalist’s Goals
Easy setup and install
Able to deploy almost anywhere (low dependency)
Contained intent Anti-Scavenger Hunt Development
Convention favored over heavy configuration But I have control if needed
No significant performance hit Improvement preferred!
PhD not required
What Do These Have in Common?
Run from a consoleFull featured web app aspectsNo need for IIS or installed web serverJenkins/Solr are JVM; Raven is .NET
My Project
Have a demo app for using Solr in .NET
Works great, but dependent on IIS
Want to make it more like Solr Install anywhere
Easy to set up and get running
Very configurable
Multiple instances running
IIS(WP)
Solr
SQL
ClientNancy(.EXE)
Is IIS Evil?
No!
But…
Not everything
requires a hammer
Basic ASP.NET MVC Operation
public class QuoteController : Controller {
private readonly QuoteRepository _repo;
public ActionResult Index() { var quotes = _repo.GetAll(); return View(quotes);}
}
Controller derives from Controller
Specific return types
Helpers that do help…But what’s the route??(Have to look in global.asax.)
Web API improves on this with declared returntypes (e.g. List<T>) and Web API 2 will haveannotated routes (which takes a lot from Nancy).
What About Bottle (Python)?
@bottle.route('/quote')def get_all_quotes():
l = solr.query(‘*:*’)
# do some Python projection here to get ll
return bottle.template(‘quotes_template', dict(myquotes=ll))
Here’s my route
Intuitive method name
Tells I’m returning a template, what the template is, and what model(s)
Simplicity over Power
ASP.NET MVC (and Web API) has a lot of power
With power comes great responsibility
Conform
Sometimes lose intuitiveness of code Routes defined elsewhere
Changing in Web API
Other configuration throughout app
Get Quotes in Nancy
public class QuoteModule : NancyModule { private readonly IQuoteRepository _repo; public QuoteModule(IQuoteRepository repo) { _repo = repo;
Get["/quote"] = _ => { var quotes = _repo.GetAll();
return View["Index.cshtml", quotes]; };
}}
Here’s my route and method
Returning dictionary with template and model
Nancy Differences with ASP.NET MVC
Simple design to create web methods
No method names – dictionary of routes and funcs
Route configuration right in with method definitions Good or bad? Hmmm….
Bare bones distributed service environment Low overhead / low ceremony service definitions
Not heavy on configuration
However, full async/await support not there…yet
Modules and Routing
Modules are like Controllers
Contain routes and route rules
Essentially all defined in Module constructor
Watch that business logic doesn’t creep in Modules could get unwieldy
public class QuoteModule : NancyModule { private readonly QuoteRepository _repo; public QuoteModule() { _repo = new QuoteRepository();
Get["/quote"] = _ => { var quotes = _repo.GetAll();
return View["Index.cshtml", quotes]; };
}}
Modules and Routing
What happens here? http://localhost/quote/100 (GET)
http://localhost/quote/100 (DELETE)
In MVC, what’s my action?Needs to be part of the route, unless default
http://localhost/quote/100 (GET)http://localhost/quote/delete/100 (DELETE)
Nancy has dictionaries for actions
Get[“/quote/{id}”] = args => { … }Delete [“/quote/{id}”] = args => { … }
Modules and Routing
Nancy’s routing is based on Method
Pattern
Action
Condition (routes can have conditions)
Get[“/quote/{id}”] = args => { … }Delete [“/quote/{id}”] = args => { … }
/quote/getall/quote/{id?} (optional capture segment)/quote/(?<id>[a..zA..Z]*) (regex)
Post[“/quote”, x => x.id > 0] = args => {…}Post[“/quote”, x => x.id < 0] = args => {…}
Finding Modules
Nancy scans app for NancyModules
Loads them
No need to define routes in config or global
Nancy favors convention over configuration generally
Changing Behavior
Nancy is a pipeline
Series of events for each request Want forms authentication?
Add it to the pipeline
Want custom error page
Add it to the pipeline
Steps can be added at application, module and route level
Allows fine grain control for distributed app dev
Auth ErrorHandler
CustomBeforeActions
Request
Module
Changing Behavior
Creating a custom bootstrapper allows for custom behavior at app level
Before and After Hooks for application and module Logging and events
Page Handlers for page type specific behavior Handle custom 404’s
Static files If outside of /Content, need to configure in Bootstrapper
pipelines.BeforeRequest += (ctx) => { Logger.Log("starting…");
Command.Enqueue(new Command()); return null; };
pipelines.AfterRequest += (ctx) => { Logger.Log("ending request"); };
Authentication
By default, none
Forms Authentication module is available Get it from NuGet
Somewhat bare bones, but gets the job done
Configure through Bootstrapper
var formsAuthCfg =new FormsAuthenticationConfiguration()
{ RedirectUrl = "~/login", UserMapper = container.Resolve<IUserMapper>(), };
FormsAuthentication.Enable(pipelines, formsAuthCfg);
Content Negotiation
Nancy detects the Accept header on a request
If applicable, will return data in that form
Default formats are JSON
XML
View
Also configurable via Bootstrapper
Gotcha! XML needs to be materialized, not deferred (List<> vs. IEnumerable<>)
Get["/api/quote"] = _ => { return _repo.GetAll()
.Quotes
.ToList(); };
Dependency Injection
By default, TinyIoc is built in Nancy co-developer’s project
Works well – rated as average on IoC Benchmark by Daniel Palme
Able to use IoC of choice Configure through Bootstrapper
Example with Ninject
Built in IoC allows automatic (magic?) injection of instances into Modules
private readonly IQuoteRepository _repo; public QuoteModule(IQuoteRepository repo) { _repo = repo;
How did this get here?
Performance (Requests/Second)
SU-20-1 SU-100-1 SU-500-1 MU-50-5 MU-100-10 MU-500-5 MU-1000-10 -
20.00
40.00
60.00
80.00
100.00
120.00
140.00
160.00
NancyFX and IIS 8.5 Requests/Second
NancyFX IIS 8.5
Performance (Time/Request)
SU-20-1 SU-100-1 SU-500-1 MU-50-5 MU-100-10 MU-500-5 MU-1000-10 -
5.00
10.00
15.00
20.00
25.00
30.00
35.00
40.00
45.00
50.00
NancyFX and IIS 8.5 Time (ms)/Request
NancyFX IIS 8.5
The Minimalist’s Goals - Recap
Easy setup and install
Able to deploy almost anywhere (low dependency)
Contained intent Anti-Scavenger Hunt Development
Convention favored over heavy configuration But I have control if needed
No significant performance hit
PhD not required
What’s Next?
Nancy + Katana (OWIN) Other ASP.NET components moving to pipeline model
Be able to plug in SignalR and other pieces into Katana
Great article in MSDN Magazine about Nancy + Katana + SignalR + WebApi
Custom view renderers
Custom pipeline components
Resources
NancyFx Site: http://nancyfx.org/
Documentation: https://github.com/NancyFx/Nancy/wiki/Documentation
Howard Dierking on Nancy and Katana: http://msdn.microsoft.com/en-us/magazine/dn451439.aspx
Dependency Injection Rankings: http://www.palmmedia.de/Blog/2011/8/30/ioc-container-benchmark-performance-comparison
Session Code: https://github.com/DavidHoerster/Minimalist.Solr
Slides: http://www.slideshare.net/dhoerster/a-minimalists-attempt-at-building-a-distributed-application