mvc ef 关联实体 非主键_asp.net core系列 40 Web 应用MVC 介绍与详细示例

一. MVC介绍

  MVC架构模式有助于实现关注点分离。视图和控制器均依赖于模型。 但是,模型既不依赖于视图,也不依赖于控制器。 这是分离的一个关键优势。 这种分离允许模型独立于可视化展示进行构建和测试。ASP.NET Core MVC 包括以下功能:

    路由、模型绑定、模型验证、依赖关系注入、筛选器、区域、Web API、可测试性、Razor 视图引擎、强类型视图、标记帮助程序、 视图组件。

  (1) 路由

    ASP.NET Core MVC 建立在 ASP.NET Core 的路由之上,是一个功能强大的 URL 映射组件,可用于生成具有易于理解和可搜索 URL 的应用程序。关于路由知识,请查看asp.net core 系列第5,6章。

  (2) 模型绑定(Model)

    ASP.NET Core MVC 模型绑定将客户端请求数据(窗体值(form)、路由数据、查询字符串参数、HTTP 头)转换到控制器(Controller)可以处理的对象中。 因此,控制器逻辑不必找出传入的请求数据;它只需具备作为其Action方法的参数的数据。下面的LoginViewModel就是一个模型类。

  public async Task Login(LoginViewModel model, string returnUrl = null)

  (3) 模型验证

    ASP.NET Core MVC 通过使用数据注释验证属性。 验证属性在值发送到服务端前,在客户端上进行检查。并在调用控制器action前在服务端上进行检查。

7e0a7a533c54004524e8afa60a9dcb95.png

