日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

ASP.NET MVC Tip #31: 给 Master Pages 和 User Controls 传递数据

發(fā)布時(shí)間:2025/3/21 asp.net 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET MVC Tip #31: 给 Master Pages 和 User Controls 传递数据 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:ASP.NET MVC Tip #31 – Passing Data to Master Pages and User Controls
原文作者:swalther

本文譯者:QLeelulu

摘要:
在這個(gè)Tip中,我會(huì)討論給MasterPages和UserControls傳遞數(shù)據(jù)的4種策略。我會(huì)講解通過(guò)code-behind類(lèi)、通過(guò)使用ActionFilter、通過(guò)調(diào)用局部方法、和通過(guò)使用抽象的Controller基類(lèi)來(lái)傳遞數(shù)據(jù)。我推薦使用最后一種方法。

?

在這個(gè)Tip中,我推薦一種傳遞數(shù)據(jù)到MasterPages和UserControls的方法。但在提出我的建議前,我會(huì)先講解一下這個(gè)問(wèn)題的幾種解決方法。

The Problem

想象一下你要使用ASP.NET MVC框架來(lái)開(kāi)發(fā)一個(gè)movie database application。你決定要在該應(yīng)用的每一個(gè)頁(yè)面上都顯示一個(gè)電影分類(lèi)的列表,這樣,用戶(hù)就可以方便的導(dǎo)航到他喜歡的分類(lèi)。一旦你想該電影分類(lèi)列表顯示在每一個(gè)頁(yè)面,很自然的就會(huì)想到在MasterPage中顯示這個(gè)列表。
你也決定在某些頁(yè)面上顯示一些熱門(mén)的電影列表,但不是顯示在所有的頁(yè)面上。這個(gè)熱門(mén)的電影列表是從數(shù)據(jù)庫(kù)中隨機(jī)的取出來(lái)的。你決定要通過(guò)用戶(hù)控件來(lái)實(shí)現(xiàn):就叫 FeaturedMovies control (見(jiàn)圖 1).

圖 1 – The Movie Database Application

問(wèn)題就出現(xiàn)在這里。你需要在程序中給每一個(gè)頁(yè)面的母版頁(yè)傳遞電影分類(lèi)列表數(shù)據(jù)。你需要給程序中的某些特定的頁(yè)面的熱門(mén)電影用戶(hù)控件傳遞熱門(mén)電影列表數(shù)據(jù)。你怎么實(shí)現(xiàn)這個(gè)呢?

Using a Code-Behind Class

最通常的做法,但是是錯(cuò)誤的,就是在code-behind class 中為你的MasterPage和FeaturedMovies用戶(hù)控件取數(shù)據(jù)來(lái)解決這個(gè)問(wèn)題。Listing 1 中的MasterPage顯示code-behind class中的叫做Categories屬性的電影分類(lèi)列表。

Listing 1 – Site.Master

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="Solution1.Views.Shared.Site" %> <%@ Import Namespace="Solution1.Models" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><title>Movies</title><link href="http://www.cnblogs.com/Content/Site.css" rel="stylesheet" type="text/css" /> </head><body> <div class="page"><div id="header"><h1>Movie Database Application</h1></div><div id="main"><div class="leftColumn"><ul><% foreach (MovieCategory c in this.Categories){ %><li> <%= Html.ActionLink(c.Name, "Category", new {id=c.Id} )%></li><% } %></ul></div><div class="rightColumn"><asp:ContentPlaceHolder ID="MainContent" runat="server" /></div><br style="clear:both" /><div id="footer">Movie Database Application &copy; Copyright 2008</div></div> </div> </body> </html>

這個(gè)MasterPage的code-behind class在Listing 2 中。注意在Listing 2 中是直接通過(guò)LINQ2SQL來(lái)取數(shù)據(jù)的。

Listing 2 – Site.Master.cs

using System.Collections.Generic; using System.Linq; using Solution1.Models;namespace Solution1.Views.Shared {public partial class Site : System.Web.Mvc.ViewMasterPage{protected IEnumerable<MovieCategory> Categories{get{var dataContext = new MovieDataContext();return from c in dataContext.MovieCategories select c;}}}}

?

你同樣可以為FeaturedMovies 用戶(hù)控件來(lái)取數(shù)據(jù)。在FeaturedMovies code-behind class 從數(shù)據(jù)庫(kù)中取熱門(mén)電影的列表數(shù)據(jù)。

那么,為什么這錯(cuò)了呢?這當(dāng)然好像一個(gè)簡(jiǎn)單的解決辦法。它正常工作了,為什么還要抱怨?

