ASP.NET MVC學習之模型綁定(2)


 

3.手工調用模型綁定

很多情況下我們都是通過形參的方式接收來自http流中的數據,這看似是完美的,但是缺少了很多過程中的控制,所以我們就需要使用手工的方式進行綁定。下面我們通過一個例子來說明,首先打開Views/Home/Index.cshtml頁面,並輸入如下代碼:

 1 @{
 2     ViewBag.Title = "Index";
 3 }
 4 
 5 @if (TempData.ContainsKey("msg"))
 6 {
 7     <h1>
 8         @TempData["msg"].ToString()
 9     </h1>
10 }
11 
12 @using (Html.BeginForm())
13 {
14     <input type="text" name="id" />
15     <input type="submit" value="submit" />
16 }

 

 

接着打開HomeController並寫入如下代碼(關於ActionName可以點擊這進行參考):

 1 namespace MvcStudy.Controllers
 2 {
 3     public class HomeController : Controller
 4     {
 5         private class TestA
 6         {
 7             public String id { get; set; }
 8         }
 9 
10         public ActionResult Index()
11         {
12             return View();
13         }
14 
15         [HttpPost]
16         [ActionName("Index")]
17         public ActionResult IndexPost()
18         {
19             TestA ta = new TestA();
20             UpdateModel(ta);
21             TempData["msg"] = ta.id;
22             return View();
23         }
24     }
25 }

 

 

這里我們通過UpdateModel進行手動綁定,最終的結果和采用形參的方式相同,讀者可以進行測試可以發現輸入的值都顯示了,但是讀者一定會奇怪,因為TestA中的id不僅僅存在於表單,同時還存在與RouteData中以及查詢字符串中,我們可以用?id=123來測試這個頁面可以發現並不會修改最終結果,而通過手動調用模型綁定的優點之一就是我們可以控制數據來源,比如我們修改HomeController代碼如下所示:

1         [HttpPost]
2         [ActionName("Index")]
3         public ActionResult IndexPost()
4         {
5             TestA ta = new TestA();
6             UpdateModel(ta,new FormValueProvider(ControllerContext));
7             TempData["msg"] = ta.id;
8             return View();
9         }

 

 

這里我們可以發現我們給UpdateModel傳遞了第二個參數,FormValueProvider這表示數據源只能來自於表單中,同樣我們還可以修改成RouteDataValueProvider或者QueryStringValueProvider,具體的效果讀者你自行替換之后,輸入http://localhost:1201/Home/Index/123?id=asdsad測試,可以看看最后顯示的內容是不是來自於我們指定的來源。再使用形參的方式中我們有時會遇到http流中不存在我們需要的值,並且這個形參的類型不能為null,或者我們不希望它為null,這個時候就會出現異常或者賦值為null,而通過UpdateModel則可以通過try…catch…的形式捕獲InvalidOperationException異常從而手動處理,如果讀者不希望通過這種方式也可以像下面這種形式來處理:

1             if (TryUpdateModel(ta, new QueryStringValueProvider(ControllerContext)))
2             {
3                 //正確時的操作
4             }
5             else
6             {
7                 //異常時的操作
8             }

這樣我們只要通過if判斷即可。

 

4.自定義值提供器

通過上面的我們發現ASP.NET MVC自帶的模型綁定器已經提供了很多我們所需要的功能,但是有時候我們想某些值不是來自於http流中而是我們自己來填充的,那么這節知識會讓你感興趣,因為下面我們將要自定義一個值提供器來完成我們的需求。首先介紹需要用的接口和類,首先是IValueProvider接口:

 1 namespace System.Web.Mvc
 2 {
 3     // 摘要:
 4     //     定義 ASP.NET MVC 中的值提供程序所需的方法。
 5     public interface IValueProvider
 6     {
 7         // 摘要:
 8         //     確定集合是否包含指定的前綴。
 9         //
10         // 參數:
11         //   prefix:
12         //     要搜索的前綴。
13         //
14         // 返回結果:
15         //     如果集合包含指定的前綴,則為 true;否則為 false。
16         bool ContainsPrefix(string prefix);
17         //
18         // 摘要:
19         //     使用指定鍵來檢索值對象。
20         //
21         // 參數:
22         //   key:
23         //     要檢索的值對象的鍵。
24         //
25         // 返回結果:
26         //     指定的鍵的值對象。
27         ValueProviderResult GetValue(string key);
28     }
29 }
View Code

 