using System.ComponentModel.DataAnnotations;public class LoginViewModel
{
[Required]
[EmailAddress]public string Email { get; set; }
[Required]
[DataType(DataType.Password)]public string Password { get; set; }
[Display(Name = "Remember me?")]public bool RememberMe { get; set; }
}//服务端控制器action验证public async Task Login(LoginViewModel model, string returnUrl = null)
{//验证模型 if (ModelState.IsValid)
{// work with the model }return View(model);
}

7e0a7a533c54004524e8afa60a9dcb95.png

  (4) 依赖注入

    依赖关系注入除了在控制器上通过构造函数请求所需服务,还可以使用@inject 指令,应用在视图文件上。下面是视图页面上通过依赖注入获取服务对象。

7e0a7a533c54004524e8afa60a9dcb95.png

@inject SomeService ServiceNameDOCTYPE html><html lang="en"><head><title>@ServiceName.GetTitletitle>head><body><h1>@ServiceName.GetTitleh1>body>html>

7e0a7a533c54004524e8afa60a9dcb95.png

  (5) 筛选器

    筛选器帮助开发者封装,横切关注点,例如异常处理或授权。筛选器允许action方法运行自定义预处理和后处理逻辑,并且可以配置为在给定请求的执行管道内的特定点上运行。筛选器可以作为属性应用于控制器或Action(也可以全局运行)。例如MVC 授权筛选器。

    [Authorize]public class AccountController : Controller

  (6) 区域

    区域用在大型Web开发上, 是功能分组的方法。区域是应用程序内的一个 MVC 结构。  例如,具有多个业务单位(如结账、计费、搜索等)的电子商务应用。每个单位都有自己的逻辑组件视图、控制器和模型。

  (7) Web API

    除了作为生成网站的强大平台,ASP.NET Core MVC 还对生成 Web API 提供强大的支持。 可以生成可连接大量客户端(包括浏览器和移动设备)的服务,前面章节有讲过。

  (8) 可测试性

    框架对界面和依赖项注入的使用非常适用于单元测试,并且该框架还包括使得集成测试快速轻松的功能(例如 TestHost 和实体框架的 InMemory 提供程序)

  (9) Razor 视图引擎

    ASP.NET Core MVC 视图使用 Razor 视图引擎呈现视图。 Razor 是一种紧凑、富有表现力且流畅的模板标记语言,用于使用嵌入式 C# 代码定义视图。 Razor 用于在服务器上动态生成 Web 内容。 可以完全混合服务器代码与客户端内容和代码。例如下面嵌入 C#代码,循环输出5组li标记

<ul>
@for (int i = 0; i < 5; i++) {>List item @ili>
}ul>

  (10) 强类型视图

    可以基于模型强类型化 MVC 中的 Razor 视图。 控制器可以将强类型化的模型传递给视图,使视图具备类型检查和 IntelliSense 支持。例如,以下视图呈现类型为 IEnumerable 的模型:

7e0a7a533c54004524e8afa60a9dcb95.png

@model IEnumerable<Product><ul>
@foreach (Product p in Model)
{<li>@p.Nameli>
}ul>

7e0a7a533c54004524e8afa60a9dcb95.png

  (11) 标记帮助程序

    标记帮助程序使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素。 例如,内置 LinkTagHelper 可以用来创建指向 AccountsController控制器中  Login的方法链接

    <p>
Thank you for confirming your email.
Please <a asp-controller="Account" asp-action="Login">Click here to Log ina>.p>

  (12) 视图组件

    通过视图组件可以包装呈现逻辑并在整个应用程序中重用它。 这些组件类似于分部视图,但具有关联逻辑。

二. 完整示例介绍(项目StudyMVCDemo)

   2.1 安装EF数据提供程序

    这里使用内存数据库Microsoft.EntityFrameworkCore.InMemory,Entity Framework Core 和内存数据库一起使用, 这对测试非常有用。

    PM> Install-Package Microsoft.EntityFrameworkCore.InMemory

  2.2 新建数据模型类(POCO )和EF上下文类

7e0a7a533c54004524e8afa60a9dcb95.png

    public class MvcMovieContext : DbContext
{public MvcMovieContext(DbContextOptions options)
: base(options)
{
}public DbSet Movie { get; set; }
}

7e0a7a533c54004524e8afa60a9dcb95.png

7e0a7a533c54004524e8afa60a9dcb95.png

    public class Movie
{public int Id { get; set; }public string Title { get; set; }
[DataType(DataType.Date)]public DateTime ReleaseDate { get; set; }public string Genre { get; set; }public decimal Price { get; set; }
}

7e0a7a533c54004524e8afa60a9dcb95.png

   2.3 初始化数据

7e0a7a533c54004524e8afa60a9dcb95.png

     public static void Main(string[] args)
{var host = CreateWebHostBuilder(args).Build();using (var scope = host.Services.CreateScope())
{var services = scope.ServiceProvider;try
{
//var context = services.GetRequiredService();//程序运行时,使用EF迁移生成数据,用在关系型数据库//context.Database.Migrate(); SeedData.Initialize(services);
}catch (Exception ex)
{var logger = services.GetRequiredService>();
logger.LogError(ex, "An error occurred seeding the DB.");
}
}
host.Run();
}

7e0a7a533c54004524e8afa60a9dcb95.png

4e4aa0ddaa6bbc359ccb28b62830655b.png

7e0a7a533c54004524e8afa60a9dcb95.png

    public static class SeedData
{/// /// 初始化数据/// /// public static void Initialize(IServiceProvider serviceProvider)
{using (var context = new MvcMovieContext(
serviceProvider.GetRequiredService>()))
{// 如果有数据返回if (context.Movie.Any())
{return; // DB has been seeded }
context.Movie.AddRange(new Movie
{
Title = "When Harry Met Sally",
ReleaseDate = DateTime.Parse("1989-2-12"),
Genre = "Romantic Comedy",
Price = 7.99M
},new Movie
{
Title = "Ghostbusters ",
ReleaseDate = DateTime.Parse("1984-3-13"),
Genre = "Comedy",
Price = 8.99M
},new Movie
{
Title = "Ghostbusters 2",
ReleaseDate = DateTime.Parse("1986-2-23"),
Genre = "Comedy",
Price = 9.99M
},new Movie
{
Title = "Rio Bravo",
ReleaseDate = DateTime.Parse("1959-4-15"),
Genre = "Western",
Price = 3.99M
}
);
context.SaveChanges();
}
}
}

7e0a7a533c54004524e8afa60a9dcb95.png

  2.4 添加控制器类(MoviesController)

7e0a7a533c54004524e8afa60a9dcb95.png

  public class MoviesController : Controller
{private readonly MvcMovieContext _MvcMovieContext;public MoviesController(MvcMovieContext MvcMovieContext)
{this._MvcMovieContext = MvcMovieContext;
}
}

7e0a7a533c54004524e8afa60a9dcb95.png

  2.5 列表页Movies/index.cshtml

7e0a7a533c54004524e8afa60a9dcb95.png

        // GET: //public IActionResult Index()
{var movies = _MvcMovieContext.Movie.ToList();return View(movies);
}

7e0a7a533c54004524e8afa60a9dcb95.png

7e0a7a533c54004524e8afa60a9dcb95.png

@model IEnumerable<StudyMVCDemo.Models.Movie>
@{
ViewData["Title"] = "Index";
}<h1>Indexh1><p><a asp-action="Create">Create Newa>p><table class="table"><thead><tr><th>
@Html.DisplayNameFor(model => model.Title)th><th>
@Html.DisplayNameFor(model => model.ReleaseDate)th><th>
@Html.DisplayNameFor(model => model.Genre)th><th>
@Html.DisplayNameFor(model => model.Price)th><th>th>tr>thead><tbody>
@foreach (var item in Model)
{<tr><td>
@Html.DisplayFor(modelItem => item.Title)td><td>
@Html.DisplayFor(modelItem => item.ReleaseDate)td><td>
@Html.DisplayFor(modelItem => item.Genre)td><td>
@Html.DisplayFor(modelItem => item.Price)td><td><a asp-action="Edit" asp-route-id="@item.Id">Edita> |<a asp-action="Details" asp-route-id="@item.Id">Detailsa> |<a asp-action="Delete" asp-route-id="@item.Id">Deletea>td>tr>
}tbody>table>

7e0a7a533c54004524e8afa60a9dcb95.png

   启动程序,在浏览器中输入http://localhost:18084/Movies,如下图所示:

43ab6697fb0d001168288e9372dc95f0.png

    上图中菜单布局是在 Views/Shared/_Layout.cshtml 文件中实现的,该_Layout.cshtml页中@RenderBody()是视图页面的占位符。

    Views/_ViewStart.cshtml 文件将 Views/Shared/_Layout.cshtml 文件引入到每个视图中。 可以使用 Layout属性设置不同的布局视图,或将它设置为 null,这样将不会使用任何布局文件。后面详细了解布局。

   2.6 详细页Movies/ Details.cshtml

7e0a7a533c54004524e8afa60a9dcb95.png

        /// /// 详细页 /// /// /// public async Task Details(int? id)
{if (id == null)
{return NotFound();
}var movie = await _MvcMovieContext.Movie
.FirstOrDefaultAsync(m => m.Id == id);if (movie == null)
{return NotFound();
}return View(movie);
}

7e0a7a533c54004524e8afa60a9dcb95.png

7e0a7a533c54004524e8afa60a9dcb95.png

@model StudyMVCDemo.Models.Movie
@{
ViewData["Title"] = "Details";
}<h1>Detailsh1><div><h4>Movieh4><hr /><dl class="row"><dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Title)dt><dd class="col-sm-10">
@Html.DisplayFor(model => model.Title)dd><dt class="col-sm-2">
@Html.DisplayNameFor(model => model.ReleaseDate)dt><dd class="col-sm-10">
@Html.DisplayFor(model => model.ReleaseDate)dd><dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Genre)dt><dd class="col-sm-10">
@Html.DisplayFor(model => model.Genre)dd><dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Price)dt><dd class="col-sm-10">
@Html.DisplayFor(model => model.Price)dd>dl>div><div><a asp-action="Edit" asp-route-id="@Model.Id">Edita> |<a asp-action="Index">Back to Lista>div>