這個(gè)解決方案的問(wèn)題是MasterPage的code-behind class 中的代碼是不可測(cè)試的。你不可以很方便的為Site類(lèi)寫(xiě)單元測(cè)試,因?yàn)镾ite類(lèi)是繼承自ViewMasterPage類(lèi),而ViewMasterPage類(lèi)繼承自Page類(lèi)。The Page class relies on the HTTP Context object and all hope of isolating your code so that it can be tested goes away.

在開(kāi)發(fā)ASP.NET MVC應(yīng)用的時(shí)候,你應(yīng)該盡量避免在你的程序中在code-behind class 中處理邏輯,嘗試將所有的東西都放回到Controllers中。Controllers被設(shè)計(jì)為可測(cè)試的。

Using an Action Filter

所以讓我們以另一種途徑來(lái)解決這個(gè)傳遞數(shù)據(jù)給MasterPage或者view的問(wèn)題。在這一節(jié),我們創(chuàng)建一個(gè)ActionFilter來(lái)修改傳遞給view的ViewData。這個(gè)方法你可以通過(guò)給controller添加一個(gè)或者多個(gè)action filter來(lái)修改由controller傳遞給view的ViewData。

這個(gè)ActionFilter,命名為[Partial] ,如Listing 3所示。

Listing 3 – ActionFilters\PartialAttribute.cs

