C# MVC 模式完全指南:从理论到实战
一般有两种构建方式
1,创建文件夹
2.创建dll库
牢记:Model层,相当于一个数据通道层,是对数据的包裹
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using C_之MVC模式.Model;
using C_之MVC模式.Service;
namespace C_之MVC模式
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 调用数据层
Data data = new Data();
// 数据转换
data.A = Convert.ToInt32(textBox1.Text.Trim());
data.B = Convert.ToInt32(textBox2.Text.Trim());
// 调用Control层
AddService addService = new AddService();
data.C= addService.Add(data);
// 返回到UI层
textBox3.Text= data.C.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace C_之MVC模式.Model
{
public class Data
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using C_之MVC模式.Model;
namespace C_之MVC模式.Service
{
public class AddService
{
public int Add(Data data)
{
return data.A + data.B; ;
}
}
}
dll库分层
MVC(Model-View-Controller,模型-视图-控制器)是一种广泛应用的软件架构模式,特别适合构建用户界面丰富的应用程序。本教程将带您深入了解C#中的MVC模式,从基础概念到实际项目应用。
一、MVC模式概述
1.1 什么是MVC?
MVC是一种将应用程序分为三个相互关联组件的设计模式:
- Model(模型):表示应用程序的数据和业务逻辑
- View(视图):负责显示数据(用户界面)
- Controller(控制器):处理用户输入,协调模型和视图之间的交互
1.2 MVC的优势
- 关注点分离:将业务逻辑、用户界面和控制流程分开
- 可维护性:修改一个组件通常不需要影响其他组件
- 可测试性:可以独立测试每个组件
- 可扩展性:更容易添加新功能或修改现有功能
二、C#中的MVC实现
2.1 基础项目结构
一个典型的C# MVC项目结构如下:
MyMvcApp/
├── Models/ # 模型类
│ ├── Product.cs
│ └── User.cs
├── Views/ # 视图文件
│ ├── Products/
│ │ ├── Index.cshtml
│ │ └── Details.cshtml
│ └── Shared/
│ └── _Layout.cshtml
├── Controllers/ # 控制器类
│ ├── ProductsController.cs
│ └── HomeController.cs
├── Program.cs # 程序入口
└── appsettings.json # 配置文件
2.2 创建基础MVC项目(.NET 6+)
dotnet new mvc -n MyMvcApp
cd MyMvcApp
dotnet run
三、深入理解MVC组件
3.1 模型(Model)
模型表示应用程序的数据和业务逻辑。它应该:
- 包含数据验证逻辑
- 实现业务规则
- 不包含用户界面代码
- 不包含输入验证(通常由控制器处理)
示例:Product模型
// Models/Product.cs
namespace MyMvcApp.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
// 业务逻辑示例
public bool IsInStock()
{
return StockQuantity > 0;
}
}
}
3.2 视图(View)
视图负责显示数据,通常是Razor视图(.cshtml文件):
- 包含HTML和C#代码的混合
- 从控制器接收数据模型
- 不包含业务逻辑
- 可以包含简单的显示逻辑
示例:产品列表视图
<!-- Views/Products/Index.cshtml -->
@model IEnumerable<MyMvcApp.Models.Product>
@{
ViewData["Title"] = "产品列表";
}
<h1>产品列表</h1>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>价格</th>
<th>库存</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach (var product in Model)
{
<tr>
<td>@product.Id</td>
<td>@product.Name</td>
<td>@product.Price.ToString("C")</td>
<td>@(product.IsInStock() ? "有货" : "缺货")</td>
<td>
<a asp-action="Details" asp-route-id="@product.Id">详情</a>
</td>
</tr>
}
</tbody>
</table>
3.3 控制器(Controller)
控制器处理用户请求,协调模型和视图:
- 接收用户输入
- 与模型交互获取/更新数据
- 选择适当的视图显示结果
- 包含输入验证逻辑
示例:Products控制器
// Controllers/ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using MyMvcApp.Models;
namespace MyMvcApp.Controllers
{
public class ProductsController : Controller
{
// 模拟数据存储
private static List<Product> _products = new List<Product>
{
new Product { Id = 1, Name = "笔记本电脑", Price = 5999.99m, StockQuantity = 10 },
new Product { Id = 2, Name = "智能手机", Price = 3999.99m, StockQuantity = 25 },
new Product { Id = 3, Name = "平板电脑", Price = 2499.99m, StockQuantity = 0 }
};
// 显示所有产品
public IActionResult Index()
{
return View(_products);
}
// 显示产品详情
public IActionResult Details(int id)
{
var product = _products.FirstOrDefault(p => p.Id == id);
if (product == null)
{
return NotFound(); // 404错误
}
return View(product);
}
// 创建产品 - GET
public IActionResult Create()
{
return View();
}
// 创建产品 - POST
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Product product)
{
if (ModelState.IsValid)
{
// 实际应用中这里会保存到数据库
product.Id = _products.Max(p => p.Id) + 1;
_products.Add(product);
return RedirectToAction(nameof(Index));
}
return View(product);
}
}
}
四、MVC工作流程
- 用户请求:用户通过浏览器发送请求(如
/Products/Index
) - 路由解析:ASP.NET Core路由系统将请求映射到ProductsController的Index方法
- 控制器处理:
- 执行Index方法
- 可能从模型获取数据
- 选择适当的视图
- 视图渲染:
- 视图接收模型数据
- 生成HTML响应
- 响应返回:将生成的HTML发送回浏览器
五、高级MVC技术
5.1 模型绑定与验证
模型绑定:自动将HTTP请求数据绑定到控制器方法参数
// 控制器方法接收表单数据
[HttpPost]
public IActionResult Create(Product product)
{
// product对象已自动填充表单数据
// ...
}
数据验证:使用数据注解进行验证
// Models/Product.cs
using System.ComponentModel.DataAnnotations;
public class Product
{
public int Id { get; set; }
[Required(ErrorMessage = "产品名称不能为空")]
[StringLength(100, MinimumLength = 3, ErrorMessage = "名称长度必须在3-100个字符之间")]
public string Name { get; set; }
[Required]
[Range(0.01, 100000, ErrorMessage = "价格必须在0.01-100000之间")]
public decimal Price { get; set; }
[Required]
[Range(0, 10000, ErrorMessage = "库存数量必须在0-10000之间")]
public int StockQuantity { get; set; }
}
显示验证错误:
<!-- 在Create视图中 -->
@model MyMvcApp.Models.Product
<h1>创建新产品</h1>
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<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">
<input type="submit" value="创建" class="btn btn-primary" />
</div>
</form>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
5.2 过滤器(Filters)
ASP.NET Core提供了多种过滤器:
- 授权过滤器:
[Authorize]
- 资源过滤器:在模型绑定前后执行
- 操作过滤器:在操作方法执行前后执行
- 异常过滤器:
[HandleError]
- 结果过滤器:在操作结果执行前后执行
示例:自定义日志过滤器
// Filters/LoggingActionFilter.cs
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
namespace MyMvcApp.Filters
{
public class LoggingActionFilter : IActionFilter
{
private readonly ILogger<LoggingActionFilter> _logger;
public LoggingActionFilter(ILogger<LoggingActionFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation($"执行操作前: {context.HttpContext.Request.Path}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation($"执行操作后: {context.HttpContext.Request.Path}");
}
}
}
注册过滤器:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 添加服务到容器
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<LoggingActionFilter>(); // 全局过滤器
});
// 或者在控制器/操作上使用特性
[TypeFilter(typeof(LoggingActionFilter))] // 特性过滤器
public class ProductsController : Controller
{
// ...
}
5.3 视图组件(View Components)
视图组件类似于部分视图,但有自己的控制器逻辑:
创建视图组件:
// ViewComponents/ShoppingCartViewComponent.cs
using Microsoft.AspNetCore.Mvc;
namespace MyMvcApp.ViewComponents
{
public class ShoppingCartViewComponent : ViewComponent
{
public IViewComponentResult Invoke()
{
// 模拟购物车
var cartItems = new List<string> { "笔记本电脑", "智能手机", "平板电脑" };
return View(cartItems);
}
}
}
创建视图组件视图:
<!-- Views/Shared/Components/ShoppingCart/Default.cshtml -->
@model IEnumerable<string>
<div class="shopping-cart">
<h3>购物车 (@Model.Count() 项)</h3>
<ul>
@foreach (var item in Model)
{
<li>@item</li>
}
</ul>
</div>
在视图中使用:
<!-- 在布局文件或其他视图中 -->
@await Component.InvokeAsync("ShoppingCart")
<!-- 或者使用简写语法 -->
<vc:shopping-cart></vc:shopping-cart>
5.4 区域(Areas)
区域用于将大型MVC应用程序划分为更小的功能单元:
MyMvcApp/
├── Areas/
│ ├── Admin/
│ │ ├── Controllers/
│ │ │ └── ProductsController.cs
│ │ ├── Models/
│ │ ├── Views/
│ │ │ └── Products/
│ │ └── AdminAreaRegistration.cs
│ └── Customer/
│ ├── ...
└── ...
创建区域:
- 右键项目 → 添加 → 新建支架项 → 选择"区域"
- 输入区域名称(如"Admin")
访问区域中的控制器:
/Admin/Products/Index
六、MVC与数据库集成
6.1 使用Entity Framework Core
-
安装NuGet包:
dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Tools
-
创建DbContext:
// Data/ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;
using MyMvcApp.Models;
namespace MyMvcApp.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
// 其他DbSet...
}
}
- 配置服务:
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// 添加数据库上下文
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// 添加其他服务...
-
迁移数据库:
dotnet ef migrations add InitialCreate dotnet ef database update
-
修改控制器使用数据库:
// Controllers/ProductsController.cs (简化版)
public class ProductsController : Controller
{
private readonly ApplicationDbContext _context;
public ProductsController(ApplicationDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
return View(await _context.Products.ToListAsync());
}
// 其他操作...
}
七、MVC最佳实践
- 保持模型瘦小:模型只包含数据和简单业务逻辑,复杂逻辑放在服务层
- 使用视图模型:不要直接将领域模型传递给视图,使用专门的视图模型
- 合理使用部分视图:复用UI组件
- 实现适当的错误处理:使用中间件和过滤器处理错误
- 考虑性能:缓存频繁访问的数据
- 遵循RESTful原则:设计控制器操作时考虑资源导向
- 编写单元测试:为控制器和模型编写测试
八、完整示例:简单博客系统
8.1 模型
// Models/Post.cs
namespace MyMvcApp.Models
{
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime PublishedDate { get; set; }
public string Author { get; set; }
}
}
8.2 控制器
// Controllers/BlogController.cs
using Microsoft.AspNetCore.Mvc;
using MyMvcApp.Models;
using MyMvcApp.Data;
using Microsoft.EntityFrameworkCore;
namespace MyMvcApp.Controllers
{
public class BlogController : Controller
{
private readonly ApplicationDbContext _context;
public BlogController(ApplicationDbContext context)
{
_context = context;
}
// GET: Blog
public async Task<IActionResult> Index()
{
var posts = await _context.Posts.OrderByDescending(p => p.PublishedDate).ToListAsync();
return View(posts);
}
// GET: Blog/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var post = await _context.Posts
.FirstOrDefaultAsync(m => m.Id == id);
if (post == null)
{
return NotFound();
}
return View(post);
}
// GET: Blog/Create
public IActionResult Create()
{
return View();
}
// POST: Blog/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,Content,Author")] Post post)
{
if (ModelState.IsValid)
{
post.PublishedDate = DateTime.Now;
_context.Add(post);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(post);
}
}
}
8.3 视图
列表视图 (Views/Blog/Index.cshtml
):
@model IEnumerable<MyMvcApp.Models.Post>
@{
ViewData["Title"] = "博客文章";
}
<h1>博客文章</h1>
<p>
<a asp-action="Create" class="btn btn-primary">创建新文章</a>
</p>
@foreach (var item in Model)
{
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">@Html.DisplayFor(modelItem => item.Title)</h5>
<p class="card-subtitle mb-2 text-muted">
由 @Html.DisplayFor(modelItem => item.Author) 发布于
@Html.DisplayFor(modelItem => item.PublishedDate)
</p>
<p class="card-text">@Html.Raw(item.Content.Substring(0, Math.Min(200, item.Content.Length)))...</p>
<a asp-action="Details" asp-route-id="@item.Id" class="btn btn-sm btn-outline-primary">阅读更多</a>
</div>
</div>
}
详情视图 (Views/Blog/Details.cshtml
):
@model MyMvcApp.Models.Post
@{
ViewData["Title"] = Model.Title;
}
<h1>@Html.DisplayFor(model => model.Title)</h1>
<div>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Author)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Author)
</dd>
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.PublishedDate)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.PublishedDate)
</dd>
<dt class="col-sm-2">
内容
</dt>
<dd class="col-sm-10">
@Html.Raw(Model.Content)
</dd>
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id" class="btn btn-primary">编辑</a>
<a asp-action="Index" class="btn btn-secondary">返回列表</a>
</div>
九、总结
MVC模式为C#应用程序开发提供了一种结构化、可维护的方法。通过将应用程序分为模型、视图和控制器,您可以:
- 提高代码可维护性:清晰的组件边界使代码更易于理解和修改
- 增强可测试性:可以独立测试每个组件
- 促进团队协作:不同开发人员可以同时处理不同组件
- 实现更好的可扩展性:更容易添加新功能或修改现有功能
记住,MVC不是银弹,但对于大多数Web应用程序来说,它是一个经过验证的、可靠的选择。随着您对MVC模式的深入理解,您将能够构建出更专业、更高效的C#应用程序。