7e0a7a533c54004524e8afa60a9dcb95.png

   启动程序,从列表页的超连接Details点击进入,如下图所示:

be2be844451cb3270d41b6255f4f0b98.png

  2.7 编辑页Movies/ Edit.cshtml

    对于编辑页有二个action, 一个是Get用来提取数据填充到表单,一个是Post用来提交修改的表单数据。

    (1) post中的Bind特性是对需要的属性进行更新。

    (2) ValidateAntiForgeryToken特性用于防止请求伪造, 生成的隐藏的 XSRF 标记 Input name="__RequestVerificationToken"。用在Post提交的比如修改和删除功能等。

    (3) 模型验证asp-validation-for是指表单Post到服务器之前,客户端验证会检查字段上的任何验证规则。 如果有任何验证错误,则将显示错误消息,并且不会Post表单,内部是输入标记帮助程序使用 DataAnnotations 特性,并在客户端上生成 jQuery 验证所需的 HTML 特性。

7e0a7a533c54004524e8afa60a9dcb95.png

       public async Task Edit(int? id)
{if (id == null)
{return NotFound();
}var movie = await _MvcMovieContext.Movie.FindAsync(id);if (movie == null)
{return NotFound();
}return View(movie);
}
[HttpPost]
[ValidateAntiForgeryToken]public async Task Edit(int id, [Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie)
{if (id != movie.Id)
{return NotFound();
}if (ModelState.IsValid)
{try
{
_MvcMovieContext.Update(movie);await _MvcMovieContext.SaveChangesAsync();
}catch (DbUpdateConcurrencyException)
{throw;
}return RedirectToAction("Index");
}return View(movie);
}

7e0a7a533c54004524e8afa60a9dcb95.png

7e0a7a533c54004524e8afa60a9dcb95.png

@model StudyMVCDemo.Models.Movie
@{
ViewData["Title"] = "Edit";
}<h1>Edith1><h4>Movieh4><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="Title" class="control-label">label><input asp-for="Title" class="form-control" /><span asp-validation-for="Title" class="text-danger">span>div><div class="form-group"><label asp-for="ReleaseDate" class="control-label">label><input asp-for="ReleaseDate" class="form-control" /><span asp-validation-for="ReleaseDate" class="text-danger">span>div><div class="form-group"><label asp-for="Genre" class="control-label">label><input asp-for="Genre" class="form-control" /><span asp-validation-for="Genre" class="text-danger">span>div><div class="form-group"><label asp-for="Price" class="control-label">label><input asp-for="Price" class="form-control" /><span asp-validation-for="Price" 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 Lista>div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

7e0a7a533c54004524e8afa60a9dcb95.png

     启动程序,从列表页的Edit点击进入,如下图所示:

25c56a636deb68c1af97c552c736fe35.png

   2.8 删除

7e0a7a533c54004524e8afa60a9dcb95.png

 // 删除没有对应的页面,从列表页的Delete点击进入,下面是删除的关键代码public async Task DeleteConfirmed(int id)
{var movie = await _context.Movie.FindAsync(id);
_context.Movie.Remove(movie);await _context.SaveChangesAsync();return RedirectToAction(nameof(Index));
}

7e0a7a533c54004524e8afa60a9dcb95.png

   参考文献

  MVC教程:

https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/first-mvc-app/start-mvc?view=aspnetcore-2.2&tabs=visual-studio

来源:

https://www.cnblogs.com/MrHSR/archive/2019/03/11/10509469.html

版权申明:本文来源于网友收集或网友提供,如果有侵权,请转告版主或者留言,本公众号立即删除。

5214f1e5b2e444b2e4f80530f74b7319.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值