ASP.NET MVC Internals

47
Vitaly Baum @butaji ASP.NET MVC Internals

Transcript of ASP.NET MVC Internals

Vitaly Baum @butaji

ASP.NET MVC Internals

> whoamiVitaly BaumProduct Manager @ bright box

[email protected]://twitter.com/butaji

BACKGROUND

▪Web Application▪MVC▪What and How

▪Controller▪How do I write Controllers? ▪How do requests come to Controller?

▪View▪How does ViewEngine render views? ▪Why do I need to change ViewEngine?

AGENDA

QUESTIONS• Non-IIS

• Azure in production

• NoSQL

• NGINX

OK. MVC

MVC• Front Controller

An object that handles all requests

• Page Controller

An object that handles a request for a specific page or action on a Web site

HTTP

HTTP

1. Request 2. Environment 3. Response

IIS• System.Web.dll

• IHttpHandler (extensions)

• IHttpModule (HttpApplication events)

using System;using System.Web;

public class LoggingHttpModule : IHttpModule{ public void Dispose() {}

public void Init(HttpApplication context) { context.BeginRequest += BeginRequest; }

void BeginRequest(object sender, EventArgs e) {

Logger.Instance.Log("Hi there!");}

}

public class RequestHandler : IHttpHandler{ public RequestHandler() { }

public bool IsReusable { get { return false; } }

public void ProcessRequest(HttpContext context) { context.Response.ContentType = "application/json"; context.Response.Write("{ id : 1 }"); }}

ASP.NET MVC?

• Were implemented on HttpHandlers

• https://servicestack.net/features

• http://www.castleproject.org/projects/monorail/

• http://mvc.fubu-project.org

IIS + ASP.NET• Highly coupled

• Hard to manage (ain’t my job)

• New features only with OS updates

a. Web Server b. Middleware c. Application

SERVER INTEROP

• authentication • cookies • authorization • output caching • localisation • request servicing (app)

MIDDLEWARE

SERVER INTEROP• Rack (ruby)

• WSGI (Python)

• Node.js

• OWIN (.NET)

require  'rack'      app  =  Proc.new  do  |env|  #  ENV  HASH          [  

'200',  #  HTTP  CODE  {'Content-­‐Type'  =>  'text/html'},    ['A  barebones  rack  app.’]  #  BODY  

   ]  end      Rack::Handler::WEBrick.run  app

MIDDLEWARE

var http = require('http');

var server = http.createServer(function (req, res) {

res.writeHead(200, {'Content-Type': 'text/plain'});

res.end('Hello World\n');

})

server.listen(1337, '127.0.0.1');

MIDDLEWARE

var  express  =  require('express')  var  app  =  express()  

app.use(function  (req,  res,  next)  {      console.log('Time:',  Date.now());      next();  });  

MIDDLEWARE

//OWIN Implementation

using AppFunc = Func< IDictionary<string, object>, Task >;

MIDDLEWARE

OWINpublic  class  Startup  {  

public  void  Configuration(IAppBuilder  app)  {  

app.Run(context  =>  {  return  context  

.Response.WriteAsync("Hi  OWIN/Katana");  });  

}  }

ASP.NET MVC

ASP.NET MVC LIFECYCLERouting UrlRoutingModule -> IRouteHandler -> IHttpHandler

Controller Execute -> Filters -> Model Binding -> Action

Action Your Code

Result Views -> TypeFormater

ROUTE HANDLERpublic  class  MyRouteHandler  :  IRouteHandler  {        public  IHttpHandler  GetHttpHandler(  RequestContext  requestContext)        {                var  handler  =  new  MyMVCHandler();                handler.RequestContext  =  requestContext;                return  handler;          }  }

ROUTE HANDLER• In case of dynamic routes

• CMS

• Blog with custom Slugs

MVC HANDLERpublic  class  MyMVCHandler  :  MvcHandler{        protected  override  void  ProcessRequest(IHttpContext  httpContext)        {var  controllerName  =  GetRequiredString(this.RequestContext.RouteData,  "controller");                var  controller  =  CreateController(controllerName);              var  controllerContext  =  new  ControllerContext(base.RequestContext,  controller);                controller.Execute(controllerContext);        }          private  IController  CreateController(string  controllerName)        {            return  _controllerFactory.Create(controllerName);        }}

DEPENDENCY MGMT

public  class  CustomControllerFactory  :  IControllerFactory  {      public  IController  CreateController(RequestContext  requestContext,  string  name)      {              return  _serviceLocator.Resolve<IController>(name);    }  }  

DEPENDENCY MGMT//ASP.NET  vNext  has  new  way  to  inject  dependencies  

public  class  Startup  {      public  void  Configure(IBuilder  app)      {          var  services  =  new  ServiceCollection();          services.AddTransient<IMessageGenerator,  HelloMessageGenerator>();  

       app.UseMiddleware(typeof(ContainerMiddleware));      }  }  

OK. CTRL

CONTROLLER FAT VS SKINNY

CONTROLLER[HttpPost,  ActionName("Delete")]  public  async  Task<ActionResult>  DeleteConfirmed(int  id)  {  var  album  =  await  _storeContext.Albums.FindAsync(id);  if  (album  ==  null)  {  return  HttpNotFound();  

}  

_storeContext.Albums.Remove(album);  await  _storeContext.SaveChangesAsync();  

return  RedirectToAction("Index");  }  

CONTROLLER[HttpPost,  ActionName("Delete")]  public  async  Task<ActionResult>  DeleteConfirmed(int  id)  {  

var  removed  =  await  _albumService.Remove(id);  

return  Status.NotFound  ==  removed.Status  ?  HttpNotFound()  :  RedirectToAction(“Index");  

}  

CONTROLLER

//vNext  can  host  POCOs  controllers  public  List<Data>  GetData()  {  return  null;  //will  return  204  (NoContent)  

}

def {action_name}( {params} )app_res = {domain_service}.{call}( {params} )return app_res

end

OK. VIEW

SEO OF SPA

SEO OF SPAMIDDLEWARE

Middleware

ApplicationGET / User-Agent: Chrome

GET / User-Agent: Google

JSON

Middleware

Application

GET / User-Agent: Google

GET / User-Agent: Chrome

HTML

SEO OF SPASHARED TEMPLATES

SHARED TEMPLATES

Server ClientTemplate

}http://mustache.github.io

{{#repo}} <b>{{name}}</b>{{/repo}}

{ "repo": [ { "name": "resque" }, { "name": "hub" }, { "name": "rip" } ]}

<b>resque</b><b>hub</b><b>rip</b>+ =

YET ANOTHER TEMPLATE

VIEW ENGINEpublic  interface  IViewEngine    {        ViewEngineResult  FindPartialView(ControllerContext  ctx,  string  name,  bool  useCache);  

     ViewEngineResult  FindView(ControllerContext  ctx,  string  viewName,  string  masterName,  bool  useCache);  

     void  ReleaseView(ControllerContext  ctx,  IView  view);  }  

public  interface  IView    {      void  Render(ViewContext  ctx,  TextWriter  writer);  }

http://buildstarted.com/2013/12/16/javascript-view-engine-for-aspnet/

VIEW ENGINEservices.AddMvc().Configure<MvcOptions>(  

options  =>  {  

options.ViewEngines.Add(  new  MyCustomerViewEngine  ());  

});

COVERED TOPICS▪Web Application▪MVC▪What and How

▪Controller▪How do I write Controllers? ▪How do requests come to Controller?

▪View▪How does ViewEngine render views? ▪Why do I need to change ViewEngine?

THANK YOU

Vitaly Baum @butaji