在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小时内与您取得联系。