T22 The ASP.NET MVC Framework

Download Report

Transcript T22 The ASP.NET MVC Framework

MVC
A new Web Project Type for
ASP.NET.
An option.
More control over your <html/>
A more easily Testable
Framework.
Not for everyone.
“ScottGu”
“The Gu”
“His Gu-ness”
“Sir”
“Master Chief Gu”
This is not Web Forms 4.0
It’s about alternatives. Car vs. Motorcycle.
Flexible
Extend it. Or not.
Fundamental
Part of System.Web and isn’t going anywhere.
Plays Well With Others
Feel free to use NHibernate for Models, Brail
for Views and Whatever for Controllers.
Keep it simple and DRY
Maintain Clean Separation of Concerns
Easy Testing
Red/Green TDD
Highly maintainable applications by default
Extensible and Pluggable
Support replacing any component of the
system
Enable clean URLs and HTML
SEO and REST friendly URL structures
Great integration within ASP.NET
All the same providers still work
Membership, Session, Caching, etc.
ASP.NET Designer Surface in VS2008
MVC
Microsoft Visual Business
Enabler Studio 2008R3v2
September Technical
Preview Refresh
MSVBES2k8R3v2lptrczstr
for short
MVC
27
Model
View
Controller
Model
View
•Browser requests /Products/
•Route is determined
•Controller is activated
•Method on Controller is invoke
•Controller does some stuff
•Renders View, passing in
custom ViewData
•URLs are rendered,
pointing to other
Controller
Controllers
Request
• You can futz at each step
in the process
HTTP
Routing
Http
Handler
Controller
Response
Route
Route
Handler
View
Engine
View
MVC
Developers adds Routes to a global RouteTable
Mapping creates a RouteData - a bag of key/values
RouteTable.Routes.Add(
new Route("blog/bydate/{year}/{month}/{day}",
new MvcRouteHandler()){
Defaults = new RouteValueDictionary {
{"controller", "blog"}, {"action", "show"}
},
Constraints = new RouteValueDictionary {
{"year", @"\d{1.4}"},
{"month", @"\d{1.2}"},
{"day", @"\d{1.2}"}}
})
Views
Controllers
Models
Routes
…are all Pluggable
View Engines render output
You get WebForms by default
Can implement your own
MVCContrib has ones for Brail, Nvelocity
NHaml is an interesting one to watch
View Engines can be used to
Offer new DSLs to make HTML easier
Generate totally different mime/types
Images, RSS, JSON, XML, OFX, VCards,
whatever.
ViewEngineBase
public abstract class ViewEngineBase {
public abstract void RenderView(ViewContext viewContext);
}
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true"
CodeBehind="List.aspx"
Inherits="MvcApplication5.Views.Products.List" Title="Products" %>
<asp:Content ContentPlaceHolderID="MainContentPlaceHolder"
runat="server">
<h2><%= ViewData.CategoryName %></h2>
<ul>
<% foreach (var product in ViewData.Products) { %>
<li>
<%= product.ProductName %>
<div class="editlink">
(<%= Html.ActionLink("Edit", new { Action="Edit",
ID=product.ProductID })%>)
</div>
</li>
<% } %>
</ul>
<%= Html.ActionLink("Add New Product", new { Action="New" }) %>
</asp:Content>
%h2= ViewData.CategoryName
%ul
- foreach (var product in ViewData.Products)
%li = product.ProductName
.editlink
= Html.ActionLink("Edit",
new { Action="Edit",
ID=product.ProductID })
= Html.ActionLink("Add New Product",
new { Action="New" })
MVC
Mockable Intrinsics
HttpContextBase,
HttpResponseBase,
HttpRequestBase
Extensibility
IController
IControllerFactory
IRouteHandler
ViewEngineBase
No requirement to test within ASP.NET runtime.
Use RhinoMocks or TypeMock
Create Test versions of the parts of the runtime you
want to stub
[TestMethod]
public void ShowPostsDisplayPostView() {
TestPostRepository repository = new TestPostRepository();
TestViewEngine viewEngine = new TestViewEngine();
BlogController controller = new BlogController(…);
controller.ShowPost(2);
Assert.AreEqual("showpost",viewEngine.LastRequestedView);
Assert.IsTrue(repository.GetPostByIdWasCalled);
Assert.AreEqual(2, repository.LastRequestedPostId);
}
This is not Web Forms 4.0
It’s about alternatives. Car vs. Motorcycle.
Flexible
Extend it. Or not.
Fundamental
Part of System.Web and isn’t going anywhere.
Plays Well With Others
Feel free to use NHibernate for Models, Brail
for Views and Whatever for Controllers.
Keep it simple and DRY
HAI!
IM IN YR Northwind
HOW DUZ I ListProducts YR id
PRODUCTS = GETPRODUCTS id
OMG FOUND YR PRODUCTS
IF U SEZ
IM OUTTA YR Northwind
HAI!
WTF:
I HAS A STRING
GIMMEH STRING
IM IN YR VAR UPPIN YR 0
TIL LENGTH OF STRING
VISIBLE “GIMMEE A ” STRING!!VAR
STEPPIN
IM OUTTA YR VAR
OMGWTF
HALP!
© 2008 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market
conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation.
MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
MVC
Base Controller Class
Basic Functionality most folks will use
IController Interface
Ultimate Control for the Control Freak
IControllerFactory
For plugging in your own stuff (IOC, etc)
Scenarios, Goals and Design
URLs route to controller “actions”, not pages –
mark actions in Controller.
Controller executes logic, chooses view.
All public methods are accessible
public void ShowPost(int id) {
Post p = PostRepository.GetPostById(id);
if (p != null) {
RenderView("showpost", p);
} else {
RenderView("nosuchpost", id);
}
}
public class Controller : IController {
…
protected virtual void Execute(ControllerContext
controllerContext);
protected virtual void HandleUnknownAction(string actionName);
protected virtual bool InvokeAction(string actionName);
protected virtual void InvokeActionMethod(MethodInfo methodInfo);
protected virtual bool OnError(string actionName,
MethodInfo methodInfo, Exception exception);
protected virtual void OnActionExecuted(FilterExecutedContext
filterContext);
protected virtual bool OnActionExecuting(FilterExecutedContext
filterContext);
protected virtual void RedirectToAction(object values);
protected virtual void RenderView(string viewName,
string masterName, object viewData);
}
public class Controller : IController {
…
protected virtual void Execute(ControllerContext
controllerContext);
protected virtual void HandleUnknownAction(string actionName);
protected virtual bool InvokeAction(string actionName);
protected virtual void InvokeActionMethod(MethodInfo methodInfo);
protected virtual bool OnError(string actionName,
MethodInfo methodInfo, Exception exception);
protected virtual void OnActionExecuted(FilterExecutedContext
filterContext);
protected virtual bool OnActionExecuting(FilterExecutedContext
filterContext);
protected virtual void RedirectToAction(object values);
protected virtual void RenderView(string viewName,
string masterName, object viewData);
}
public class Controller : IController {
…
protected virtual void Execute(ControllerContext
controllerContext);
protected virtual void HandleUnknownAction(string actionName);
protected virtual bool InvokeAction(string actionName);
protected virtual void InvokeActionMethod(MethodInfo methodInfo);
protected virtual bool OnError(string actionName,
MethodInfo methodInfo, Exception exception);
protected virtual void OnActionExecuted(FilterExecutedContext
filterContext);
protected virtual bool OnActionExecuting(FilterExecutedContext
filterContext);
protected virtual void RedirectToAction(object values);
protected virtual void RenderView(string viewName,
string masterName, object viewData);
}
public class Controller : IController {
…
protected virtual void Execute(ControllerContext
controllerContext);
protected virtual void HandleUnknownAction(string actionName);
protected virtual bool InvokeAction(string actionName);
protected virtual void InvokeActionMethod(MethodInfo methodInfo);
protected virtual bool OnError(string actionName,
MethodInfo methodInfo, Exception exception);
protected virtual void OnActionExecuted(FilterExecutedContext
filterContext);
protected virtual bool OnActionExecuting(FilterExecutedContext
filterContext);
protected virtual void RedirectToAction(object values);
protected virtual void RenderView(string viewName,
string masterName, object viewData);
}
Scenarios, Goals and Design:
Are for rendering/output.
Pre-defined and extensible rendering helpers
Can use .ASPX, .ASCX, .MASTER, etc.
Can replace with other view
technologies:
Template engines (NVelocity, Brail, …).
Output formats (images, RSS, JSON, …).
Mock out for testing.
Controller sets data on the View
Loosely typed or strongly typed data
View Engines render output
You get WebForms by default
Can implement your own
MVCContrib has ones for Brail, Nvelocity
NHaml is an interesting one to watch
View Engines can be used to
Offer new DSLs to make HTML easier to write
Generate totally different mime/types
Images
RSS, JSON, XML, OFX, etc.
VCards, whatever.
ViewEngineBase
public abstract class ViewEngineBase {
public abstract void RenderView(ViewContext viewContext);
}
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
AutoEventWireup="true"
CodeBehind="List.aspx"
Inherits="MvcApplication5.Views.Products.List" Title="Products"
<asp:Content ContentPlaceHolderID="MainContentPlaceHolder"
runat="server">
<h2><%= ViewData.CategoryName %></h2>
<ul>
<% foreach (var product in ViewData.Products) { %>
<li>
<%= product.ProductName %>
<div class="editlink">
(<%= Html.ActionLink("Edit", new { Action="Edit",
ID=product.ProductID })%>)
</div>
</li>
<% } %>
</ul>
<%= Html.ActionLink("Add New Product", new { Action="New" }) %>
</asp:Content>
%h2= ViewData.CategoryName
%ul
- foreach (var product in ViewData.Products)
%li = product.ProductName
.editlink
= Html.ActionLink("Edit",
new { Action="Edit",
ID=product.ProductID })
= Html.ActionLink("Add New Product",
new { Action="New" })
Scenarios, Goals and Design:
Hook creation of controller instance
Dependency Injection.
Object Interception.
public interface IControllerFactory {
IController CreateController(RequestContext context,
string controllerName);
}
protected void Application_Start(object s, EventArgs e) {
ControllerBuilder.Current.SetControllerFactory(
typeof(MyControllerFactory));
}
Scenarios, Goals and Design:
Mock out views for testing
Replace ASPX with other technologies
public interface IViewEngine {
void RenderView(ViewContext context);
}
Inside controller class:
this.ViewEngine = new XmlViewEngine(...);
RenderView("foo", myData);