using System; using System.Reflection; using System.Web.Mvc;namespace Solution2.ActionFilters {public class PartialAttribute : ActionFilterAttribute{private string _partialClassName;public PartialAttribute(string partialClassName){_partialClassName = partialClassName;}public override void OnActionExecuting(ActionExecutingContext filterContext){var viewData = (filterContext.Controller as Controller).ViewData;ExecutePartial(_partialClassName, viewData);}private void ExecutePartial(string partialName, ViewDataDictionary viewData){// Get partial typevar partialType = Type.GetType(partialName, true, true);var partial = Activator.CreateInstance(partialType);// Execute all public methodsvar methods = partialType.GetMethods();foreach (MethodInfo method in methods){var pams = method.GetParameters();if (pams.Length > 0 && pams[0].ParameterType == typeof(ViewDataDictionary))method.Invoke(partial, new object[] { viewData });}}} }

?

當(dāng)你添加[Partial] 到一個(gè)controller action的時(shí)候,這個(gè)ation filter會(huì)附加一些數(shù)據(jù)到view data中去。例如,有可以使用[Partial] 特性來(lái)添加電影分類(lèi)列表的數(shù)據(jù)到view data中去以便在master page中顯示。你也可以使用[Partial] 特性來(lái)添加熱門(mén)電影列表到view data 中以使在FeaturedMovie 用戶(hù)控件中得到該數(shù)據(jù)。

[Partial] 特性通過(guò)一個(gè)類(lèi)名,實(shí)例化這個(gè)類(lèi),然后執(zhí)行類(lèi)里面所有的public方法(每一個(gè)方法都包含一個(gè)ViewDataDictionary參數(shù)),Listing 4 中的controller說(shuō)明了你可以怎樣使用[Partial] action filter來(lái)為不同的controller返回不同的ViewData。

Listing 4 – HomeController.cs

using System.Linq; using System.Web.Mvc; using Solution2.ActionFilters; using Solution2.Models;namespace Solution2.Controllers {[Partial("Solution2.Partials.Master")]public class HomeController : Controller{[Partial("Solution2.Partials.Featured")]public ActionResult Index(){return View();}public ActionResult Category(int id){var dataContext = new MovieDataContext();var movies = from m in dataContext.Movies where m.CategoryId == id select m;return View("Category", movies);}} }

注意到HomeController它本身是添加了[Partial] action filter的。由于[Partial] action filter應(yīng)用到類(lèi)上,在HomeController里面的每一個(gè)action執(zhí)行的時(shí)候這個(gè)action filter都會(huì)執(zhí)行的。在類(lèi)級(jí)別上應(yīng)用[Partial] 特性來(lái)為master page提供view data。

類(lèi)級(jí)別上的[Partial]特性添加電影分類(lèi)列表到view data中。[Partial]執(zhí)行Solution2.Partials.Master 類(lèi)中的方法,如Listing 5 所示。

Listing 5 – Master.cs

using System.Linq; using System.Web.Mvc; using Solution2.Models;namespace Solution2.Partials {public class Master{public void AddViewData(ViewDataDictionary viewData){var dataContext = new MovieDataContext();var categories = from c in dataContext.MovieCategories select c;viewData["master"] = categories; }} }

?

AddViewData() 方法將categories 添加到key為"master"的view data dictionary中。master page從view data 中取出categories 并顯示。

[Partial] 也可以添加到特定的action上,例如Listing 4 中的Index()方法。

然而這種從controller中傳遞數(shù)據(jù)給母版頁(yè)和用戶(hù)控件的解決方案錯(cuò)在哪里呢?這種方法的優(yōu)于前面一種方法的地方在于他將獲取數(shù)據(jù)的邏輯放回到controller中來(lái)處理了。ViewData在controller action 調(diào)用的時(shí)候會(huì)被修改。

無(wú)論怎樣,這個(gè)解決方案還是挺不錯(cuò)的。通過(guò)使用[Partial] 特性,你可以為view data dictionary 添加更多的數(shù)據(jù)。例如,如果你決定你要添加一個(gè)新的用戶(hù)控件到某一個(gè)頁(yè)面,而這個(gè)新的用戶(hù)控件需要一個(gè)不同的數(shù)據(jù)集,你可以很簡(jiǎn)單的添加一個(gè)新的[Partial] 特性到正確的controller action上來(lái)添加新的數(shù)據(jù)到view data dictionary中去。

遺憾的是,只是一點(diǎn)點(diǎn)的遺憾,這個(gè)解決方案不是很容易進(jìn)行單元測(cè)試。當(dāng)你在一個(gè)單元測(cè)試?yán)锩鎴?zhí)行action方法的時(shí)候ActionFilter并不會(huì)執(zhí)行。所以,我們需要尋找一個(gè)不同的策略來(lái)解決這個(gè)問(wèn)題。

Calling Partial Methods Directly

讓我們進(jìn)入到這個(gè)問(wèn)題的第三個(gè)解決方案中。在這一節(jié)中,我們嘗試通過(guò)直接在controller中來(lái)獲取數(shù)據(jù)然后傳遞給母版頁(yè)和用戶(hù)控件來(lái)解決這個(gè)問(wèn)題。在Listing 6 中是我們修改后的HomeController的代碼。

Listing 6 – HomeController.cs (with partials logic)

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Solution3.Models; using Solution3.Partials;namespace Solution3.Controllers {public class HomeController : Controller{public HomeController(){Master.AddViewData(this.ViewData);}public ActionResult Index(){Featured.AddViewData(this.ViewData);return View();}public ActionResult Category(int id){var dataContext = new MovieDataContext();var movies = from m in dataContext.Movies where m.CategoryId == id select m;return View("Category", movies);}} }

注意到Listing 6 中的HomeController有一個(gè)構(gòu)造函數(shù)。在構(gòu)造函數(shù)中調(diào)Master.AddViewData() 來(lái)改變controller action中返回的view data。這個(gè)方法要在母版頁(yè)中顯示的view data。

Index()方法也改變了。在Index()方法里面,調(diào)用了Featured.AddViewData() 方法。這個(gè)方法為FeaturedMovies 用戶(hù)控件添加必需的view data。由于FeaturedMovies 用戶(hù)控件只在Index視圖中呈現(xiàn),而不在Categorys視圖中呈現(xiàn),所以不在構(gòu)造函數(shù)中調(diào)用Featured.AddViewData() 方法。

這個(gè)解決方案的優(yōu)點(diǎn)是非常容易進(jìn)行單元測(cè)試。當(dāng)你調(diào)用Index()方法,view data同時(shí)被Master和Featured的部分方法改變了。也就是說(shuō),你可以容易的測(cè)試你傳遞給母版頁(yè)和用戶(hù)控件的view data是否是正確的。

那么,這個(gè)解決方案錯(cuò)在哪里了呢?添加view data的所有邏輯都已經(jīng)放到controller類(lèi)中來(lái)處理了。這個(gè)解決方案已經(jīng)比前面的兩個(gè)方案要好很多了。這個(gè)解決方法的唯一的問(wèn)題是它違背了單一責(zé)任原則。

根據(jù)單一責(zé)任原則,代碼應(yīng)該只有一個(gè)單一的理由去改變(code should have only a single reason to change)。然而,我們有很多原因要去改變Listing 8 中的Index()方法。如果我們也決定添加一個(gè)新的用戶(hù)控件到Index視圖中,而這個(gè)新的用戶(hù)控件顯示一個(gè)新的數(shù)據(jù)集,然后我們就需要去修改Index() action了。

單一責(zé)任制原則背后的目的是你永遠(yuǎn)不要去改變已經(jīng)在運(yùn)作中的代碼。改變代碼通常意味著為你的應(yīng)用帶入一個(gè)bug。我們需要尋找一些途徑來(lái)添加新的view data而不用修改我們的controller action。

Using Abstract Base Classes

這里是我對(duì)于這個(gè)問(wèn)題的最后一個(gè)解決方案:我們將使用抽象的基類(lèi)來(lái)改變從controller action返回來(lái)的view data。我現(xiàn)在要警告你這個(gè)是復(fù)雜的。我們需要?jiǎng)?chuàng)建好幾個(gè)類(lèi)。然而,每一個(gè)類(lèi)都是單一職責(zé)的。每一個(gè)類(lèi)都只是負(fù)責(zé)一種類(lèi)型的view data 而已(見(jiàn)圖2)。

