[关闭]
@wang9563 2017-05-26T12:22:16.000000Z 字数 3273 阅读 1792

关于在目前 WebForm 项目中混用 MVC

问题思考


我们目前的 SongshuERP 项目采用 WebForm 作为主要开发框架,但在实际使用中我们更倾向于 MVC 的开发方式,并在 SongshuERP.Web.UI.dll 的 ManagePage 基类中定义的处理请求的方式。

现在我们尝试在原先用 WebForm 写的代码无需修改为前提,后续新模块直接使用 MVC 进行开发,以下则是介绍了最初版新的开发模式,望大家给予建议不断完善。


1、SongshuERP.Mvc 项目结构

目前对原有项目进行了如下更改:

  • 新增了项目 SongshuERP.Mvc 用存放 MVC的业务代码,并在 SongshuERP.Web 中引用
  • SongshuERP.WebGlobal.asax 中增加了对 SongshuERP.Mvc 的初始化,不需要引用任何 MVC 组件的库

项目结构

Areas

存放各模块的业务代码,比如 仓储管理 财务管理 等,此处定义了两个文件夹 Admin 和 Demo 表示业务功能不同的两个模块,各自模块下均有 Controller 和 Register

*Controller.cs (例如: HelpController RuleController TestController

实现具体的业务功能,比如 CURD 、逻辑计算等

Register.cs

注册当前模块的路由,不同的模块有不同的实现,建议默认按 {module}/{controller}/{action} 进行路由配置,如注册一条路由 {admin}/{controller}/{action} 后,通过 URL http://ip:port/admin/help/index 可访问 Admin 模块下 HelpController 的 Index 方法

PS. 也可以根据自己的业务需要,注册当前模块下的多条路由

Core

存放没有具体业务逻辑的基础组件、帮助类等,如本项目中所有 Controller 的基类 BaseController

ValidateAttribute

存放验证 Model 的 Attribute 类型

Dto

存放用户数据传输的 Model,可以根据需要的 Request 定义 Model 类,如 TestLoginInput


2、如何增加一个模块功能

假设需要为一个叫 仓储(Warehouse)的模块增加部分功能,可以按照如下流程编写代码

  • 在 Areas 下建立采购模块 Purchase 文件夹,按照功能编写 Controller 如 采购订单(OrderController) 预入库(InStockController) 采购分析(AnalysisController) 等代码

文件夹

  • 添加 Register.cs 并通过以下代码注册本模块的默认路由
  1. using System.Web.Mvc;
  2. namespace SongshuERP.Mvc.Areas.Purchase
  3. {
  4. public class Register : AreaRegistration
  5. {
  6. public override string AreaName => "Purchase";
  7. public override void RegisterArea(AreaRegistrationContext context)
  8. {
  9. context.MapRoute(
  10. "purchase_default",
  11. "purchase/{controller}/{action}");
  12. }
  13. }
  14. }
  • 关于实现功能代码可参考 Demo 下的 TestController 实现

接受 Reuqest 参数的可以通过以下三种方式 不区分大小写

1、直接通过上下文的 Request 对象取值

  1. public ActionResult Login()
  2. {
  3. var email = Request["email"];
  4. var pwd = Request["pwd"];
  5. var code = Request["pwd"];
  6. if (email == "xunkiz@dingtalk.com")
  7. return Json(new { error = "您的账号被禁用了~" });
  8. return Json(new { nick = "鼠西奥" });
  9. }

2、通过参数传入

  1. public ActionResult Login(string email, string pwd, string code)
  2. {
  3. if (email == "xunkiz@dingtalk.com")
  4. return Json(new { error = "您的账号被禁用了~" });
  5. return Json(new { nick = "鼠西奥" });
  6. }

3、通过参数传入,Model 实体对象 字段必须定义成属性

  1. public ActionResult Login(TestLoginInput input)
  2. {
  3. if (input.Email == "xunkiz@dingtalk.com")
  4. return Json(new { error = "您的账号被禁用了~" });
  5. return Json(new { nick = "鼠西奥" });
  6. }
  7. public class TestLoginInput
  8. {
  9. [Required(ErrorMessage = "邮箱不能为空")]
  10. [Mail(ErrorMessage = "邮箱不合法")]
  11. public string Email { get; set; }
  12. [StringLength(6, ErrorMessage = "密码不能超过6位")]
  13. public string Pwd { get; set; }
  14. public string Code { get; set; }
  15. }

在第三种方法中,支持用定义好的 Attribute 来完成验证,其他两种均需要手工实现。第三种方法的实现在 BaseController 中的 OnActionExecuting(请求处理前) 方法中进行了验证,如下代码:

  1. //验证 Model 是否通过
  2. foreach (var m in ModelState.Values)
  3. {
  4. var error = m.Errors.FirstOrDefault();
  5. if (error == null) continue;
  6. filterContext.Result = Json(new SsOutput { ErrMsg = error.ErrorMessage });
  7. return;
  8. }

关于 Response 响应报文的说明

因为目前都是前端通过 ajax 请求后端的服务,所以定义了 SsOutPut 和 SsOutPut,并声明了他们的隐式转换,如下代码:

  1. public SsOutput<Model> Login3(TestLoginInput input)
  2. {
  3. if (input.Email == "xunkiz@dingtalk.com")
  4. return "您的账号被禁用了~";
  5. return new Model { sign_date = DateTime.Now };
  6. }

如果需要报错,直接返回 string 就会被识别成 ErrMsg 并返回到前端
如果是正常返回内容,直接返回 Model 实例即可,会被识别成 Data 并返回到前端
PS. 当你的 Model 就是 string 类型时,隐式转换会冲突,此时只能手写返回内容

  1. public SsOutput<string> Login(TestLoginInput input)
  2. {
  3. if (input.Email == "test")
  4. return new SsOutput<string> { ErrMsg = "您的账号被禁用了~" };
  5. return new SsOutput<string> { Data = "登录成功!" };
  6. }

通过 Controller 的 Json 方法返回值,以及通过返回 SsOutput 类型的值的 Content-Type 均是 application/json,所以可在前端 ajax 的 success 中直接当对象来使用

  1. $("#login").click(function () {
  2. $.post({
  3. url: "/demo/test/login",
  4. data: { email: $("#email").val(), Pwd: $("#pwd").val(), Code: $("#code").val() },
  5. success: function (data) {
  6. if (data.IsError) {
  7. alert(data.ErrMsg);
  8. } else {
  9. //处理正常的业务
  10. }
  11. }
  12. });
  13. });
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注