【譯】ASP.NET MVC并不僅僅只是Linq to SQL

作者: CareySon  來源: 博客園  發布時間: 2010-03-04 10:14  閱讀: 4159 次  推薦: 0   原文鏈接   [收藏]  

  很多ASP.NET的教程中的示例代碼使用的數據訪問方法是Linq to Sql或是Entity Framework。我在www.asp.net的論壇上看到很多關于討論是否有其他替代的數據庫訪問方式,回答是:當然有。這篇文章就講述了使用Ado.Net作為數據訪問層來實現一個典型的增刪查改程序。

  由于是以練習作為目的,那我就不妨借用Spaanjaar’s 的N層構架文章(Building Layered Web Applications with Microsoft ASP.NET 2.0.)的構架方式。我強烈推薦你閱讀他的系列文章,如果嫌太長起碼也得看完前兩部分,這樣就能對N-Layer構架有個基本的認識。N-Layer構架的三個關鍵層分別為:業務對象層,業務邏輯層和數據訪問層。而其數據訪問層會幾乎不加改變的包含在本文的MVC項目中,Spaanjaar的文件詳細描述了各個層是如何組織的。這篇文章僅僅講述各個層所扮演的角色,但是不會深入到代碼的細節中。

  首先,我們來看Imar提供的程序,這是一個具有典型增刪查改的程序,這個程序允許用戶管理聯系人,包括聯系人的地址,電話,email。它能增,刪,查,改任何實體。

  程序內包括的實體有:ContactPersons, PhoneNumbers, Addresses EmailAddresses.他們都隸屬于程序的業務對象(BO)層。上述的每一個類都包含可以獲取或者賦值的屬性,但并不包含任何方法。而所有方法存放于業務邏輯層(BLL)中的對應類中。在業務對象層和業務邏輯層的實體和實體manger是一對一的關系,在業務邏輯層中類包含的方法都會返回業務對象層(BO)的實例,或是實例集合,或者保存實例(更新或是添加),或是刪除實例。業務邏輯層(BLL)中也可以包含一些業務規則驗證,安全性檢查的代碼。但在本篇文章為了簡便起見,就不添加這些了。如果你對業務規則和安全性有興趣的話,可以去看Imar文章的6 part series

  最后一層是數據訪問層(DAL),同樣,DAL層的類也和業務邏輯層(BLL)內的類有著一對一的關系,在BLL層的類中會調用相關DAL層中的方法。而在這些層中,只有DAL層需要知道利用什么技術(linq,entity framework..)保存業務實體。在本例中,使用Sql Server Express數據庫和Ado.net。而這樣分層的思想是如果你需要更換數據源(XML,oracle,更或者是Web Service甚至是Linq to Sql或者其他ORM框架),因為DAL層給BLL層暴漏的方法的簽名是一致的,所以只需要更換DAL層即可。而為了保證所有DAL的實現有著同樣的簽名,則利用接口即可。但我想或許是未來帖子中討論的話題了吧。

  MVC構架

  已經有很多優秀的文章中已經探討了MVC程序的構架,所以本篇文章就不再累述相關細節了。如果想要了解更多,我推薦訪問Asp.net MVC官方站點.簡單二代說,M代表Model,也是包含BO,BLL,DAL的地方,V代表View,也是UI相關開發的部分,或者說是用戶看到的部分,C是Controller的簡寫,也是控制用戶請求與程序回復的部分。如果用戶點擊了一個指向特定地址的按鈕,請求會和Controller的Action(類的方法)進行匹配,而Action負責處理請求,并返回響應。通常情況下是一個新的View,或者是更新現有的View。

  下面用Visual Studio創建一個MVC應用程序并刪除默認的View和Controller,然后將Imar的程序中的Bo,Bll和DAL復制到這個MVC程序的Model內,我還復制了響應的數據庫文件和Style.css。

  我還做了一些其他的修改,把數據庫連接字符串添加到Web.Config中。除此之外,我還將復制過來的代碼的命名空間做了響應的調整并把DAL層的代碼升級到了3.0.雖然這并不是必須的。做完這些,我按Ctrl+Shift+F5來測試是否編譯成功。------------------

  Controller

  我添加了4個Controller(Visual Studio附帶的默認Controller已經被刪除),和四個實體類相匹配。它們分別為:ContactController, PhoneController, AddressController and EmailController。

  每個Controller都含有四個Action:List, Add, Edit and Delete。首先需要在Global.exe中為這些Action注冊這些路由。

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  routes.MapRoute(
      "Default",                                              
      "{controller}/{action}/{id}",                           
      new { controller = "Contact", action = "List", id = " " }  
  );
}


  默認的View會顯示所有聯系人,BLL層中的ContactPersonManager類內的GetList()方法會獲取所有聯系人的數據,響應的List() Action代碼如下:

public ActionResult List()
{
  var model = ContactPersonManager.GetList();
  return View(model);
}

  強類型View

  整個實例代碼中,我都會使用強類型的View,因為這樣不僅可以使用intellisense(智能提示)的好處,還不必依賴于使用String作為索引值的ViewData。為了讓代碼更加有序,我添加了一些命名空間到web.config中的節點,這些都是我用來替換Imar代碼的方式:

namespace="System.Web.Mvc"/>
namespace="System.Web.Mvc.Ajax"/>
namespace="System.Web.Mvc.Html"/>
namespace="System.Web.Routing"/>
namespace="System.Linq"/>
namespace="System.Collections.Generic"/>
namespace="ContactManagerMVC.Views.ViewModels"/>
namespace="ContactManagerMVC.Models.BusinessObject"/>
namespace="ContactManagerMVC.Models.BusinessObject.Collections"/>
namespace="ContactManagerMVC.Models.BusinessLogic"/>
namespace="ContactManagerMVC.Models.DataAccess"/>
namespace="ContactManagerMVC.Models.Enums"/>

  上面代碼意味著我可以在程序的任何地方訪問上述命名空間。上面GetList()方法返回的類型是ContactPersonList,這個類型是ContactPerson對象的集合,在顯示List的View中的Page聲明如下:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
    Inherits="System.Web.Mvc.ViewPage<ContactPersonList>" %>

  我想你已經注意到了我使用了MasterPage,利用MasterPage,我借用了從Imar實例代碼中的Css文件。用于顯示ContactPerson對象的HTML如下:

<table class="table">
    <tr>
      <th scope="col">Idth>
      <th scope="col">Full Nameth>
      <th scope="col">Date of Birthth>
      <th scope="col">Typeth>
      <th scope="col"> th>
      <th scope="col"> th>
      <th scope="col"> th>
      <th scope="col"> th>
      <th scope="col"> th>  
    tr>
    <%
      if (Model != null)
      {
        foreach (var person in Model)
        {%>
    <tr>
      <td><%= person.Id %>td>
      <td><%= person.FullName %>td>
      <td><%= person.DateOfBirth.ToString("d") %>td>
      <td><%= person.Type %>td>
      <td title="address/list" class="link">Addressestd>
      <td title="email/list" class="link">Emailtd>
      <td title="phone/list" class="link">Phone Numberstd>
      <td title="contact/edit" class="link">Edittd>
      <td title="contact/delete" class="link">Deletetd>
    tr>
    <%
        }
      }else{%>
    <tr>
      <td colspan="9">No Contacts Yettd>
    tr>  
     <% }%>
  table>

   我想你已經能發現強類型View的好處了吧,Model的類型是ContactPersonList,所以你可以任意使用ContactPersonList的屬性而不用強制轉換,而強制轉換錯誤只有在運行時才能被發現,所以這樣省了不少事。

 在做Html時,我小小的作弊了一下,我本可以使用vs對list自動生成的view,但我沒有。因為我需要和Imar的css文件相匹配的html.所以我運行了imar的程序,在瀏覽器中查看源代碼,并把生成的html復制下來,imar使用GridView來生成列表,所以CSS會在運行時嵌入到html代碼中。我將這些css代碼移到一個外部的css文件中。并給   元素添加了一些額外樣式,你可以在代碼的下載鏈接中找到。

  我還未一些表格的單元格添加了title屬性。這些包含了訪問其他action的鏈接。我希望用戶在瀏覽電話本或者編輯或者刪除電話本時頁面不會post back,換句話說,我希望我的網站是ajax的。而title屬性就發揮作用了。而“。link”這個css選擇符可以讓普通的文本看起來像超鏈接,也就是有下劃線和鼠標hover時出現小手。

  jQuery AJax

    在我們深入實現ajax功能的相關代碼之前,下面3行代碼是需要加入到html中:

button" id="addContact" name="addContact" value="Add Contact" />
details">
dialog" title="Confirmation Required">Are you sure about this?

  第一行代碼的作用是一個允許用戶添加新聯系人的按鈕,第二行代碼是一個空div,方便后面顯示信息,第三行代碼是jQuery modal 提示驗證對話框的一部分,用于提示用戶是否刪除一條記錄。

     還需要在頁面中添加3個js文件,第一個是主要的jQuery文件,其他兩個分別是jQuery UI的核心js,以及date picker和modal dialog部分的js

  下面是我們生成后的列表顯示視圖以及完全的js代碼:

 

  上面代碼看起來讓人望而卻步,但實際上,使用jQuery,這非常簡單。并且在上面代碼中我多處加入了注釋,代碼一開始是用js代碼是替換了數據源控件默認呈現出來的隔行變色的顏色。然后我加入了使點擊行點擊時可以變色的代碼。然后下面的代碼是防止IE對頁面進行緩存。如果不禁止了IE緩存,你會為執行編輯或者刪除以后,數據庫改變了但頁面卻沒有發生變化而撞墻的。

  接下來的代碼更有趣了,依靠live()方法可以確$選擇器中所有匹配的元素都被附加了相應的事件,無論元素當前是否存在于頁面中。比如說,當你點擊了Addresses鏈接,相應的結果就會在另一個表中出現:

  上圖中可以看出表中包含編輯和刪除鏈接,如果不使用live()方法,相應的鏈接就不會被附加事件。所有具有class為link的元素都會被委派上click事件。這個事件會首先獲取到當前條目的id.以ContactPerson表為例,這個id就是ContactPersonId.在相應的子表中,則id會是電話號碼或者是email地址。這些都是需要傳遞給controller action作為參數進行編輯,刪除,或者顯示的。

  你現在可以看出為什么我為每個單元格加上title屬性了吧。title屬性包含相關的route信息,而完全的url則把id附加到route作為url.然后,上面js會做一個檢查,來看route信息內是否包含delete,如果包含delelte,則彈出一個對話框來提示用戶是否要刪除。看,是不是很簡單?

  最后,代碼會為添加聯系人按鈕添加click事件,在文章的下部分我們再進行討論

  添加聯系人以及自定義View Models

  使用Asp.net添加一條記錄時,通常的做法是提供一個包含一系列輸入框的form.對于ContactPerson類的大多屬性來說,都是可以直接賦值的,比如:姓,名字,生日。但是其中有一個屬性卻不能直接賦值--Type屬性,這個值是從PersonType.cs(朋友,同事等)中的枚舉類型中選擇出來的.這意味著用戶只能從有限的幾種選項中選擇一種。可以用DropDwonList來實現,但是ContactPerson對象并不包含枚舉類型的所有選項,所以我們只能提供一個自定義版本的ContactPerson類傳遞給View.這也是為什么要用到自定義View Model

我看過很多關于在程序的哪里放置View Models的討論,有些人認為自定義View Models是Model的一部分,但是我認為它和View緊密相關,View Models并不是MVC程序必不可少的一部分,也不能服用,所以它不應該放到Model中區。我把所有的View Model放入一個創建的ViewModel文件夾下,ContactPersonViewModel.cs的源代碼如下:

using System;
using System.Collections.Generic;
using System.Web.Mvc;

namespace ContactManagerMVC.Views.ViewModels
{
  public class ContactPersonViewModel
  {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public IEnumerable Type { get; set; }
  }
}

  看上面類的最后一個屬性,我將這個type屬性設置成IEnumerable類型,這樣就可以將Type綁定到View中的Html.DropDownList了。

  對應的,也要在Controller中添加2個action,第一個action使用AcceptVerbs(HttpVerbs.Get)標簽,第二個action使用AcceptVerbs(HttpVerbs.Post)標簽,第一個方法用于從服務器向客戶端傳值,第一個方法處理從form提交的數據。

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Add()
{
  var personTypes = Enum.GetValues(typeof (PersonType))
    .Cast()
    .Select(p => new
                   {
                     ID = p, Name = p.ToString()
                   });
  var model = new ContactPersonViewModel
                {
                  Type = new SelectList(personTypes, "ID", "Name")
                };
  return PartialView(model);
}


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(ContactPerson person)
{
  ContactPersonManager.Save(person);
  return RedirectToAction("List");
}

  上面第一個action的前幾行代碼將ContactType枚舉類型轉換成數組,數組中的每一個元素都是一個包含id和name屬性的匿名對象,id是枚舉值,Name是和對應枚舉匹配的constant值,ContactPersonViewModel然后進行初始化并且Type屬性被賦值相應的類型。我使用Partial View來添加聯系人和使用ContactPersonViewModel類型的強類型,對應View部分的代碼如下:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<script type="text/javascript">
  $(function() {
  $('#DateOfBirth').datepicker({ dateFormat: 'yy/mm/dd' });
  });