Figure 2 – Class Hierarchy

我們將創(chuàng)建一個(gè)抽象基類(lèi),命名為ApplicationController ,改變view data divtionary來(lái)為我們的母版頁(yè)添加所需的所有的view data(見(jiàn)Listing 7)。這個(gè)ApplicationController 在我們的程序中作為每一個(gè)controller的基類(lèi),而不單單是HomeController。

Listing 7 – ApplicationController

using System.Web.Mvc; using Solution4.Partials;namespace Solution4.Controllers {public abstract class ApplicationController : Controller{public ApplicationController(){Master.AddViewData(this.ViewData);}} }

下一步,我們將要?jiǎng)?chuàng)建一個(gè)命名為HomeControllerBase 的抽象基類(lèi)(見(jiàn)Listing 8).這個(gè)類(lèi)包含了通常出現(xiàn)在HomeController的所有的應(yīng)用邏輯。我們將會(huì)重寫(xiě)action方法來(lái)為特定的用戶(hù)控件添加需要的view data。

Listing 8 – HomeControllerBase.cs

using System.Linq; using System.Web.Mvc; using Solution4.Models;namespace Solution4.Controllers.Home {public abstract class HomeControllerBase : ApplicationController{public virtual ActionResult Index(){return View("Index");}public virtual ActionResult Category(int id){var dataContext = new MovieDataContext();var movies = from m in dataContext.Movies where m.CategoryId == id select m;return View("Category", movies);}} }

對(duì)于每一個(gè)用戶(hù)控件,我們將會(huì)需要?jiǎng)?chuàng)建一個(gè)額外的抽象類(lèi)。對(duì)于FeaturedMovies 用戶(hù)控件,我們將會(huì)創(chuàng)建一個(gè)HomeControllerFeatured 類(lèi)(見(jiàn)Listing 9)。對(duì)于PopularMovies 用戶(hù)控件,我們將會(huì)創(chuàng)建一個(gè)HomeControllerPopular 類(lèi)(見(jiàn)Listing 10)。

Listing 9 – HomeControllerFeatured.cs

using System.Web.Mvc;namespace Solution4.Controllers.Home {public abstract class HomeControllerFeatured : HomeControllerBase{public override ActionResult Index(){var result = (ViewResult)base.Index();Partials.Featured.AddViewData(result.ViewData);return result;}} }

?

Listing 10 – HomeControllerPopular.cs

using System.Web.Mvc;namespace Solution4.Controllers.Home {public abstract class HomeControllerPopular : HomeControllerFeatured{public override System.Web.Mvc.ActionResult Category(int id){var result = (ViewResult)base.Category(id);Partials.Popular.AddViewData(result.ViewData);return result;}} }

最后,我們需要添加這個(gè)層次關(guān)系的最上面一個(gè)類(lèi)。我們將會(huì)創(chuàng)建一個(gè)HomeController 類(lèi)。這個(gè)類(lèi)簡(jiǎn)單的繼承自上面的其中一個(gè)基類(lèi)(見(jiàn)Listing 11)。他本身并不包含應(yīng)用邏輯。

HomeController 類(lèi)這個(gè)層次關(guān)系中的唯一一個(gè)不是抽象類(lèi)的。由于它不是抽象類(lèi),他的controller actions 可以被全世界調(diào)用(its controller actions can be invoked by the world)。

Listing 11 – HomeController.cs

namespace Solution4.Controllers.Home {public class HomeController : HomeControllerPopular{} }

現(xiàn)在,你或許會(huì)受不了這么多的類(lèi)。然而,這個(gè)解決方案的優(yōu)點(diǎn)是我們已經(jīng)很干凈的分離了建造view data 的邏輯。每一個(gè)抽象類(lèi)都具有單一的責(zé)任。我們的代碼不再脆弱。

Summary

我并完全信服我自己的Tip。我仍然在嘗試這通過(guò)使用action filter 來(lái)為我的master pages 和 user controls 添加view data。描述的最后一個(gè)解決,使用抽象基類(lèi),好像需要大量工作。我很好奇于這個(gè)問(wèn)題的其他的解決方案。

轉(zhuǎn)載于:https://www.cnblogs.com/QLeelulu/archive/2008/08/17/1269599.html

總結(jié)

以上是生活随笔為你收集整理的ASP.NET MVC Tip #31: 给 Master Pages 和 User Controls 传递数据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。