.Net Core开发学习(三) ——Mvc应用
Mvc概念
Mvc分别为Model、View、Controller,分工不同
模型(Model):为应用程序提供并绑定数据,为业务逻辑与视图显示提供支持。
视图(View):为应用程序提供前端数据显示与数据绑定。
控制器(Controller):处理请求。
创建项目
项目结构
项目相关文件与Web应用相似,可参考.Net Core开发学习(二) ——Web应用
文件夹Models:存放模型(Model)
文件夹Views:存放视图(View)
文件夹Controllers:存放控制器(Controller)
添加控制器(Controller)
添加控制器: 项目 > 右键Controllers > 添加 > 新建项 > 控制器类 > 修改名称(HelloController) > 确定
HelloController文件内容如下:
public class HelloController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
}
现在是不能运行的,因为Index方法返回的是一个视图,而我们还没有创建对应的视图文件,所以会报InvalidOperationException错误。
让我们改一下Index方法
public string Index()
{
return "HelloWorld";
}
运行结果
HelloWorld
现在我们来加点参数,添加如下方法
public string Hello(string name)
{
return "Hello " + name;
}
请求并Url传参/Hello/Hello?name=ZiYun,运行结果
Hello ZiYun
但带参数名的传参不太美观,且可能影响安全性。没关系,我们可以使用路由。
在Hello()方法上加上Route属性
//添加路由,参数为路由的路径
[Route("Hello/Hello/{name}")]
public string Hello(string name)
{
return "Hello " + name;
}
请求并Url传参/Hello/Hello/ZiYun,运行结果
Hello ZiYun
添加视图(View)
首先我们将HelloController.cs的Index方法改回来
public IActionResult Index()
{
return View();
}
添加视图: 右键Views文件夹 > 新建文件夹(Hello) > 右键Hello文件夹 > 添加 > 新建项 > Razor 视图文件 > 命名(Index.cshtml) > 确定
添加完成后视图是没有内容的,我们添加一点内容
@{
ViewData["Title"] = "Hello Index";
}
<h2>Hello Index</h2>
请求/Hello,运行结果
将数据传递给页面
修改代码 HelloController.cs > Index()
public IActionResult Index()
{
ViewData["name"] = "ZiYun";
return View();
}
修改视图 Views > Hello >
@{
ViewData["Title"] = "Hello Index";
}
<h2>Hello @ViewData["name"]</h2>
请求/Hello,运行结果
添加模型(Model)
新建类:Models > User.cs
结构如下
public class User
{
public int ID { get; set; }
[Required(ErrorMessage = "用户名不能为空")]
public string Name { get; set; }
[Required(ErrorMessage = "请输入正确的日期")]
[DataType(DataType.Date, ErrorMessage = "请输入正确的日期")]
public DateTime Birthday { get; set; }
}
打开:菜单栏 > NuGet 包管理器 > 包管理器控制台(PMC)
输入以下命令安装Sqlserver数据驱动
Install-Package Microsoft.EntityFrameworkCore.SqlServer
新建数据上下文类:Data > WebApplicationContext.cs
结构如下
public class WebApplicationContext : DbContext
{
public WebApplicationContext(DbContextOptions<WebApplicationContext> options) : base(options)
{
}
public DbSet<User> User { get; set; }
}
配置DbContext服务
修改文件:Startup.cs > ConfigureServices()
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
//注册数据上下文
services.AddDbContext<WebApplicationContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("WebApplicationContext")));
}
修改文件:appsettings.json
将连接字符串添加到第一个大括号内
"ConnectionStrings": {
"WebApplicationContext": "Server=(localdb)\\mssqllocaldb;Database=WebApplication1-1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
数据迁移:菜单栏 > 工具(Tools) > Nuget包管理器(NPM) > 程序包管理控制台(PMC)
输入以下命令:
Add-Migration Initial
Update-Database
命令解释:
Add-Migration:添加迁移文件,根据创建的数据上下文,添加创建数据库及结构的代码。Initial为迁移名,可自行定义。执行完成后会弹出创建数据库的文件Migrations/<time-stamp>_Initial.cs。可根据实际情况进行更改。
Update-Database:根据迁移文件更新数据库。
这样我们的数据源就配置好了
添加测试界面
新建文件夹:Views > Users
新建基架:右键Users文件夹 > 新搭建基架的项目 > 视图使用Entity Framework 的 MVC 控制器 > 模型类(User) > 数据上下文类(WebApplicationContext) > 确定
可以看到已经帮我们添加好了增删改查页面以及UsersController控制器
运行项目,测试增删改查
Mvc的数据请求与数据绑定
在Mvc中通过控制器来处理页面请求和查询数据,Web应用通过Razor页面代码(.cshtml.cs)来处理。
查看Action:UsersController > [HttpGet]Edit
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var user = await _context.User.FindAsync(id);
if (user == null)
{
return NotFound();
}
return View(user);
}
当请求Edit Action时,控制器返回一个User对象,返回类型为 Task<IActionResult> 表示 异步处理 ,同步 使用 IActionResult
查看文件:Views > Users > Edit.cshtml
@model WebApplication1.Models.User
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>User</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="ID" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Birthday" class="control-label"></label>
<input asp-for="Birthday" class="form-control" />
<span asp-validation-for="Birthday" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
@model WebApplication1.Models.User :声明当前视图需要的数据类型
asp-for:绑定模型数据
其他获取数据方式
@Html.DisplayNameFor(model => model.Name)
@Html.DisplayFor(model => model.Name)
@Model.Name
查看Action:UsersController > [HttpPost]Edit
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("ID,Name,Birthday")] User user)
{
if (id != user.ID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(user);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!UserExists(user.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(user);
}
可以看到,在Mvc中提交绑定数据需要手动设置一下 [Bind()] ,其他操作和Web应用差距不大。
查看Action:UsersController > Delete() 以及 DeleteConfirmed()
// GET: Users/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var user = await _context.User
.FirstOrDefaultAsync(m => m.ID == id);
if (user == null)
{
return NotFound();
}
return View(user);
}
// POST: Users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var user = await _context.User.FindAsync(id);
_context.User.Remove(user);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
注意:
我们发现Delete的Post方法被命名成DeleteConfirmed,其实是因为如果写Delete,因为命名一致,参数一致会造成二义性。解决方法就是将修改命名,添加属性ActionName写上需要的Action名。
OK,一个简单的.Net Core Mvc项目就完成啦。