C#之MVC模式

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的优势

  1. 关注点分离:将业务逻辑、用户界面和控制流程分开
  2. 可维护性:修改一个组件通常不需要影响其他组件
  3. 可测试性:可以独立测试每个组件
  4. 可扩展性:更容易添加新功能或修改现有功能

二、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工作流程

  1. 用户请求:用户通过浏览器发送请求(如/Products/Index
  2. 路由解析:ASP.NET Core路由系统将请求映射到ProductsController的Index方法
  3. 控制器处理
    • 执行Index方法
    • 可能从模型获取数据
    • 选择适当的视图
  4. 视图渲染
    • 视图接收模型数据
    • 生成HTML响应
  5. 响应返回:将生成的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提供了多种过滤器:

  1. 授权过滤器[Authorize]
  2. 资源过滤器:在模型绑定前后执行
  3. 操作过滤器:在操作方法执行前后执行
  4. 异常过滤器[HandleError]
  5. 结果过滤器:在操作结果执行前后执行

示例:自定义日志过滤器

// 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/
│       ├── ...
└── ...

创建区域

  1. 右键项目 → 添加 → 新建支架项 → 选择"区域"
  2. 输入区域名称(如"Admin")

访问区域中的控制器

/Admin/Products/Index

六、MVC与数据库集成

6.1 使用Entity Framework Core

  1. 安装NuGet包

    dotnet add package Microsoft.EntityFrameworkCore.SqlServer
    dotnet add package Microsoft.EntityFrameworkCore.Tools
    
  2. 创建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...
    }
}
  1. 配置服务
// Program.cs
var builder = WebApplication.CreateBuilder(args);

// 添加数据库上下文
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

// 添加其他服务...
  1. 迁移数据库

    dotnet ef migrations add InitialCreate
    dotnet ef database update
    
  2. 修改控制器使用数据库

// 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最佳实践

  1. 保持模型瘦小:模型只包含数据和简单业务逻辑,复杂逻辑放在服务层
  2. 使用视图模型:不要直接将领域模型传递给视图,使用专门的视图模型
  3. 合理使用部分视图:复用UI组件
  4. 实现适当的错误处理:使用中间件和过滤器处理错误
  5. 考虑性能:缓存频繁访问的数据
  6. 遵循RESTful原则:设计控制器操作时考虑资源导向
  7. 编写单元测试:为控制器和模型编写测试

八、完整示例:简单博客系统

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#应用程序开发提供了一种结构化、可维护的方法。通过将应用程序分为模型、视图和控制器,您可以:

  1. 提高代码可维护性:清晰的组件边界使代码更易于理解和修改
  2. 增强可测试性:可以独立测试每个组件
  3. 促进团队协作:不同开发人员可以同时处理不同组件
  4. 实现更好的可扩展性:更容易添加新功能或修改现有功能

记住,MVC不是银弹,但对于大多数Web应用程序来说,它是一个经过验证的、可靠的选择。随着您对MVC模式的深入理解,您将能够构建出更专业、更高效的C#应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值