script>

<% using (Html.BeginForm("Add", "Contact", FormMethod.Post)) {%>
      <table>
        <tr>
          <td class="LabelCell">Nametd>
          <td><%= Html.TextBox("FirstName") %>td>
        tr>
        <tr>
          <td class="LabelCell">Middle Nametd>
          <td><%= Html.TextBox("MiddleName") %>td>
        tr>
        <tr>v
          <td class="LabelCell">Last Nametd>
          <td><%= Html.TextBox("LastName") %>td>
        tr>
        <tr>
          <td class="LabelCell">Date of Birthtd>
          <td><%= Html.TextBox("DateOfBirth", String.Empty)%>td>
        tr>
        <tr>
          <td class="LabelCell">Typetd>
          <td><%=Html.DropDownList("Type")%>
          td>
        tr>
        <tr>
          <td class="LabelCell">td>
          <td><input type="submit" name="submit" id="submit" value="Save" />td>
        tr>
      table>
<% } %>

  在最上面的代碼我使用了jQuery UI的Date picker插件作為DateOfBirth輸入框的選擇方式,而DateOfBirth的第二個參數保證這個textbox在初始狀態下為空。此外,所有的輸入框對ContactPerson的對應屬性名相同,這是為了確保默認的model binder不出差錯,MVC還自動為ContactType枚舉進行綁定。

  負責響應Post請求的方法可以自動將Request.Form的值和ContactPerson對象的對應屬性進行匹配,然后調用BLL層的Save()方法,然后RedicrectToAction會讓頁面刷新最后調用List這個action.

  編輯一個聯系人

  和前邊一樣,需要在Controller添加兩個action來完成編輯,一個用于響應Get請求,另一個用于響應Post請求:

