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

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

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

      ASP.NET MVC 4 (九) 模型綁定

      模型綁定指的是MVC從瀏覽器發送的HTTP請求中為我們創建.NET對象,在HTTP請求和C#間起著橋梁的作用。模型綁定的一個最簡單的例子是帶參數的控制器action方法,比如我們注冊這樣的路徑映射:

      routes.MapRoute( 
      name: "Default", 
      url: "{controller}/{action}/{id}", 
      defaults: new { controller = "Home", action = "Index", 
      id = UrlParameter.Optional } 
      ); 

      控制器Home的Index action帶有名為id的參數:

      public ActionResult Index(int id) { 
      Person dataItem = personData.Where(p => p.PersonId == id).First(); 
      return View(dataItem); 
      } 

      在我們請求URL“/Home/Index/1”時,默認action調用器ControllerActionInvoker使用模型綁定器為參數id賦值“1”。

      默認模型綁定器

      模型綁定器實現IModelBinder接口,MVC默認的模型綁定器類名為DefaultModelBinder。它從Request.form、RouteData.Values 、Request.QueryString、Request.Files查找參數值,比如上面例子中的參數id,它在下面路徑中搜索:

      1.  Request.Form["id"]
      2.  RouteData.Values["id"]
      3.  Request.QueryString["id"]
      4.  Request.Files["id"]

      模型綁定器使用參數的名稱搜索可用值,一旦找到一個可以結果搜索即停止。

      DefaultModelBinder在參數綁定中同時做類型變換,如果類型轉換失敗,參數綁定也失敗,比如我們請求URL “/Home/Index/apple”會得到int類型不能null的錯誤,模型綁定器無法將apple轉換成整數,視圖將null賦值給id引發此錯誤。我們可以定義id參數為int?,這也只能解決部分問題,在Index方法內我們沒有檢查id為null的情況,我們可以使用默認參數來徹底解決:

      ... 
      public ActionResult Index(int id = 1) { 
      Person dataItem = personData.Where(p => p.PersonId == id).First(); 
      return View(dataItem); 
      } 
      ... 

      實際的應用中我們還需要驗證綁定的參數值,比如URL  /Home/Index/-1和 /Home/Index/500都可以成功綁定數值到id,但他們超過了集合的上下限。在類型轉換時還必須注意文化語言差異,比如日期格式,我們可以使用語言無關的通用格式yyyy-mm-dd。

      復雜類型的綁定

      上面我們看到的都是綁定到簡單c#類型的例子,如果要綁定的模型是類則要復雜的多。以下面的Model類為例:

       public class Person {
              public int PersonId { get; set; }
              public string FirstName { get; set; }
              public string LastName { get; set; }
              public DateTime BirthDate { get; set; }
              public Address HomeAddress { get; set; }
              public bool IsApproved { get; set; }
              public Role Role { get; set; }
          }
      
          public class Address {
              public string Line1 { get; set; }
              public string Line2 { get; set; }
              public string City { get; set; }
              public string PostalCode { get; set; }
              public string Country { get; set; }
          }
      
          public enum Role {
              Admin,
              User,
              Guest
          }

      創建兩個CreatePerson控制器action來獲取數據:

      public ActionResult CreatePerson() { 
        return View(new Person()); 
      } 
      [HttpPost] 
      public ActionResult CreatePerson(Person model) { 
        return View("Index", model); 
      } 

      這里的action方法參數為復雜類型Person,我們使用Html.EditorFor()幫助函數在視圖中創建輸入數據的HTML:

      @model MvcModels.Models.Person
      @{
          ViewBag.Title = "CreatePerson";
      }
      <h2>Create Person</h2>
      @using (Html.BeginForm())
      {
          <div>@Html.LabelFor(m => m.PersonId)@Html.EditorFor(m => m.PersonId)</div>
          <div>@Html.LabelFor(m => m.FirstName)@Html.EditorFor(m => m.FirstName)</div>
          <div>@Html.LabelFor(m => m.LastName)@Html.EditorFor(m => m.LastName)</div>
          <div>@Html.LabelFor(m => m.Role)@Html.EditorFor(m => m.Role)</div>
          <div>
              @Html.LabelFor(m => m.HomeAddress.City)
              @Html.EditorFor(m => m.HomeAddress.City)
          </div>
          <div>
              @Html.LabelFor(m => m.HomeAddress.Country)
              @Html.EditorFor(m => m.HomeAddress.Country)
          </div>
          <button type="submit">Submit</button>
      } 

      使用強類型的EditFor函數能保證生成的HTML元素Name包含模型綁定需要的嵌套前綴,比如HomeAddress.Country,生成的HTML為:

      ... 
      <input class="text-box single-line" id="HomeAddress_Country" name="HomeAddress.Country" type="text" value="" /> 
      ... 

      自定義綁定名稱前綴

      有這樣一種情況,我們根據一個對象類型生成HTML,但是希望結果綁定到另外一個對象類型,我們可以通過自定義綁定前綴來實現。比如我們的Model類:

      public class AddressSummary { 
      public string City { get; set; } 
      public string Country { get; set; } 
      } 

      定義一個控制器方法來使用這個Model:

      public ActionResult DisplaySummary(AddressSummary summary) { 
      return View(summary); 
      } 

      對應的DisplaySummary.cshtml視圖也使用這個Model類:

      @model MvcModels.Models.AddressSummary 
      @{ 
      ViewBag.Title = "DisplaySummary"; 
      } 
      <h2>Address Summary</h2> 
      <div><label>City:</label>@Html.DisplayFor(m => m.City)</div> 
      <div><label>Country:</label>@Html.DisplayFor(m => m.Country)</div> 

      如果我們從上面編輯Person的視圖CreatePerson.cshtml提交到DisplaySummary action:

      @model MvcModels.Models.Person
      @{
          ViewBag.Title = "CreatePerson";
      }
      <h2>Create Person</h2>
      @using(Html.BeginForm("DisplaySummary", "Home")) {
          <div>@Html.LabelFor(m => m.PersonId)@Html.EditorFor(m=>m.PersonId)</div>
          <div>@Html.LabelFor(m => m.FirstName)@Html.EditorFor(m=>m.FirstName)</div>
          <div>@Html.LabelFor(m => m.LastName)@Html.EditorFor(m=>m.LastName)</div>
          <div>@Html.LabelFor(m => m.Role)@Html.EditorFor(m=>m.Role)</div>
          <div>
              @Html.LabelFor(m => m.HomeAddress.City)
              @Html.EditorFor(m=> m.HomeAddress.City)
          </div>
          <div>
              @Html.LabelFor(m => m.HomeAddress.Country)
              @Html.EditorFor(m=> m.HomeAddress.Country)
          </div>    
          <button type="submit">Submit</button>
      }

      DisplaySummary視圖中將無法正確綁定City和Country,因為CreatePerson中City和Country的input元素名稱包含HomeAddress前綴,提交的數據是HomeAddress.City和HomeAddress.Country,而DisplaySummary視圖中是不需要這個前綴的。我們可以在控制器方法上通過Bind特性指定綁定前綴來修正:

      public ActionResult DisplaySummary([Bind(Prefix="HomeAddress")]AddressSummary summary) {
                  return View(summary);
              }

      在Bind特性中我們還可以指定哪個屬性不要綁定,比如:

      public ActionResult DisplaySummary([Bind(Prefix="HomeAddress", Exclude="Country")]AddressSummary summary) {
                  return View(summary);
              }

      這里通過Exclude="Country"禁止Country屬性的綁定,與此相對,可以通過Include來指定需要綁定的屬性。Bind可以應用在單個action方法上,如果需要更大范圍的效果,我們可以直接應用在模型類上:

      [Bind(Include="City")]
          public class AddressSummary {
              public string City { get; set; }
              public string Country { get; set; }
          }

      Bind可以同時應用在Model類和action方法上,一個屬性只有在兩個地方都沒有被排除才會包含在綁定結果中。

      綁定到數組和集合

      DefaultModelBinder支持數組集合的綁定,比如下面的action方法使用數組作為參數:

      public ActionResult Names(string[] names) { 
      names = names ?? new string[0]; 
      return View(names); 
      } 

      視圖中我們創建一組同名的input元素:

      @model string[]
      @{
          ViewBag.Title = "Names";
      }
      <h2>Names</h2>
      @if (Model.Length == 0) {
          using(Html.BeginForm()) {
              for (int i = 0; i < 3; i++) {
                  <div><label>@(i + 1):</label>@Html.TextBox("names")</div>
              }
              <button type="submit">Submit</button>
          }
      } else {
          foreach (string str in Model) {
              <p>@str</p>
          }
          @Html.ActionLink("Back", "Names");
      }

      生成的HTML:

      ... 
      <form action="/Home/Names" method="post"> 
      <div><label>1:</label><input id="names" name="names"type="text" value="" /></div> 
      <div><label>2:</label><input id="names" name="names"type="text" value="" /></div> 
      <div><label>3:</label><input id="names" name="names"type="text" value="" /></div> 
      <button type="submit">Submit</button> 
      </form> 
      ...

      提交數據時綁定器從多個names構建一個數組。

      上面的例子換成集合是這樣的:

      public ActionResult Names(IList<string> names) {
                  names = names ?? new List<string>();
                  return View(names);
              }

      視圖:

      @model IList<string>
      @{
          ViewBag.Title = "Names";
      }
      <h2>Names</h2>
      @if (Model.Count == 0) {
          using(Html.BeginForm()) {
              for (int i = 0; i < 3; i++) {
                  <div><label>@(i + 1):</label>@Html.TextBox("names")</div>
              }
              <button type="submit">Submit</button>
          }
      } else {
          foreach (string str in Model) {
              <p>@str</p>
          }
          @Html.ActionLink("Back", "Names");
      }

      如果是要綁定到一個自定義Model類型的集合:

      public ActionResult Address(IList<AddressSummary> addresses) { 
      addresses = addresses ?? new List<AddressSummary>(); 
      return View(addresses); 
      } 

      視圖:

      @using MvcModels.Models
      @model IList<AddressSummary>
      @{
          ViewBag.Title = "Address";
      }
      <h2>Addresses</h2>
      @if (Model.Count() == 0) {
          using (Html.BeginForm()) {
              for (int i = 0; i < 3; i++) {
                  <fieldset>
                      <legend>Address @(i + 1)</legend>
                      <div><label>City:</label>@Html.Editor("[" + i + "].City")</div>
                      <div><label>Country:</label>@Html.Editor("[" + i + "].Country")</div>
                  </fieldset> 
              }
              <button type="submit">Submit</button>
          }
      } else {
          foreach (AddressSummary str in Model) {
              <p>@str.City, @str.Country</p>
          }
          @Html.ActionLink("Back", "Address");
      }

      生成的HTML表單:

      ... 
      <fieldset> 
      <legend>Address 1</legend> 
      <div> 
      <label>City:</label> 
      <input class="text-box single-line" name="[0].City"type="text" value="" /> 
      </div> 
      <div> 
      <label>Country:</label> 
      <input class="text-box single-line" name="[0].Country"type="text" value="" /> 
      </div> 
      </fieldset> 
      <fieldset> 
      <legend>Address 2</legend> 
      <div> 
      <label>City:</label> 
      <input class="text-box single-line" name="[1].City"type="text" value="" /> 
      </div> 
      <div> 
      <label>Country:</label> 
      <input class="text-box single-line" name="[1].Country"type="text" value="" /> 
      </div> 
      </fieldset> 
      ... 

      使用[0]、[1]作為輸入元素的名稱前綴,綁定器知道需要創建一個集合。

      手工調用模型綁定

      在請求action方法時MVC自動為我們處理模型綁定,但是我們也可以在代碼中手工綁定,這提供了額外的靈活性。我們調用控制器方法UpdateModel手工綁定:

      public ActionResult Address() { 
      IList<AddressSummary> addresses = new List<AddressSummary>(); 
      UpdateModel(addresses); 
      return View(addresses); 
      } 

      我們可以提供UpdateModel額外的參數指定要數據提供者:

      public ActionResult Address() { 
      IList<AddressSummary> addresses = new List<AddressSummary>(); 
      UpdateModel(addresses, new FormValueProvider(ControllerContext)); 
      return View(addresses); 
      } 

       參數FormValueProvider指定從Request.Form綁定數據,其他可用的Provider的還有RouteDataValueProvider(RouteData.Values)、QueryStringValueProvider(Request.QueryString)、HttpFileCollectionValueProvider(Request.Files),它們都實現IValueProvider接口,使用控制器類提供的ControllerContext作為構造函數參數。

      實際上最常用的限制綁定源的方式是:

      public ActionResult Address(FormCollection formData) { 
      IList<AddressSummary> addresses = new List<AddressSummary>(); 
      UpdateModel(addresses, formData); 
      return View(addresses); 
      } 

      FormCollection為表單數據的鍵值集合,這是UpdateModel眾多重載形式中的一種。

      手工數據綁定的另外一個好處是方便我們處理綁定錯誤:

      public ActionResult Address(FormCollection formData) { 
      IList<AddressSummary> addresses = new List<AddressSummary>(); 
      try { 
      UpdateModel(addresses, formData); 
      } catch (InvalidOperationException ex) { 
      // provide feedback to user 
      } 
      return View(addresses); 
      } 

      另外一種處理錯誤的方式是使用TryUpdateModel:

      public ActionResult Address(FormCollection formData) { 
      IList<AddressSummary> addresses = new List<AddressSummary>(); 
      if (TryUpdateModel(addresses, formData)) { 
      // proceed as normal 
      } else { 
      // provide feedback to user 
      } 
      return View(addresses); 
      } 

      自定義Value Provider

      除了上面看到的內建Value provider,我們可以從IValueProvider接口實現自定義的Value provider:

      namespace System.Web.Mvc { 
      public interface IValueProvider { 
      bool ContainsPrefix(string prefix); 
      ValueProviderResult GetValue(string key); 
      } 
      } 

      模型綁定器調用ContainsPrefix方法確定value provider是否可以處理提供的名稱前綴,GetValue根據傳入的鍵返回可用的參數值,如果沒有可用的數據返回null。下面用實例演示如何使用自定義value provider:

      public class CountryValueProvider : IValueProvider {
      
              public bool ContainsPrefix(string prefix) {
                  return prefix.ToLower().IndexOf("country") > -1;
              }
      
              public ValueProviderResult GetValue(string key) {
                  if (ContainsPrefix(key)) {
                      return new ValueProviderResult("USA", "USA", CultureInfo.InvariantCulture);
                  } else {
                      return null;
                  }
              }
          }

      CountryValueProvider處理任何包含country的屬性,對所有包含country名稱的屬性總是返回“USA”。使用自定義value provider之前還需要創建一個工廠類來創建自動那個有value provider的實例:

      public class CustomValueProviderFactory : ValueProviderFactory {
      
              public override IValueProvider GetValueProvider(ControllerContext controllerContext) {
                  return new CountryValueProvider();
              }
          }

      最后把我們的類工廠在global.asax的application_start中添加到value provider工廠列表中:

      public class MvcApplication : System.Web.HttpApplication {
              protected void Application_Start() {
                  AreaRegistration.RegisterAllAreas();
      
                  ValueProviderFactories.Factories.Insert(0, new CustomValueProviderFactory());
      
                  WebApiConfig.Register(GlobalConfiguration.Configuration);
                  FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                  RouteConfig.RegisterRoutes(RouteTable.Routes);
                  BundleConfig.RegisterBundles(BundleTable.Bundles);
              }
          }

      這里使用ValueProviderFactories.Factories.Insert()將自定義的value provider工廠添加到列表首位以優先使用,當然也可以ValueProviderFactories.Factories.Add()添加到列表末尾。在注冊使用這個value provider后,任何對country屬性的綁定都會得到值USA。

      自定義模型綁定器

      除了自定義value provider,我們還可以從IModelBinder接口創建自定義的模型綁定器:

      public class AddressSummaryBinder : IModelBinder {
      
              public object BindModel(ControllerContext controllerContext,  ModelBindingContext bindingContext) {
      
                  AddressSummary model = (AddressSummary)bindingContext.Model ?? new AddressSummary();
                  model.City = GetValue(bindingContext, "City");
                  model.Country = GetValue(bindingContext, "Country");
                  return model;
              }
      
              private string GetValue(ModelBindingContext context, string name) {
                  name = (context.ModelName == "" ? "" : context.ModelName + ".") + name;
      
                  ValueProviderResult result = context.ValueProvider.GetValue(name);
                  if (result == null || result.AttemptedValue == "") {
                      return "<Not Specified>";
                  } else {
                      return (string)result.AttemptedValue;
                  }
              }
      
          }

      MVC調用AddressSummaryBinder的BindModel()方法獲取模型類型的實例,這里簡單的初始化一個AddressSummary實例,調用value provider獲取對象屬性值,在從value provider獲取屬性值時我們把添加模型名稱ModelBindingContext.ModelName作為屬性的前綴。同樣,必須在application_start中注冊自定義模型綁定器后才能使用:

      ...
      ModelBinders.Binders.Add(typeof(AddressSummary), new AddressSummaryBinder());
      ...

      Dependency Injection和依賴解決器

      C#中使用接口可以幫助我們解耦構件, 獲取接口的實現我們通常是直接初始化接口的一個實現類:

      public class PasswordResetHelper { 
        public void ResetPassword() { 
          IEmailSender mySender = new MyEmailSender(); 
          //...call interface methods to configure e-mail details... 
          mySender.SendEmail(); 
          } 
      } 

      使用IEmailSender接口在一定程度上PasswordResetHelper不再要求發送郵件時需要一個具體的郵件發送類,但是直接初始化MyEmailSender使得PasswordResetHelper并沒有和MyEmailSender解耦開。我們可以把IEmailSender接口的初始化放到PasswordResetHelper的構造函數上來解決:

      public class PasswordResetHelper { 
        private IEmailSender emailSender; 
        public PasswordResetHelper(IEmailSender emailSenderParam) { 
          emailSender = emailSenderParam; 
        } 
        public void ResetPassword() { 
          // ...call interface methods to configure e-mail details... 
          emailSender.SendEmail(); 
        } 
      } 

      但這樣帶來的問題是如何獲取IEmailSender的實現呢?這可以通過運行時Dependency Injection機制來解決,在創建PasswordResetHelper實例時依賴解決器提供一個IEmailSender的實例給PasswordResetHelper構造函數,這種注入方式又稱為構造注入。依賴解決器又是怎么知道如何初始化接口的固實實現呢?答案是DI容器,通過在DI容器中注冊接口/虛類和對應的實現類將兩者聯系起來。當然DI不只是DI容器這么簡單,還必須考慮類型依賴鏈條、對象生命周期管理、構造函數參數配置等等問題,好在我們不需要編寫自己的容器,微軟提供自己的DI容器名為Unity(在nity.codeplex.com獲取),而開源的Ninject是個不錯的選擇。Ninject可以在visual studio中使用nuget包管理器獲取并安裝,下面就以實例演示如何使用Ninject,我們從接口的定義開始:

      using System.Collections.Generic;
      
      namespace EssentialTools.Models {
          public interface IValueCalculator {
      
              decimal ValueProducts(IEnumerable<Product> products);
          }
      }

      接口的一個類實現:

      using System.Collections.Generic;
      using System.Linq;
      
      namespace EssentialTools.Models {
      
          public class LinqValueCalculator : IValueCalculator {
              private IDiscountHelper discounter;
      
              public LinqValueCalculator(IDiscountHelper discounterParam) {
                  discounter = discounterParam;
              }
      
              public decimal ValueProducts(IEnumerable<Product> products) {
                  return  discounter.ApplyDiscount(products.Sum(p => p.Price));
              }
          }
      }

      我們創建一個使用Ninject的自定義依賴解決器:

      using System;
      using System.Collections.Generic;
      using System.Web.Mvc;
      using Ninject;
      using EssentialTools.Models;
      
      namespace EssentialTools.Infrastructure {
          public class NinjectDependencyResolver : IDependencyResolver {
              private IKernel kernel;
      
              public NinjectDependencyResolver() {
                  kernel = new StandardKernel();
                  AddBindings();
              }
      
              public object GetService(Type serviceType) {
                  return kernel.TryGet(serviceType);
              }
      
              public IEnumerable<object> GetServices(Type serviceType) {
                  return kernel.GetAll(serviceType);
              }
      
              private void AddBindings() {
                  kernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
      
              }
          }
      }

      這里最重要的是AddBindings方法中的kernel.Bind<IValueCalculator>().To<LinqValueCalculator>(),它將接口IValueCalculator和類實現LinqValueCalculator結合起來,在我們需要接口IValueCalculator的一個實例時,會調用NinjectDependencyResolver的GetService獲取到LinqValueCalculator的一個實例。要使NinjectDependencyResolver起作用還必須注冊它為應用默認的依賴解決器,這是在application_start中操作:

      public class MvcApplication : System.Web.HttpApplication {
              protected void Application_Start() {
                  AreaRegistration.RegisterAllAreas();
      
                  DependencyResolver.SetResolver(new NinjectDependencyResolver());
      
                  WebApiConfig.Register(GlobalConfiguration.Configuration);
                  FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                  RouteConfig.RegisterRoutes(RouteTable.Routes);
      
              }
          }

      控制器的構造函數中我們傳入接口IValueCalculator,依賴解決器會自動為我們創建一個LinqValueCalculator的實例:

      public class HomeController : Controller {
              private Product[] products = {
                  new Product {Name = "Kayak", Category = "Watersports", Price = 275M},
                  new Product {Name = "Lifejacket", Category = "Watersports", Price = 48.95M},
                  new Product {Name = "Soccer ball", Category = "Soccer", Price = 19.50M},
                  new Product {Name = "Corner flag", Category = "Soccer", Price = 34.95M}
              };
              private IValueCalculator calc;
      
              public HomeController(IValueCalculator calcParam) {
                  calc = calcParam;
              }
      
              public ActionResult Index() {
                  ShoppingCart cart = new ShoppingCart(calc) { Products = products };
      
                  decimal totalValue = cart.CalculateProductTotal();
      
                  return View(totalValue);            
              }
          }

       Ninject的綁定方法非常的靈活:

      kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 50M); //綁定時指定DefaultDiscountHelper的屬性DiscountSize=50
      kernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountParam", 50M);//綁定時指定DefaultDiscountHelper的構造函數參數discountParam=50
      kernel.Bind<IDiscountHelper>().To<FlexibleDiscountHelper>().WhenInjectedInto<LinqValueCalculator>();//條件綁定,在注入到LinqValueCalculator時綁定接口LinqValueCalculator到FlexibleDiscountHelper

      除了使用自定義的依賴解決器,我們可以從默認控制器工廠擴展控制器工廠,在自定義控制器工廠中使用Ninject依賴注入:

       public class NinjectControllerFactory : DefaultControllerFactory {
              private IKernel ninjectKernel;
      
              public NinjectControllerFactory() {
                  ninjectKernel = new StandardKernel();
                  AddBindings();
              }
      
              protected override IController GetControllerInstance(RequestContext 
                  requestContext, Type controllerType) {
      
                  return controllerType == null
                      ? null
                      : (IController)ninjectKernel.Get(controllerType);
              }
      
              private void AddBindings() {
                  ninjectKernel.Bind<IValueCalculator>().To<LinqValueCalculator>();
              }

      MVC在獲取控制器時調用GetControllerInstance,它使用ninjectKernel.Get(controllerType)來獲取相應的控制類實例,同時解決構造注入的問題,比如HomeController的構造函數參數IValueCalculator calcParam,使用這種方式可以限制僅在控制器內注入,控制器外整個應用范圍內我們仍然可以使用自定義依賴解決器注入。

      需要注意的是依賴解決和注入不是模型綁定的一部分,但它們有一定的相似性,后者解決的action方法上的參數綁定,前者可以說是整個控制器類(構造函數)上的參數綁定(當然不只是用在控制器類上)。

       

      以上為對《Apress Pro ASP.NET MVC 4》第四版相關內容的總結,不詳之處參見原版 http://www.apress.com/9781430242369。 

      posted @ 2016-09-02 22:26  閆寶平  閱讀(438)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 中文字幕日韩一区二区不卡| 亚洲国产在一区二区三区| 亚洲中文字幕人妻系列| 久久亚洲国产品一区二区| 国内不卡一区二区三区| 黑人好猛厉害爽受不了好大撑| 高清中文字幕国产精品| 暖暖 在线 日本 免费 中文| 岛国岛国免费v片在线观看| 大屁股国产白浆一二区| 亚洲国产在一区二区三区| 久久精品中文字幕少妇| 涩涩爱狼人亚洲一区在线| 久久人妻无码一区二区三区av| 人人妻人人狠人人爽天天综合网| 亚洲线精品一区二区三八戒| 妖精视频yjsp毛片永久| 日韩精品中文字幕亚洲| 亚洲精品成人一二三专区| 99热精品毛片全部国产无缓冲 | 国产超碰无码最新上传| 亚洲色成人网站www永久| 在线观看亚洲欧美日本| 日韩精品在线观看一二区| 日韩福利视频导航| 99精品国产综合久久久久五月天| 免费特黄夫妻生活片| 精品国产国语对白主播野战| 永久黄网站色视频免费直播| 久久综合亚洲鲁鲁九月天| 国产欧美综合在线观看第十页| 国产精品天天在线午夜更新| 亚洲五月天一区二区三区| 国产色无码专区在线观看| 1000部拍拍拍18勿入免费视频下载| 九九热精品视频在线免费| 久久―日本道色综合久久| 男女激情一区二区三区| 国产精品国产三级国av| h无码精品3d动漫在线观看| 国精偷拍一区二区三区|