其中ContainsPrefix用來判斷這個值的前綴是不是我們能夠處理的(因為ASP.NET MVC其實自帶了很多這種值提供器,最后會通過循環調用的方式調用這些提供器,直到有一個返回值。)然后就是GetValue方法就是返回對應的值了,當然光有這個還不夠,還需要一個工廠去創建它,以提供調用,這個類就是ValueProviderFactory,而我們僅僅只需要實現GetValueProvider方法即可,其實就是new一個值提供器並返回,當然你也可以通過這個方法的ControllerContext從而有選擇性的返回一個值提供器,下面我們簡單的舉一個例子來處理ns

 

首先我們創建一個Provider文件夾,然后新建一個NSValueProvider類並在文件中寫入如下代碼:

 1 namespace MvcStudy.Provider
 2 {
 3     public class NSValueProvider : IValueProvider
 4     {
 5 
 6         public bool ContainsPrefix(string prefix)
 7         {
 8             return String.Compare("ns", prefix, true) == 0;
 9         }
10 
11         public ValueProviderResult GetValue(string key)
12         {
13             if (ContainsPrefix(key))
14             {
15                 return new ValueProviderResult("from ns", null, CultureInfo.InvariantCulture);
16             }
17             return null;
18         }
19     }
20 
21     public class NSValueProviderFactory : ValueProviderFactory
22     {
23         public override IValueProvider GetValueProvider(ControllerContext controllerContext)
24         {
25             return new NSValueProvider();
26         }
27     }
28 }

 

 

最后打開Global.asax將它注冊:

1 ValueProviderFactories.Factories.Insert(0, new NSValueProviderFactory());

 

 

最后我們需要修改HomeController以便能夠看到結果:

1         public ActionResult Index(string ns)
2         {
3             TempData["msg"] = ns;
4             return View();
5         }

 

 

重新編譯之后刷新頁面我們就可以看到如下的結果:

 

這樣我們就完成了一個值提供器了,看到這個讀者一定會想模型提供器怎么去自定義呢,其實模型綁定器就是依靠這些值提供器完成的,大家想想就可以明白了。

 

5.模型綁定器

模型綁定器跟值提供器很相似,只是需要做的工作比較多,因為你要負責將一個類的屬性填充,所以比較麻煩。下面是需要實現的接口IModelBinder:

 1 namespace System.Web.Mvc
 2 {
 3     // 摘要:
 4     //     定義模型聯編程序所需的方法。
 5     public interface IModelBinder
 6     {
 7         // 摘要:
 8         //     使用指定的控制器上下文和綁定上下文將模型綁定到一個值。
 9         //
10         // 參數:
11         //   controllerContext:
12         //     控制器上下文。
13         //
14         //   bindingContext:
15         //     綁定上下文。
16         //
17         // 返回結果:
18         //     綁定值。
19         object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
20     }
21 }

 

 

這里重點是bindingContext參數,里面包含了很多綁定所需要的值和方法,下面我們舉一個簡單的例子,就是自定義一個模型綁定器負責綁定如下類:

1         public class TestA
2         {
3             public String id { get; set; }
4         }

 

 

同時還要規定只能通過namens.id獲取值,並不會根據參數的名稱去獲取,下面就是我們實現接口的代碼:

 1 namespace MvcStudy.Provider
 2 {
 3     public class NSModelBinder : IModelBinder
 4     {
 5 
 6         public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
 7         {
 8             TestA a = (TestA)bindingContext.Model ?? new TestA();
 9             bool isHave = bindingContext.ValueProvider.ContainsPrefix("ns.id");
10             if (isHave)
11             {
12                 a.id = bindingContext.ValueProvider.GetValue("ns.id").AttemptedValue;
13             }
14             else
15             {
16                 a.id = "asd";
17             }
18             return a;
19         }
20     }
21 }

 

 

最后一步當然還是需要注冊(Global.asax):

1 ModelBinders.Binders.Add(typeof(MvcStudy.Controllers.HomeController.TestA), new NSModelBinder());

 

 

然后我們重新編譯,並在頁面中輸入值並提交,可以發現TestAid並不是我們輸入的值而是模型綁定器中的值,但是如果我們將Views/Home/Index.cshtml中的文本框的name改成ns.id之后,我們再輸入值,最后顯示的就是我們輸入的值了,由此可以看出來模型綁定器是依賴於值提供器的。

 

至此關於模型綁定的部分就結束了,下面我們將開始學習模型驗證。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM