饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 69 页

作者:Nick Randolph/等 当前章节:15411 字 更新时间:2026-6-18 14:51

applications this is an unlikely scenario. The ASP.NET MVC framework makes it very easy to

parameterize action methods from a variety of sources.

As mentioned in the previous section, the “Default” route exposes an “id” parameter, which

defaults to an empty string. To access the value of the “id” parameter from within the action

method you can just add it to the signature of the method itself as the following snippet shows:

c#

public ActionResult Details(int id)

{

using (var db = new ProductsDataContext())

{

var product = db.Products.SingleOrDefault(x = > x.ProductID == id);

if (product == null)

return View("NotFound");

return View(product);

}

}

Code snippet Controllers\ProductsController.cs

Vb

Public Function Details(ByVal id As Integer) As ActionResult

Using db As New ProductsDataContext

Dim product = db.Products.FirstOrDefault(Function(p As Product)

p.ProductID = id)

Return View(product)

End Using

End Function

Code snippet Controllers\ProductsController.vb

When the MVC framework executes the Details action method it will search through the parameters

that have been extracted from the URL by the matching route. These parameters are matched up

with the parameters on the action method by name and then passed in when the method is called.

As the details method shows, the framework is even able to convert the type of the parameter on the

fly. Action methods can also retrieve parameters from the query string portion of the URL and from

HTTP POST data using the same technique.

If the conversion cannot be made for any reason, an exception is thrown.

advanced MVC .

457

Additionally, an action method can accept a parameter of the FormValues type that will aggregate

all of the HTTP POST data into a single parameter. If the data in the FormValues collection

represents the properties of an object, you can simply add a parameter of that type and a new

instance will be created when the action method is called. The Create action, shown in the

following snippet, uses this to construct a new instance of the Product class and then save it:

c#

public ActionResult Create()

{

return View();

}

[HttpPost]

public ActionResult Create([Bind(Exclude="ProductId")]Product product)

{

if (!ModelState.IsValid)

return View();

using (var db = new ProductsDataContext())

{

db.Products.InsertOnSubmit(product);

db.SubmitChanges();

}

return RedirectToAction("List");

}

Code snippet Controllers\ProductsController.cs

Vb

< HttpPost() >

Function Create( < Bind(Exclude:="id") > ByVal product As Product)

If (Not ModelState.IsValid) Then

Return View()

End If

Using db As New ProductsDataContext

db.Products.InsertOnSubmit(product)

db.SubmitChanges()

End Using

Return RedirectToAction("List")

End Function

Code snippet Controllers\ProductsController.vb

There are two Create action methods here. The first one simply renders the “Create”

view. The second one is marked up with an HttpPostAttribute, which means that

it will only be selected if the HTTP request uses the POST verb. This is a common

practice in designing ASP.NET MVC web sites. In addition to HttpPostAttribute

there are also corresponding attributes for the GET, PUT, and DELETEverbs.

458 .

chaPter 21 ASp.neT mVc

Model Binders

The process of creating the new Product instance is the responsibility of a model binder. The model

binder matches properties in the HTTP POST data with properties on the type that it is attempting to

create. This works in this example because the template that was used to generate the “Create” view

renders the HTML INPUT fields with the correct name as this snippet of the rendered HTML shows:

htMl

<p>

<label for=”ProductID”>ProductID:</label>

<input id=”ProductID” name=”ProductID” type=”text” value=”” />

</p>

<p>

<label for=”Name”>Name:</label>

<input id=”Name” name=”Name” type=”text” value=”” />

</p>

A number of ways exist to control the behavior of a model binder including the BindAttribute,

which is used in the Create method shown previously. This attribute is used to include or exclude

certain properties and to specify a prefix for the HTTP POST values. This can be very useful if

multiple objects in the POST collection need to be bound.

Model binders can also be used from within the action method to update existing instances of

your model classes using the UpdateModel and TryUpdateModel methods. The chief difference is

that TryUpdateModel will return a Boolean value indicating whether or not it was able to build a

successful model and UpdateModel will just throw an exception if it can’t. The Edit action method

shows this technique:

c#

[HttpPost]

public ActionResult Edit(int id, FormCollection formValues)

{

using (var db = new ProductsDataContext())

{

var product = db.Products.SingleOrDefault(x => x.ProductID == id);

if (TryUpdateModel(product))

{

db.SubmitChanges();

return RedirectToAction("Index");

}

return View(product);

}

}

Code snippet Controllers\ProductsController.cs

Vb

<HttpPost()>

Function Edit(ByVal id As Integer, ByVal formValues As FormCollection)

Using db As New ProductsDataContext

advanced MVC .

459

Dim product = db.Products.FirstOrDefault(Function(p As Product)

p.ProductID = id)

If TryUpdateModel(product) Then

db.SubmitChanges()

Return RedirectToAction("Index")

End If

Return View(product)

End Using

End Function

Code snippet Controllers\ProductsController.vb

areas

An area is a self-contained part of an MVC

application that manages its own models,

controllers, and views. You can even define

routes specific to an area. To create a new area,

select Add . Area from the project context

menu in the Solution Explorer. The Add Area

dialog, shown in Figure 21-7,

prompts you to provide a name for your area.

After you click Add, many new files are added to your project to

support the area. Figure 21-8 shows a project with two areas added

to it named Shop and Blog, respectively.

In addition to having its own controllers and views, each area has

a class called AreaNameAreaRegistration that inherits from the

abstract base class AreaRegistration. This class contains an

abstract property for the name of your area and an abstract method

for integrating your area with the rest of the application. The

default implementation registers the standard routes.

c#

public class BlogAreaRegistration : AreaRegistration

