<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      從零開始學習 ASP.NET MVC 1.0 (四) View/Model 全解

      《從零開始學習ASP.NET MVC 1.0》 文章導航

       

      一.摘要

      本文講解在Action中向View傳遞Model的幾種方式.以及View獲取Model以后如何編寫顯示邏輯.還詳細的介紹了ASP.NET MVC框架提供的Html Helper類的使用及如何為Html Helper類添加自定義擴展方法.

      二.承上啟下

      上一篇文章中我們學習了Controller處理一次請求的全過程.在Controller的Action中, 會傳遞數據給View,還會通知View對象開始顯示.所以Model是在Action中獲取的, 并由Action傳遞給View. View對象接到Action通知后會使用自己的顯示邏輯展示頁面.

      image

      下面首先讓我們學習如何將Model傳遞給View對象.

      三.傳遞數據給View

      在MVC中,Model對象是指包含了數據的模型. Controller將Model傳遞給View以后, View對象中不應該做任何的業務邏輯處理, 僅僅根據Model對象做一些顯示邏輯的處理.

      傳遞Model對象時, 我們有兩種選擇:

      1.傳遞一個弱類型的集合, 即成員為object類型的集合,  在View中需要將每個成員轉換成我們需要的類型,比如int, string,自定義類型等.

      2.傳遞強類型對象, 這些類型是我們自定義的. 在View中直接使用我們傳遞的強類型對象, 不需要再轉換類型.

      如果讓我們自己設計一個MVC框架, 我們也會想到上面兩種實現方式,接下來看看在ASP.NET MVC中的實現.

      1.傳遞弱類型的集合

      (1) 如何傳遞

      ASP.NET MVC框架定義了ViewContext類, 直譯后是"View上下文", 其中保存和View有關的所有數據, 其中Model對象也封裝在了此類型中.

      ViewContext對象包含三個屬性:

      • IView View
      • ViewDataDictionary ViewData
      • TempDataDictionary TempData

      其中ViewData集合和TempData集合都是用來保存Model對象的.在一個Controller的Action中, 我們可以用如下方式為這兩個集合賦值:

              /// <summary>
              /// 傳遞弱類型Model的Action示例
              /// </summary>
              /// <returns>ViewResult</returns>
              public ActionResult WeakTypedDemo()
              {
                  ViewData["model"] = "Weak Type Data in ViewData";
                  TempData["model"] = "Weak Type Data in TempData";
                  return View("WeakTypedDemo");
              }

       

      在頁面中, 是用如下方式使用這兩個集合:

          <div>
              <% = ViewData["model"] %><br />
              <% = TempData["model"] %><br />
          </div>

       

      (2) 傳遞過程

      請注意Action中的賦值語句實際上操作的是Controller類的ViewData和TempData屬性, 此時并沒有任何的數據傳遞.上一篇文章中我們已經學到, return View語句會返回一個ViewResult對象, 并且接下來要執行ViewResult的Executeresult方法. Controller的View方法會將Controller類的ViewData和TempData屬性值傳遞給ViewResult,代碼如下:

              protected internal virtual ViewResult View(IView view, object model) {
                  if (model != null) {
                      ViewData.Model = model;
                  }
      
                  return new ViewResult {
                      View = view,
                      ViewData = ViewData,
                      TempData = TempData
                  };
              }

      然后在ViewResult中根據ViewData和TempData構建ViewContext對象:

              public override void ExecuteResult(ControllerContext context) {
                //...
                  ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
                  View.Render(viewContext, context.HttpContext.Response.Output);
                //...
              }

       

      ViewContext對象最終會傳遞給ViewPage, 也就是說ViewData和TempData集合傳遞到了ViewPage. 我這里簡化了最后的傳遞流程, 實際上ViewData對象并不是通過ViewContext傳遞到ViewPage中的, ViewPage上的ViewData是一個單獨的屬性, 并沒有像TempData一樣其實訪問的是ViewContext.TempData. 這么做容易產生奇異, 本類ViewContext是一個很好理解職責十分清晰的類. 作為使用者的我們暫時可以忽略這點不足, 因為如此實現ViewData完全是為了下面使用強類型對象.

      (3)ViewData和TempData的區別

      雖然ViewData和TempData都可以傳遞弱類型數據,但是兩者的使用是有區別的:

      • ViewData的生命周期和View相同, 只對當前View有效.
      • TempData保存在Session中, Controller每次執行請求的時候會從Session中獲取TempData并刪除Session, 獲取完TempData數據后雖然保存在內部的字典對象中,但是TempData集合的每個條目訪問一次后就從字典表中刪除. 也就是說TempData的數據至多只能經過一次Controller傳遞.

      (4) TempData的實現

      TempData的類型是TempDataDictionary, 和一般的字典表沒有明顯的不同, TempData的生命周期是由Controll決定的.

      在所有Controll的基類ControllerBase中, 創建了類型為TempDataDictionary的TempData屬性.

      在ControllerBase的派生類Controller中, 重寫了ExecuteCore()方法:

              protected override void ExecuteCore() {
                  TempData.Load(ControllerContext, TempDataProvider);
      
                  try {
                      string actionName = RouteData.GetRequiredString("action");
                      if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
                          HandleUnknownAction(actionName);
                      }
                  }
                  finally {
                      TempData.Save(ControllerContext, TempDataProvider);
                  }
              }

      注意其中的TempData.Load和TempData.Save語句.

      TempDataDictionary.Load用來從ControllerContext總讀取TempData的數據.

      TempDataDictionary.Save方法將發生了變化的TempData數據保存到ControllerContext中.

      這兩個方法都需要傳遞ITempDataProvider實例負責具體的讀取和保存操作. 在Controll中默認的TempDataProvider是SessionStateTempDataProvider, 也就是說讀取和保存都使用Session. 我們也可以擴展自己的TempDataProvider, 可以將臨時數據保存在任何地方.比如制作AspNetCacheTempDataProvider使用機器本地緩存來保存TempData.

      為何TempData只能夠在Controll中傳遞一次? 因為SessionStateTempDataProvider.LoadTempData方法(在TempDataDictionary.Load中調用)在從ControllerContext的Session中讀取了TempData數據后, 會清空Session:

              public virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext) {
                  HttpContextBase httpContext = controllerContext.HttpContext;
                  
                  if (httpContext.Session == null) {
                      throw new InvalidOperationException(MvcResources.SessionStateTempDataProvider_SessionStateDisabled);
                  }
      
                  Dictionary<string, object> tempDataDictionary = httpContext.Session[TempDataSessionStateKey] as Dictionary<string, object>;
      
                  if (tempDataDictionary != null) {
                      // If we got it from Session, remove it so that no other request gets it
                      httpContext.Session.Remove(TempDataSessionStateKey);
                      return tempDataDictionary;
                  }
                  else {
                      return new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                  }
              }

      注意上面加粗的部分. 一旦讀取成功, 就會刪除TempData的Session.

      再回憶一下Controll的ExecuteCore方法,  是在Controll的Execute方法中調用的, 是每一次Controll一定會執行的方法, 所以我們得出了"只能在Controll之間傳遞一次"的結論.

       

       

      2.傳遞強類型對象

      我在系統中建立了一個模型類:StrongTypedDemoDTO

      從名字可以看出, 這個模型類是數據傳輸時使用的(Data Transfer Object).而且是我為一個View單獨創建的.

      添加一個傳遞強類型Model的Action,使用如下代碼:

              public ActionResult StrongTypedDemo()
              {
                  StrongTypedDemoDTO model = new StrongTypedDemoDTO() { UserName="ziqiu.zhang", UserPassword="123456" };
                  return View(model);
              }

      使用了Controller.View()方法的一個重載, 將model對象傳遞給View對象.下面省略此對象的傳輸過程, 先讓我們來看看如何在View中使用此對象.

      在創建一個View時, 會彈出下面的彈出框:

      image

      勾選"Create a strongly-typed view"即表示要創建一個強類型的View, 在"View data class"中選擇我們的數據模型類.

      在"view content"中如下選項:

      image

      這里是選擇我們的View的"模板", 不同的模板會生成不同的View頁面代碼. 雖然這些代碼不一定滿足我們需要, 但是有時候的確能節省一些時間,尤其是在寫文章做Demo的時候. 比如我們的View是添加數據使用的,那就選擇"Create".如果是顯示一條數據用的, 就選擇"Detail".

      以選擇Detail為例, 自動生成了下列代碼:

      <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<DemoRC.Models.DTO.TransferModelController.StrongTypedDemoDTO>" %>
      ...
      <body>
          <fieldset>
              <legend>Fields</legend>
              <p>
                  UserName: 
                  <%= Html.Encode(Model.UserName) %>
              </p>
              <p>
                  UserPassword: 
                  <%= Html.Encode(Model.UserPassword) %>
              </p>
          </fieldset>
          <p>
              <%=Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) %> |
              <%=Html.ActionLink("Back to List", "Index") %>
          </p>
      </body>
      ...

      頁面的Model屬性就是一個強類型對象, 在這里就是StrongTypedDemoDTO類實例.page頁面指令可以看出, 這里的頁面繼承自ViewPage<T>類, 而不是ViewPage, 用T已經確定為StrongTypedDemoDTO類型, 所以Model的類型就是StrongTypedDemoDTO.

      3.傳遞數據的思考

      使用強類型數據要優于弱類型數據, 老趙也曾提出過. 強類型有太多的好處, 智能提示, 語意明確, 提高性能,編譯時發現錯誤等等.

      所以在實際應用中, 我們應該傳遞強類型的數據.

      目前ASP.NET MVC還存在一些不足. 將頁面類型化,  導致了只能傳遞一種數據類型實例到頁面上. 而且內部代碼的實現上并不十分完美.尤其是雖然我們已經知道傳遞的是StrongTypedDemoDTO類型, 頁面的Model屬性也是StrongTypedDemoDTO類型, 但是仍然需要進行強制類型轉換, 原因是Controller的View(object model)方法重載接收的是一個object類型.

      還有, 為每個View建立一個模型類, 也是一件繁瑣的工作. 也許我們的業務模型中的兩個類組合在一起就是View頁面需要的數據, 但是卻不得不建立一個類將其封裝起來.模型類的膨脹也是需要控制一個事情. 尤其是對于互諒網應用而非企業內部的系統, 頁面往往會有成百上千個.而且復用較少.

      當然目前來說既然要使用強類型的Model, 我提出一些組織Model類型的實踐方法.下面是我項目中的Model類型組織結構:

      image

      這里Model是一個文件夾, 稍大一些的系統可以建立一個Model項目. 另外我們需要建立一個DTO文件夾, 用來區分Model的類型. MVC中的Model應該對應DTO文件夾中的類.在DTO中按照Controller再建立文件夾, 因為Action和View大部分都是按照Controller組織的, 所以Model也應該按照Controller組織.

      在Controller文件夾里放置具體的Model類. 其實兩個Controller文件夾中可以同相同的類名稱, 我們通過命名空間區分同名的Model類:

      namespace DemoRC.Models.DTO.TransferModelController
      {
          /// <summary>
          /// Action為StrongTypedDemo的數據傳輸模型
          /// </summary>
          public class StrongTypedDemoDTO
          {
              /// <summary>
              /// 用戶名
              /// </summary>
              public string UserName
              {
                  get;
                  set;
              }
      
              /// <summary>
              /// 用戶密碼
              /// </summary>
              public string UserPassword
              {
                  get;
                  set;
              }
          }
      }

      使用時也要通過帶有Controller的命名空間使用比如DTO.TransferModelController.StrongTypedDemoDTO, 或者建立一些自己的約定.

      四.使用Model輸出頁面

      View對象獲取了Model以后, 我們可以通過兩種方式使用數據:

      1.使用內嵌代碼

      熟悉ASP,PHP等頁面語言的人都會很熟悉這種直接在頁面上書寫代碼的方式.但是在View中應該只書寫和顯示邏輯有關的代碼,而不要增加任何的業務邏輯代碼.

      假設我們創建了下面這個Action,為ViewData添加了三條記錄:

              /// <summary>
              /// Action示例:使用內嵌代碼輸出ViewData
              /// </summary>
              /// <returns></returns>
              public ActionResult ShowModelWithInsideCodeDemo()
              {
                  ViewData["k1"] = @"<script type=""text/javascript"">";
                  ViewData["k2"] = @"alert(""Hello ASP.NET MVC !"");";
                  ViewData["k3"] = @"</script>";
                  return View("ShowModelWithInsideCode");
              }

      在ShowModelWithInsideCode中, 我們可以通過內嵌代碼的方式, 遍歷ViewData集合:

      <html xmlns="http://www.w3.org/1999/xhtml" >
      <head runat="server">
          <title>使用內嵌代碼輸出ViewData</title>
          <% foreach(KeyValuePair<string, object> item in ViewData )
             {%>
                  <% = item.Value %>
          <% } %>    
      </head>
      <body>
          <div>
          
              <div>此頁面運行的腳本代碼為:</div>
              <fieldset>       
              <% foreach(KeyValuePair<string, object> item in ViewData )
                 {%>
                     <% = Html.Encode(item.Value) %> <br />
              <%  } %>
              </fieldset> 
          </div>
      </body>
      </html>

      頁面上遍歷了兩遍ViewData,第一次是作為腳本輸出的, 第二次由于進行了HTML編碼,所以將作為文字顯示在頁面上.

      使用這種方式, 我們可以美工做好的HTML頁面的動態部分, 使用<% %>的形式轉化為編碼區域, 通過程序控制輸出.由于只剩下顯示邏輯要處理,所以這種開發方式往往要比CodeBehind的編碼方式更有效率, 維護起來一目了然.

      最讓我高興是使用這種方式后,我們終于可以只使用HTML控件了.雖然ASP.NET WebFrom編程模型中自帶了很多服務器控件, 功能很好很強大, 但是那終究是別人開發的控件, 這些控件是可以隨意變化的, 而且實現原理也對使用者封閉. 使用原始的頁面模型和HTML控件將使我們真正的做程序的主人.而且不會因為明天服務器控件換了個用法就要更新知識, 要知道幾乎所有的HTML控件幾乎是被所有瀏覽器支持且不會輕易改變的.

      2.使用服務器控件

      注意雖然我們同樣可以在ASP.NET MVC中使用服務器端控件, 但是在MVC中這并不是一個好的使用方式.建議不要使用.

      要使用服務器端控件, 我們就需要在后臺代碼中為控件綁定數據. ASP.NET MVC框架提供的添加一個View對象的方法已經不能創建后臺代碼, 也就是說已經摒棄了這種方式.但是我們仍然可以自己添加.

      首先創建一個帶有后臺代碼的(.cs文件),一般的Web Form頁面(aspx頁面),然后修改頁面的繼承關系, 改為繼承自ViewPage:

      public partial class ShowModelWithControl : System.Web.Mvc.ViewPage

       

      在頁面上放置一個Repeater控件用來顯示數據:

      <body>
          <form id="form1" runat="server">
          <div>
              <asp:Repeater ID="rptView" runat="server">
                  <ItemTemplate>
                      <%# ((KeyValuePair<string, object>)Container.DataItem).Value  %><br />
                  </ItemTemplate>
              </asp:Repeater>
          </div>
          </form>
      </body>

      在Page_Load方法中, 為Repeater綁定數據:

          public partial class ShowModelWithControl : System.Web.Mvc.ViewPage
          {
              protected void Page_Load(object sender, EventArgs e)
              {
                  rptView.DataSource = ViewData;
                  rptView.DataBind();
              }
          }

      在Controller中創建Action, 為ViewData賦值:

              /// <summary>
              /// Action示例:使用服務器控件輸出ViewData
              /// </summary>
              /// <returns></returns>
              public ActionResult ShowModelWithControlDemo()
              {
                  ViewData["k1"] = @"This";
                  ViewData["k2"] = @"is";
                  ViewData["k3"] = @"a";
                  ViewData["k4"] = @"page";
                  return View("ShowModelWithControl");
              }

      運行結果:

      image

      再次強調,  在ASP.NET MVC中我們應該盡量避免使用這種方式.

      3.使用 HTML Helper 類生成HTML控件

      HTML Helper類是ASP.NET MVC框架中提供的生成HTML控件代碼的類. 本質上與第一種方式一樣, 只是我們可以不必手工書寫HTML代碼,而是借助HTML Helper類中的方法幫助我們生成HTML控件代碼.

      同時,我們也可以使用擴展方法為HTML Helper類添加自定義的生成控件的方法.

      HTML Helper類的大部分方法都是返回一個HTML控件的完整字符串, 所以可以直接在需要調用的地方使用<% =Html.ActionLink() %>的形式輸出字符串.

      (1)ASP.NET MVC中的HtmlHelper類

      在ViewPage中提供了Html屬性, 這就是一個HtmlHelper類的實例. ASP.NET MVC框架自帶了下面這些方法:

      • Html.ActionLink()
      • Html.BeginForm()
      • Html.CheckBox()
      • Html.DropDownList()
      • Html.EndForm()
      • Html.Hidden()
      • Html.ListBox()
      • Html.Password()
      • Html.RadioButton()
      • Html.TextArea()
      • Html.TextBox()

      上面列舉的常用的HtmlHelper類的方法,并不是完整列表.

      下面的例子演示如何使用HtmlHelper類:

          <div>
              <% using (Html.BeginForm())
                 { %>
                 <label style="width:60px;display:inline-block;">用戶名:</label>
                 <% =Html.TextBox("UserName", "ziqiu.zhang", new { style="width:200px;" })%>
                 <br /><br /> 
                 <label style="width:60px;display:inline-block;">密碼:</label>
                 <% =Html.Password("Psssword", "123456", new { style = "width:200px;" })%>                     
              <% }%>
          </div>

      上面的代碼使用Html.BeginForm輸出一個表單對象, 并在表單對象中添加了兩個Input, 一個使用Html.TextBox輸出, 另一個使用Html.Password輸出,區別是Html.Password輸出的input控件的type類型為password.效果如圖:

      image

      (2)擴展Html Helper類

      我們可以自己擴展HtmlHelper類, 為HtmlHelper類添加新的擴展方法, 從而實現更多的功能.

      在項目中建立Extensions文件夾, 在其中創建SpanExtensions.cs文件.源代碼如下:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Web;
      using System.Web.Mvc;
      
      
      namespace System.Web.Mvc
      {
          public static class SpanExtensions
          {
              public static string Span(this HtmlHelper helper,string id, string text)
              {
                  return String.Format(@"<span id=""{0}"">{1}</span>", id, text);
              }
          }
      }

      上面的代碼我們為HtmlHelper類添加了一個Span()方法, 能夠返回一個Span的完整HTML字符串.

      因為命名空間是System.Web.Mvc,所以頁面使用的時候不需要再做修改,Visual Studio會自動識別出來:

      image

      請大家一定要注意命名空間, 如果不使用System.Web.Mvc命名空間, 那么一定要在頁面上引用你的擴展方法所在的命名空間, 否則我們的擴展方法將不會被識別.

      接下來在頁面上可以使用我們的擴展方法:

          <div>
              <!-- 使用自定義的Span方法擴展HTML Helper -->
              <% =Html.Span("textSpan", "使用自定義的Span方法擴展HtmlHelper類生成的Span") %>
          </div>

       

      (3) 使用TagBuilder類創建擴展方法

      上面自定義的Span()方法十分簡單, 但是有時候我們要構造具有復雜結構的Html元素, 如果用字符串拼接的方法就有些笨拙.

      ASP.NET MVC框架提供了一個幫助我們構造Html元素的類:TagBuilder

      TagBuilder類有如下方法幫助我們構建Html控件字符串:

      方法名稱 用途
      AddCssClass() 添加class=””屬性
      GenerateId() 添加Id,  會將Id名稱中的"."替換為IdAttributeDotReplacement 屬性值的字符.默認替換成"_"
      MergeAttribute() 添加一個屬性,有多種重載方法.
      SetInnerText() 設置標簽內容, 如果標簽中沒有再嵌套標簽,則與設置InnerHTML 屬性獲得的效果相同.
      ToString() 輸出Html標簽的字符串, 帶有一個參數的重載可以設置標簽的輸出形式為以下枚舉值:
      • TagRenderMode.Normal -- 有開始和結束標簽
      • TagRenderMode.StartTag -- 只有開始標簽
      • TagRenderMode.EndTag -- 只有結尾標簽
      • TagRenderMode.SelfClosing -- 單標簽形式,如<br/>

      同時一個TagBuilder還有下列關鍵屬性:

      屬性名稱 用途
      Attributes Tag的所有屬性
      IdAttributeDotReplacement 添加Id時替換"."的目標字符
      InnerHTML Tag的內部HTML內容
      TagName Html標簽名, TagBuilder只有帶一個參數-TagName的構造函數.所以TagName是必填屬性


      下面在添加一個自定義的HtmlHelper類擴展方法,同樣是輸出一個<Span>標簽:

              public static string Span(this HtmlHelper helper, string id, string text, string css, object htmlAttributes)
              {
                  //創意某一個Tag的TagBuilder
                  var builder = new TagBuilder("span");
      
                  //創建Id,注意要先設置IdAttributeDotReplacement屬性后再執行GenerateId方法.
                  builder.IdAttributeDotReplacement = "-";
                  builder.GenerateId(id);
                  
      
                  //添加屬性            
                  builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
      
                  //添加樣式
                  builder.AddCssClass(css);
                  //或者用下面這句的形式也可以: builder.MergeAttribute("class", css);
      
                  //添加內容,以下兩種方式均可
                  //builder.InnerHtml = text;
                  builder.SetInnerText(text);
      
                  //輸出控件
                  return builder.ToString(TagRenderMode.Normal);
      
              }

      在頁面上,調用這個方法:

      <% =Html.Span("span.test", "使用TagBuilder幫助構建擴展方法", "ColorRed", new { style="font-size:15px;" })%>

      生成的Html代碼為:

      <span id="span-test" class="ColorRed" style="font-size: 15px;">使用TagBuilder幫助構建擴展方法</span>


      注意已經將id中的"."替換為了"-"字符.

      五.總結

      本來打算在本文中直接將ViewEngine的使用也加進來, 但是感覺本文已經寫了很長的內容, (雖然不多,但是很長......)所以將ViewEngine作為下一章單獨介紹.

      前些天 Scott Guthrie's的博客上放出了"ASP.NET MVC免費教程", 里面介紹了創建一名為"NerdDinner"項目的全過程, 使用LINQ+ASP.NET MVC, 但是其中對于技術細節沒有詳細介紹(和本系列文章比較一下就能明顯感覺出來), 下面提供本書的pdf文件下載地址以及源代碼下載地址:

      image

    3. 免費下載PDF版本
    4. 下載應用源碼 + 單元測試

       

      源代碼是英文版本,  其實我最近有做一個中文的"Nerd Dinner"的想法, 但是因為要寫文章而且還要工作已經讓我焦頭爛額, 寫文章真的是一件體力活.如果有人同樣有興趣翻譯代碼, 我可以提供域名和服務器空間.

      差點提供忘記本篇文章的示例源代碼下載:

      https://files.cnblogs.com/zhangziqiu/AspNet-Mvc-4-Demo.rar

    5. posted @ 2009-03-18 00:15  ziqiu.zhang  閱讀(44091)  評論(65)    收藏  舉報
      主站蜘蛛池模板: 亚洲精品一区二区妖精| 国产成人精品一区二三区在线观看| 无码人妻久久一区二区三区app| 国产影片AV级毛片特别刺激| 陕西省| 亚洲一区二区三区自拍天堂| 无码人妻精品一区二区三区下载| 国产仑乱无码内谢| 亚洲国产成熟视频在线多多| 久草热久草热线频97精品| 国产精品一二区在线观看| 欧美牲交a欧美牲交aⅴ免费真| 久久午夜私人影院| 青海省| 亚洲一本二区偷拍精品| 亚洲男人的天堂久久香蕉| 色综合色国产热无码一| 少妇人妻偷人精品无码视频| 久久人人妻人人爽人人爽| 天堂网在线.www天堂在线资源| 成人做爰www网站视频| 亚洲a人片在线观看网址| 国产剧情91精品蜜臀一区| 日韩人妻少妇一区二区三区| 99精品国产一区二区三区| 国内精品久久久久影院薰衣草| 衣服被扒开强摸双乳18禁网站| 亚洲第一狼人成人综合网| 一区二区中文字幕av| 亚洲综合黄色的在线观看| 中文字字幕在线中文乱码| 人人妻人人做人人爽夜欢视频| 国内精品久久黄色三级乱| 黄色三级亚洲男人的天堂| 狠狠躁夜夜躁人人爽天天5| 人人妻人人爽人人澡av| 国产精品午夜福利片国产| 手机看片AV永久免费| 国产成人无码免费视频在线| 国产短视频精品一区二区| 久久久av男人的天堂|