在ASP.NET Core處理模型有兩個核心的概念
模型綁定分為基礎和高級分別兩篇,在這節中,我們學習關于模型綁定處理的細節
我們通過一個例子來了解模型綁定的概念,在Visual Studio 2022 中創建一個ASP.NET Core Web App (Model-View-Controller) 項目,名稱為AspNetCore.ModelBinding
Models & Repository
在Models文件夾下添加一個新的類叫EmployeeDetails.cs,這定義了2個兩個類和一個枚舉:
namespace AspNetCore.ModelBinding.Models
{
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime DOB { get; set; }
public Address HomeAddress { get; set; }
public Role Role { get; set; }
}
public class Address
{
public string HouseNumber { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
public enum Role
{
Admin,
Designer,
Manager
}
}
namespace AspNetCore.ModelBinding.Models
{
public interface IRepository
{
IEnumerable<Employee> Employee { get; }
Employee this[int id] { get; set; }
}
public class EmployeeRepository : IRepository
{
private Dictionary<int, Employee> employee=new Dictionary<int, Employee>
{
[1]=new Employee
{
Id=1,
Name="John",
DOB=new DateTime(1980, 12, 25),
Role=Role.Admin
},
[2]=new Employee
{
Id=2,
Name="Michael",
DOB=new DateTime(1981, 5, 13),
Role=Role.Designer
},
[3]=new Employee
{
Id=3,
Name="Rachael",
DOB=new DateTime(1982, 11, 25),
Role=Role.Designer
},
[4]=new Employee
{
Id=4,
Name="Anna",
DOB=new DateTime(1983, 1, 20),
Role=Role.Manager
}
};
public IEnumerable<Employee> Employee=> employee.Values;
public Employee this[int id]
{
get
{
return employee.ContainsKey(id) ? employee[id] : ;
}
set
{
employee[id]=value;
}
}
}
}
我們創建repository并且創建4個員工,我們使用4個員工的數據幫助我們理解模型綁定的概念
Controllers & Views
using AspNetCore.ModelBinding.Models;
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.ModelBinding.Controllers
{
public class HomeController : Controller
{
private IRepository repository;
public HomeController(IRepository repo)
{
repository=repo;
}
public IActionResult Index(int id=1)
{
return View(repository[id]);
}
}
}
@model Employee
@{
ViewData["Title"]="Index";
}
<h2>Employee</h2>
<table class="table table-bordered align-middle">
<tr><th>Id:</th><td>@Model.Id</td></tr>
<tr><th>Name:</th><td>@Model.Name</td></tr>
<tr><th>Date of Birth:</th><td>@Model.DOB.ToShortDateString()</td></tr>
<tr><th>Role:</th><td>@Model.Role</td></tr>
</table>
注冊Repository作為服務
builder.Services.AddSingleton<IRepository, EmployeeRepository>();
在應用中更新下面代碼:
using ModelBindingValidation.Models;
var builder=WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddSingleton<IRepository, EmployeeRepository>();
builder.Services.AddControllersWithViews();
var app=builder.Build();
...
2 理解模型綁定
ASP.NET Core模型綁定在整個過程發揮什么作用呢?我們請求的URL包含了employee id的值(給與第三段的URL是1) /Home/Index/1
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
public IActionResult Index(int id=1)
{
return View(repository[id]);
}
模型綁定會從下面3個地方查詢值:
1 表單數據值
2 路由變量
3 查詢字符串
這是為什么Employee 為2的員工被顯示,因為在查詢字符串Id的值(即1)之前框架在路由變量中發現了Id(即2)值,因此2的值被提供給action方法參數,如果我們打開URL-Home/Index?id=3,然而Employee Id為3的員工將被顯示:
如果ASP.NET Core在這三個地方沒有發現綁定的值,會發生什么呢?– 表單數據值,路由變量&查詢字符串,在這種情況下,它將根據action方法定義的類型提供默認值,這些默認值是:
2 string類型為""
3 時間類型為01-01-0001 00:00:00
4 float類型為0
public IActionResult Index(int id)
{
if (id==0)
id=1;
return View(repository[Convert.ToInt32(id)]);
}
我們數據中沒有員工Id為0,因此我們在if代碼塊中賦值為1,這將幫助我們阻止運行時錯誤,我們可以通過使用Try-Catch 塊處理運行時錯誤
注意可空類型的默認值為,現在修改Index方法有一個able int類型參數,代碼如下:
public IActionResult Index(int? id)
{
if (id==)
id=1;
return View(repository[Convert.ToInt32(id)]);
}
運行你的應用程序并且進入URL– /Home/Index,現在通過斷點來檢查id的值, 這時你將發現它的值為
4 模型綁定簡單類型
public IActionResult Index(int? id)
{
if (id==)
id=1;
return View(repository[Convert.ToInt32(id)]);
}
如果你收到要給URL,Id值是字符串 像– /Home/Index/John 在這種情況下,框架將嘗試把John轉換到int值,這時不能轉化,因此action 方法接收到id的參數為
模型綁定查找公共屬性從下面三個地方:
在Home Controller中添加Create方法,這兩個方法如下:
public IActionResult Create()=> View();
[HttpPost]
public IActionResult Create(Employee model)=> View("Index", model);
模型綁定的功能是從Http請求中提取Employee類公共屬性,并且將它提供給Create方法的參數,該方法傳遞Employee模型對象到默認View
@model Employee
@{
ViewData["Title"]="Create Employee";
}
<h2>Create Employee</h2>
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="Id"></label>
<input asp-for="Id" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Name"></label>
<input asp-for="Name" class="form-control" />
</div>
<div class="form-group">
<label asp-for="DOB"></label>
<input asp-for="DOB" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Role"></label>
<select asp-for="Role" class="form-control"
asp-items="@new SelectList(Enum.GetNames(typeof(Role)))"></select>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<input asp-for="Id" class="form-control" />
Name屬性被綁定通過下面這種方式
<input asp-for="Name" class="form-control" />
下面2張圖片顯示了填充和提交的表單:
6 復雜對象包含復雜對象
EmployeeDetails.cs類包含了名稱為HomeAddress公共屬性,這個屬性是一個Address類型,因此復雜對象包含另一個復雜對象案例
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime DOB { get; set; }
public Address HomeAddress { get; set; }
public Role Role { get; set; }
}
public class Address
{
public string HouseNumber { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
綁定HomeAddress屬性時,模型綁定處理過程和前面的相同:
更新Create.cshtml視圖文件綁定HomeAddress類型所有屬性,代碼如下:
@model Employee
@{
ViewData["Title"]="Create Employee";
}
<h2>Create Employee</h2>
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="Id"></label>
<input asp-for="Id" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Name"></label>
<input asp-for="Name" class="form-control" />
</div>
<div class="form-group">
<label asp-for="DOB"></label>
<input asp-for="DOB" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Role"></label>
<select asp-for="Role" class="form-control"
asp-items="@new SelectList(Enum.GetNames(typeof(Role)))"></select>
</div>
<div class="form-group">
<label asp-for="HomeAddress.HouseNumber"></label>
<input asp-for="HomeAddress.HouseNumber" class="form-control" />
</div>
<div class="form-group">
<label asp-for="HomeAddress.City"></label>
<input asp-for="HomeAddress.City" class="form-control" />
</div>
<div class="form-group">
<label asp-for="HomeAddress.Street"></label>
<input asp-for="HomeAddress.Street" class="form-control" />
</div>
<div class="form-group">
<label asp-for="HomeAddress.PostalCode"></label>
<input asp-for="HomeAddress.PostalCode" class="form-control" />
</div>
<div class="form-group">
<label asp-for="HomeAddress.Country"></label>
<input asp-for="HomeAddress.Country" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
當綁定HomeAddress屬性時候,我們必須包含"HomeAddress",看Helper標簽asp-for="HomeAddress.HouseNumber" 綁定HouseNumber屬性,我們也為另一些屬性使用這種綁定
@model Employee
@{
ViewData["Title"]="Index";
}
<h2>Employee</h2>
<table class="table table-sm table-bordered table-striped">
<tr><th>Id:</th><td>@Model.Id</td></tr>
<tr><th>Name:</th><td>@Model.Name</td></tr>
<tr><th>Date of Birth:</th><td>@Model.DOB.ToShortDateString()</td></tr>
<tr><th>Role:</th><td>@Model.Role</td></tr>
<tr><th>House No:</th><td>@Model.HomeAddress?.HouseNumber</td></tr>
<tr><th>Street:</th><td>@Model.HomeAddress?.Street</td></tr>
<tr><th>City:</th><td>@Model.HomeAddress?.City</td></tr>
<tr><th>Postal Code:</th><td>@Model.HomeAddress?.PostalCode</td></tr>
<tr><th>Country:</th><td>@Model.HomeAddress?.Country</td></tr>
</table>
現在,運行應用程序并且進入URL– /Home/Create, 填充并提交表單,我們將發現address類型屬性的顯示,顯示圖片如下:
檢查源代碼
下面是瀏覽器為html生成的源代碼
<div class="form-group">
<label for="HomeAddress_HouseNumber">HouseNumber</label>
<input class="form-control" type="text" id="HomeAddress_HouseNumber" name="HomeAddress.HouseNumber" value="" />
</div>
<div class="form-group">
<label for="HomeAddress_City">City</label>
<input class="form-control" type="text" id="HomeAddress_City" name="HomeAddress.City" value="" />
</div>
<div class="form-group">
<label for="HomeAddress_Street">Street</label>
<input class="form-control" type="text" id="HomeAddress_Street" name="HomeAddress.Street" value="" />
</div>
<div class="form-group">
<label for="HomeAddress_PostalCode">PostalCode</label>
<input class="form-control" type="text" id="HomeAddress_PostalCode" name="HomeAddress.PostalCode" value="" />
</div>
<div class="form-group">
<label for="HomeAddress_Country">Country</label>
<input class="form-control" type="text" id="HomeAddress_Country" name="HomeAddress.Country" value="" />
</div>
HouseNumber輸入控件獲取屬性名字的值HomeAddress.HouseNumber,然而id屬性的值變為HomeAddress_HouseNumber,相同的方式,City輸入控件獲取name屬性的值,然而id的屬性的值為 HomeAddress_City
string houseNo=Request.Form["HomeAddress.HouseNumber"];
[Bind(Prefix)]特性能修改復雜類型模型綁定的默認行為,讓我們通過一個例子來理解,創建一個名為PersonAddress.cs的模型類使用下面代碼:
namespace AspNetCore.ModelBinding.Models
{
public class PersonAddress
{
public string City { get; set; }
public string Country { get; set; }
}
}
[ ]
public IActionResult DisplayPerson(PersonAddress personAddress)
{
return View(personAddress);
}
下一步,修改Create視圖中asp-action標簽的值,將該值設置為DisplayPerson,代碼如下:
<form asp-action="DisplayPerson" method="post">
...
</form>
@model PersonAddress
@{
ViewData["Title"]="Person";
}
<h2>Person</h2>
<table class="table table-sm table-bordered table-striped">
<tr><th>City:</th><td>@Model.City</td></tr>
<tr><th>Country:</th><td>@Model.Country</td></tr>
</table>
現在運行你的應用程序,并且進入URL- /Home/Create,填充表單并且點擊提交按鈕
模型綁定失敗的原因是因為City和Country輸入控件屬性Name包含了字符串HomeAddress 前綴,在瀏覽器中檢查輸入控件源代碼
<input class="form-control" type="text" id="HomeAddress_City" name="HomeAddress.City" value="">
<input class="form-control" type="text" id="HomeAddress_Country" name="HomeAddress.Country" value="">
為了解決這個問題,我們在action方法的參數中應用[Bind(Prefix)],告訴ASP.NET Core 基于HomeAddress前綴完成模型綁定
public IActionResult DisplayPerson
([Bind(Prefix=nameof(Employee.HomeAddress))] PersonAddress personAddress)
{
return View(personAddress);
}
再次提交表單,這次我們將發現City和Country值并將他們顯示在瀏覽器,看下面圖片:
使用[Bind]選擇性的綁定屬性
public IActionResult DisplayPerson([Bind(nameof(PersonAddress.City), Prefix=nameof(Employee.HomeAddress))] PersonAddress personAddress)
{
return View(personAddress);
}
我們可以使用另外一種方法實現相同的功能,在PersonAddress類的Country屬性上使用 [BindNever] 特性,BindNever指定的屬性模型綁定將被忽略
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace AspNetCore.ModelBinding.Models
{
public class PersonAddress
{
public string City { get; set; }
[ ]
public string Country { get; set; }
}
}
8 模型綁定上傳文件
我們通過模型綁定技術完成上傳文件功能,這里我們必須做3件事情:
1 在View中添加input type=”file”控件
2 在html表單的標簽中添加enctype="multipart/form-data"特性
3 在action方法中添加IFormFile類型參數,使用該參數綁定上傳文件
我們創建一個上傳文件的特性,添加一個新的Controller并且命名為FileUploadController.cs. 代碼給與如下:
using Microsoft.AspNetCore.Mvc;
namespace ModelBindingValidation.Controllers
{
public class FileUploadController : Controller
{
private IWebHostEnvironment hostingEnvironment;
public FileUploadController(IWebHostEnvironment environment)
{
hostingEnvironment=environment;
}
public IActionResult Index()=> View();
[ ]
public async Task<IActionResult> Index(IFormFile file)
{
string path=Path.Combine(hostingEnvironment.WebRootPath, "Images/" + file.FileName);
using (var stream=new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(stream);
}
return View((object)"Success");
}
}
}
添加一個IWebHostEnvironment 的依賴用來獲取"wwwroot"文件夾的全部路徑, Index方法通過模型綁定技術將上傳的文件綁定到IFormFile類型參數
方法內部將文件保存到應用程序wwwroot/Images文件夾內
為了能夠正常工作你確保在wwwroot目錄下創建Images文件夾,接下來在 Views/FileUpload文件夾內添加Index文件,代碼如下:
@model string
@{
ViewData["Title"]="Upload File";
}
<h2>Upload File</h2>
<h3>@Model</h3>
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<input type="file" name="file" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
總結:
參考文獻
https://www.yogihosting.com/aspnet-core-model-binding/
AngularJS支持通過單個頁面上的多個視圖單頁應用。要做到這一點AngularJS提供了ng-view 、 ng-template 指令和 $routeProvider 服務。
ng-view
NG-view標記簡單地創建一個占位符,其中一個相應的視圖(HTML或ng-template視圖),可以根據配置來放置。
使用
定義主模塊使用一個 div 及ng-view。
<div ng-app="mainApp">
...
<div ng-view></div>
</div> 12345復制代碼類型:[html]
ng-template
ng-template指令用于創建使用腳本標記的HTML視圖。它包含一個“id”屬性用于由 $routeProvider 映射帶有控制器的視圖。
使用
定義腳本塊類型為 ng-template 的主模塊 。
div ng-app="mainApp">
...
<script type="text/ng-template" id="addStudent.htm">
<h2> Add Student </h2>
{{message}}
</script>
</div> 12345678復制代碼類型:[html]
$routeProvider
$routeProvider是用來設置URL配置的關鍵服務,映射與對應的HTML頁面或ng-template,并附加相同的控制器。
使用
定義腳本塊類型為 ng-template 的主模塊 。
<div ng-app="mainApp">
...
<script type="text/ng-template" id="addStudent.htm">
<h2> Add Student </h2>
{{message}}
</script>
</div>
123456789復制代碼類型:[html]
使用
定義腳本塊及主模塊,并設置路由配置。
var mainApp=angular.module("mainApp", ['ngRoute']);
mainApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/addStudent', {
templateUrl: 'addStudent.htm',
controller: 'AddStudentController'
}).
when('/viewStudents', {
templateUrl: 'viewStudents.htm',
controller: 'ViewStudentsController'
}).
otherwise({
redirectTo: '/addStudent'
});
}]);
123456789101112131415161718復制代碼類型:[html]
以下是在上面的例子中要考慮的重點。
$ routeProvider定義作為一個函數在mainApp模塊的配置下,使用鍵 '$routeProvider'.
$routeProvider定義URL “/addStudent”,然后映射到“addStudent.htm”。addStudent.htm 存在于相同的路徑的主html頁面。如果HTM網頁沒有定義,那么NG-模板使用id="addStudent.htm"。我們使用ng-template。
"otherwise" 用于設置的默認視圖。
"controller" 用于為視圖設置相應的控制器。
開課吧廣場-人才學習交流平臺
言
網站開發一般基于瀏覽器來展示,手機端目前成為兵家必爭之地,怎么在網頁端開發一份代碼,在手機端也能有不錯的效果呢。查資料發現通過響應式布局和自適應布局可以解決,那接下來我們來實踐一下。
概念:
1、首先,響應式和自適應最為關鍵的區別是什么呢?
簡而言之,響應式就相當于液體,它可以自動適應不同尺寸的屏幕,無論你的設備尺寸多么奇葩。響應式使用CSS media queries的方法,根據目標設備自動改變風格如顯示類型,寬度、高度等,這能很好解決不同屏幕尺寸的顯示問題。
而自適應設計是基于斷點使用靜態布局,一旦頁面被加載就無法再進行自動適應,自適應會自動檢測屏幕的大小來加載適當的工作布局,也就是說,當你要采用自適應設計網站時,你得一個一個設計6種常見的屏幕布局。
1.320
2.480
3.760
4.960
5.1200
6.1600
顯然,自適應設計需要做更多的工作,你必須至少設計6種常見的布局。而響應式設計可以更好地適應復雜的媒體設備要求,能很好地解決顯示和性能問題。
千言萬語不如一圖:
如何確定媒體查詢的分割點也是一個開發中會遇到的問題,下面是市場上的移動設備和電腦屏幕分辨率的分布情況,可以發現不同品牌和型號的設備屏幕分辨率一般都不一樣
如果我們選擇600px,900px,1200px,1800px作為分割點,可以適配到常見的14個機型:
當然這只是其中的一種分割方案,我們還可以這樣劃分:480px,800px,1400px,1400px
簡單點:提供三個設計稿件尺寸分別是:640px、960px、1200px
而作為曾經典型的響應式布局框架,Bootstrap是怎么進行斷點的呢?
上面的分割方案不一定滿足項目中的實際需求,我們可以先用跨度大的分割點進行分割,如果出現不適配的情況可以再根據實際情況增加新的分割點。
大多數移動瀏覽器將HTML頁面放大為寬的視圖(viewport)以符合屏幕分辨率。你可以使用視圖的meta標簽來進行重置。下面的視圖標簽告訴瀏覽器,使用設備的寬度作為視圖寬度并禁止初始的縮放。在<head>標簽里加入這個meta標簽。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
[1](user-scalable=no 屬性能夠解決 iPad 切換橫屏之后觸摸才能回到具體尺寸的問題。)
Media Queries 是響應式設計的核心。 它根據條件告訴瀏覽器如何為指定視圖寬度渲染頁面。假如一個終端的分辨率小于 980px,那么可以這樣寫:
@media screen and (max-width: 980px) {
#head { … }
#content { … }
#footer { … }
}
這里的樣式就會覆蓋上面已經定義好的樣式。
假如我們要設定兼容 iPad 和 iPhone 的視圖,那么可以這樣設置:
/** iPad **/
@media only screen and (min-width: 768px) and (max-width: 1024px) {}
/** iPhone **/
@media only screen and (min-width: 320px) and (max-width: 767px) {}
恩,差不多就這樣的一個原理。
例如這樣:
#head { width: 100% }
#content { width: 50%; }
img { width: auto; max-width: 100%; }
或
img { max-width: 100%; height: auto }
這行代碼對于大多數嵌入網頁的視頻也有效果,所以可以寫成:
img object { max-width: 100%; height:auto}
老版本的Ie不支持max-width,所以只好寫成:
img { width: 100%; height:auto}
此外,windows平臺縮放圖片時,可能出現圖像失真現象,這時可以嘗試使用IE的專有命令:
Img { -ms-interpolation-mode: bicubic }
<img src="image.jpg"
data-src-600px="image-600px.jpg"
data-src-800px="image-800px.jpg"
alt="">
CSS 控制:
@media (min-device-width:600px) {
img[data-src-600px] {
content: attr(data-src-600px, url);
}
}
@media (min-device-width:800px) {
img[data-src-800px] {
content: attr(data-src-800px, url);
}
}
例如pre,iframe,video等,都需要和img一樣控制好寬度。對于table,建議不要增加 padding 屬性,低分辨率下使用內容居中:
table th, table td { padding: 0 0; text-align: center; }
來源資料:
http://www.woshipm.com/pd/153425.html
https://www.yisu.com/zixun/118775.html
http://caibaojian.com/356.html
https://juejin.cn/post/6844903814332432397(推薦)
https://www.xiaoxili.com/blog/posts/fusion-web-design
*請認真填寫需求信息,我們會在24小時內與您取得聯系。