{

public override string AreaName

{

get

{

return "Blog";

}

}

public override void RegisterArea(AreaRegistrationContext context)

{

context.MapRoute(

"Blog_default",

"Blog/{controller}/{action}/{id}",

fiGure 21-7

fiGure 21-8

460 .

chaPter 21 ASp.neT mVc

new { action = "Index", id = "" }

);

}

}

Code snippet Areas\Blog\BlogAreaRegistration.cs

Vb

Public Class BlogAreaRegistration

Inherits AreaRegistration

Public Overrides ReadOnly Property AreaName() As String

Get

Return "Blog"

End Get

End Property

Public Overrides Sub RegisterArea(ByVal context As AreaRegistrationContext)

context.MapRoute( _

"Blog_default", _

"Blog/{controller}/{action}/{id}", _

New With {.action = "Index", .id = ""} _

)

End Sub

End Class

Code snippet Areas\Blog\BlogAreaRegistration.vb

The RegisterArea method of the BlogAreaRegistration class defines a route

in which every URL is prefixed with /Blog/ by convention. This can be useful

while debugging routes but is not necessary as long as area routes do not clash

with any other routes.

In order to link to a controller which is inside another area, you need to use an overload of

Html.ActionLink that accepts a routeValues parameter. The object you provide for this parameter

must include an area property set to the name of the area which contains the controller you are

linking to.

c#

< %= Html.ActionLink("Blog", "Index", new { area = "Blog" }) % >

Vb

< %= Html.ActionLink("Blog", "Index", New With {.area = "Blog"})%>

One issue that is frequently encountered when adding area support to a project is that the controller

factory becomes confused when multiple controllers have the same name. To avoid this issue you

can limit the namespaces that a route will use to search for a controller to satisfy any request. The

advanced MVC .

461

following code snippet limits the namespaces for the global routes to MvcApplication.Controllers,

which will not match any of the area controllers.

c#

routes.MapRoute(

"Default",

"{controller}/{action}/{id}",

new { controller = "Home", action = "Index", id = "" },

null,

new[] { "MvcApplication.Controllers" }

);

Code snippet Global.asax.cs

Vb

routes.MapRoute( _

"Default", _

"{controller}/{action}/{id}", _

New With {.controller = "Home", .action = "Index", .id = ""}, _

Nothing, _

New String() {"MvcApplication.Controllers"} _

)

Code snippet Global.asax.vb

The AreaRegistrationContext automatically includes the area namespace

when you use it to specify routes so you should only need to supply namespaces

to the global routes.

Validation

In addition to just creating or updating it, a model

binder is able to decide whether the model instance

that it operating on is valid. The results of this

decision are found in the ModelState property.

Model binders can pick up some simple validation

errors by default, usually with regard to incorrect

types. Figure 21 - 9 shows the result of attempting to

save a Product when the form is empty. Most of

these validation errors are based on the fact that

these properties are non-nullable value types and

require a value.

The user interface for this error report is provided

by the Html.ValidationSummary call, which is

made on the view. This helper method examines the

ModelState and if it finds any errors it renders them

as a list along with a header message. fiGure 21-9

462 .

chaPter 21 ASp.neT mVc

You can add additional validation hints to the properties of the model class by marking them up with

using the attributes in the System.ComponentModel.DataAnnotations assembly. Because the Product

class is created by LINQ to SQL you should not update it directly. The LINQ to SQL generated classes

are defined as partial so you can extend them but there is no easy way to attach metadata to the

generated properties this way. Instead, you need to create a metadata proxy class with the properties

you want to mark up, provide them with the correct data annotation attributes, and then mark up the

partial class with a MetadataTypeAttribute identifying the proxy class. The following code snippet

shows this technique being used to provide some validation metadata to the Product class:

c#

[MetadataType(typeof(ProductValidationMetadata))]

public partial class Product

{

}

public class ProductValidationMetadata

{

[Required, StringLength(256)]

public string Name { get; set; }

[Range(0, 100)]

public int DaysToManufacture { get; set; }

}

Code snippet Models\Product.cs

Vb

Imports System.ComponentModel.DataAnnotations

<MetadataType(GetType(ProductMetaData))>

Partial Public Class Product

End Class

Public Class ProductMetaData

<Required(), StringLength(256)>

Property Name As String

<Range(0, 100)>

Property DaysToManufacture As Integer

End Class

Code snippet Models\Product.vb

Now, attempting to create a new Product with no name

and a negative “Days to Manufacture” produces the errors

shown in Figure 21-10.

fiGure 21-10

Partial Views

At times you have large areas of user interface markup that you would like to reuse. In the ASP.NET

MVC framework a re - usable section of view is called a partial view. Partial views act very similar to

views except that they have an .ascx extension and inherit from System.Web.Mvc.ViewUserControl .

To create a partial view, check the Create a Partial View checkbox on the same Add View dialog that

you use to create other views.

To render a partial view you can use the Html.RenderPartial method. The most common

overload of this method accepts a view name and a model object. Just as with a normal view, a

partial view can be either controller - specifi c or shared. Once the partial view has been rendered,

its HTML markup is inserted into the main view. This code snippet renders a “ Form ” partial for

the current model:

c#

< % Html.RenderPartial("Form", Model); % >

Vb

< % Html.RenderPartial("Form", Model) % >

You might notice that along with the error report at the top of the page, for each

fi eld which has a validation error, the textbox is colored red and has an asterisk

after it. The fi rst effect is caused by the Html.TextBox helper, which accepts the

value of the property that it is attached to. If it encounters an error in the model

state for its attached property, it adds an input - validation - error CSS class to

the rendered INPUT control. The default stylesheet defi nes the red background.

The second effect is caused by the Html.ValidationMessage helper. This helper

is also associated with a property and renders the contents of its second

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页