[AcceptVerbs(HttpVerbs.Get)]
    public ActionResult Edit(int id)
    {
      var personTypes = Enum.GetValues(typeof (PersonType))
        .Cast()
        .Select(p => new { ID = p, Name = p.ToString() });

      var contactPerson = ContactPersonManager.GetItem(id);
      var model = new ContactPersonViewModel
                    { 
                      Id = id,
                      FirstName = contactPerson.FirstName,
                      MiddleName = contactPerson.MiddleName,
                      LastName = contactPerson.LastName,
                      DateOfBirth = contactPerson.DateOfBirth,
                      Type = new SelectList(personTypes, "ID", "Name", contactPerson.Type)
                    };
      return PartialView(model);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(ContactPerson person)
    {
      ContactPersonManager.Save(person);
      return RedirectToAction("List");
    }
     

  我們在前面已經看到jQuery是如何調用Edit這個action并把被編輯人的id作為參數進行傳遞的了,然后id用于通過眾所周知的bll調用DAL從數據庫將聯系人的詳細信息取出來。在這個過程中ContactPersonViewModel被創建來返回從數據庫取出的值,SelectList的通過三個參數構造,第一個參數是Person的類型,第三個參數是DropDownList當前選擇的值

partial view的代碼和Add View幾乎一樣:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<script type="text/javascript">
  $(function() {
    $('#DateOfBirth').datepicker({dateFormat: 'yy/mm/dd'});
  });
script>

<% using (Html.BeginForm("Edit", "Contact", FormMethod.Post)) {%> 
     <table>
        <tr>
          <td class="LabelCell">Nametd>
          <td><%= Html.TextBox("FirstName") %>td>
        tr>
        <tr>
          <td class="LabelCell">Middle Nametd>
          <td><%= Html.TextBox("MiddleName") %>td>
        tr>
        <tr>
          <td class="LabelCell">Last Nametd>
          <td><%= Html.TextBox("LastName") %>td>
        tr>
        <tr>
          <td class="LabelCell">Date of Birthtd>
          <td><%= Html.TextBox("DateOfBirth", Model.DateOfBirth.ToString("yyyy/MM/dd")) %>td>
        tr>
        <tr>
          <td class="LabelCell">Typetd>
          <td><%= Html.DropDownList("Type")%>td>
        tr>
        <tr>
          <td class="LabelCell"><%= Html.Hidden("Id") %>td>
          <td><input type="submit" name="submit" id="submit" value="Save" />td>
        tr>
      table>
<% } %>

  關鍵不同是DateOfBirth包含一個將生日信息轉換更容易識別的方式,還有在提交按鈕附近添加了一個Html.Hidden(),用于保存被編輯用戶的id。當然,form的action屬性肯定是和Add的View不同。在Form中可以加一個參數用于告訴Action是Add View還是Edit View,這樣就能減少代碼的重復,但是在示例代碼中我還是把他們分成了不同的action,來讓職責劃分的更清晰一些。

  刪除一個聯系人

  刪除action就簡單多了,并且不需要與之相關的View.僅僅是重新調用List這個action,被刪除的數據就不復存在了。

public ActionResult Delete(int id)
{
  ContactPersonManager.Delete(id);
  return RedirectToAction("List");
}

  上面代碼是我對BLL和DAL做出改變的地方,原來的ContactPersonManager.Delete()方法的參數是Person的實例,而在DAL中,只有id作為參數。我看不出傳遞整個對象給BLL,但BLL卻只傳遞對象的唯一ID給DAL的意義所在,所以我將BLL的代碼改成接受int類型的參數,這樣寫起來會更簡單。

  當刪除鏈接被點擊時,調用jQuery的confirmation modal dialog:

  如果點擊取消,則什么事也不發生,如果點擊確認,則鏈接就會指向響應的delete action.

  管理集合

  所有的集合--PhoneNumberList,EmailAddressLIst,AddressList被管理的方式如出一轍。所以,我僅僅挑選EmailAddressLIst作為示例來說明方法,你可以下載示例代碼來看其他部分。

  首先,我們來看顯示被選擇聯系人的email地址,這包含了controller中List這個Action:

public ActionResult List(int id)
{
  var model = new EmailAddressListViewModel
                {
                  EmailAddresses = EmailAddressManager.GetList(id),
                  ContactPersonId = id
                };
  return PartialView(model);
}

  上面方法使用聯系人的id作為聯系人,并且返回一個自定義View Model—EmailAddressListViewModel.這也是將聯系人的id傳到View的方法:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script type="text/javascript">
  $(function() {
    $('#add').click(function() {
      $.get('Email/Add/<%= Model.ContactPersonId %>', function(data) {
        $('#details').html(data);
      });
    });
  });
script>
<table class="table">
   <tr>
     <th scope="col">Contact Person Idth>
     <th scope="col">Emailth>
     <th scope="col">Typeth>
     <th scope="col"> th>
     <th scope="col"> th>
   tr>
   <%if(Model.EmailAddresses != null)
     {foreach (var email in Model.EmailAddresses) {%>
   <tr>
     <td><%= email.Id %>td>
     <td><%= email.Email %>td>
     <td><%= email.Type %>td>
     <td title="email/edit" class="link">Edittd>
     <td title="email/delete" class="link">Deletetd>
   tr>
        <%}
    }else
 {%>
   <tr>
     <td colspan="9">No email addresses for this contacttd>
   tr>
 <%}%>
table>
<input type="button" name="add" value="Add Email" id="add" />

  你可以看出添加方法需要ContactPersonID作為參數,我們需要確保可以添加新的聯系人到響應的聯系人列表。編輯和刪除方法也是如此--id參數通過url傳遞到相關action.而所有的單元格都有title屬性,這樣就可以使用前面部署的live()方法:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Add(int id)
{
  var contactTypes = Enum.GetValues(typeof(ContactType))
    .Cast()
    .Select(c => new
    {
      Id = c,
      Name = c.ToString()
    });
  var model = new EmailAddressViewModel
                {
                  ContactPersonId = id,
                  Type = new SelectList(contactTypes, "ID", "Name")
                };
  return PartialView("Add", model);
}


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(EmailAddress emailAddress)
{
  emailAddress.Id = -1;
  EmailAddressManager.Save(emailAddress);
  return RedirectToAction("List", new {id = emailAddress.ContactPersonId});
}

  創建自定義View Model存在的目的是為了對現有的EmailAddress進行添加或編輯,這包括一些綁定IEnumerable集合到Type dropdown的屬性,上面兩個Add不同之處在于他們的返回不同,第一個返回partial view,第二個返回List這個action.

  集合中的每一個選在在一開始都會將id設為-1,這是為了保證符合”Upsert”存儲過程的要求,因為Imar對于添加和刪除使用的是同一個存儲過程,如果不設置成-1,則當前新建的聯系人會更新掉數據庫中的聯系人。如果你想了解更多,請看他的文章。下面是添加email address的partial view:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<script type="text/javascript">
  $(function() {
    $('#save').click(function() {
      $.ajax({
        type: "POST",
        url: $("#AddEmail").attr('action'),
        data: $("#AddEmail").serialize(),
        dataType: "text/plain",
        success: function(response) {
          $("#details").html(response);
        }
      });
    });
  });
script>

<% using(Html.BeginForm("Add", "Email", FormMethod.Post, new { id = "AddEmail" })) {%>
<table class="table">
<tr>
  <td>Email:td>
  <td><%= Html.TextBox("Email")%>td>
tr>
<tr>
  <td>Type:td>
  <td><%= Html.DropDownList("Type") %>td>
tr>
<tr>
  <td><%= Html.Hidden("ContactPersonId") %>td>
  <td><input type="button" name="save" id="save" value="Save" />td>
tr>
table>
<% } %>

  上面jQuery代碼負責通過Ajax提交form.jQuery給html button(而不是input type=”submit”)附加事件,然后將頁面中的內容序列化并通過post 請求發送到使用合適AcceptVerbs標簽修飾的名為add()的action.

  編輯和刪除EmailAddress對象

  編輯EmailAddress對象所涉及的action和前面提到的很相似,仍然是兩個action,一個用于處理get請求,另一個用于處理post請求:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Edit(int id)
{
  var emailAddress = EmailAddressManager.GetItem(id);
  var contactTypes = Enum.GetValues(typeof(ContactType))
    .Cast()
    .Select(c => new
    {
      Id = c,
      Name = c.ToString()
    });
  var model = new EmailAddressViewModel
  {
    Type = new SelectList(contactTypes, "ID", "Name", emailAddress.Type),
    Email = emailAddress.Email,
    ContactPersonId = emailAddress.ContactPersonId,
    Id = emailAddress.Id
  };
  return View(model);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(EmailAddress emailAddress)
{
  EmailAddressManager.Save(emailAddress);
  return RedirectToAction("List", "Email", new { id = emailAddress.ContactPersonId });
}

  下面的partial View代碼現在應該很熟悉了吧:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<script type="text/javascript">
  $(function() {
    $('#save').click(function() {
      $.ajax({
        type: "POST",
        url: $("#EditEmail").attr('action'),
        data: $("#EditEmail").serialize(),
        dataType: "text/plain",
        success: function(response) {
          $("#details").html(response);
        }
      });
    });
  });
script>

<% using(Html.BeginForm("Edit", "Email", FormMethod.Post, new { id = "EditEmail" })) {%>
<table class="table">
<tr>
  <td>Email:td>
  <td><%= Html.TextBox("Email")%>td>
tr>
<tr>
  <td>Type:td>
  <td><%= Html.DropDownList("Type") %>td>
tr>
<tr>
  <td><%= Html.Hidden("ContactPersonId") %><%= Html.Hidden("Id") %>td>
  <td><input type="button" name="save" id="save" value="Save" />td>
tr>
table>

 

  上面代碼仍然和Add View很像,除了包含EmailAddress.Id的html隱藏域,這是為了保證正確的email地址被更新,而Delete action就不用過多解釋了吧。

public ActionResult Delete(int id)
{
  EmailAddressManager.Delete(id);
  return RedirectToAction("List", "Contact");
}

 總結

  這篇練習的目的是為了證明Asp.net MVC在沒有Linq To Sql和Entity framework的情況下依然可以很完美的使用。文章使用了現有分層結構良好的Asp.net 2.0 form程序,還有可重用的,business Objects層,bussiness logic層以及Data Access 層。而DAL層使用Ado.net調用Sql Server的存儲過程來實現。

  順帶的,我還展示了如何使用強類型的View Models和簡潔的jQuery來讓UI體驗更上一層。這個程序并不是完美的,也不是用于真實世界。程序中View部分,以及混合編輯和刪除的action都還有很大的空間可以重構提升,程序還缺少驗證用戶輸入的手段,所有的刪除操作都會返回頁面本身。而更好的情況應該是顯示刪除后用一個子表來顯示刪除后的內容,這需要將ContactPersonId作為參數傳遞到相關action,這也是很好實現的。

---------------------------------------------------

原文鏈接:http://www.mikesdotnetting.com/Article/132/ASP.NET-MVC-is-not-all-about-Linq-to-SQL

translated by CareySon

0
0
 
標簽:MVC
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()