ASP.Net:(6)MVC编程入门指南

作者:陆金龙    发表时间:2016-08-21 15:04   


1.MVC项目创建

1.1 新建一个ASP.NET Web应用程序项目

在VS2015中,通过文件 -> 新建 -> 项目,弹出新建项目窗体,如下图。在左侧模板选中Visual C#下的Web,右侧选中ASP.NET Web应用程序,窗体底部输入项目名称和解决方案名称,选择项目存放位置,点击下一步继续。

1.2 选择MVC模板

在弹出的选择模板窗体,选中MVC,点击确定即完成项目创建。

2.MVC路由

2.1 注册路由

打开项目根目录下的全局应用程序类Global.asax,可以看到在Application_Start中完成了路由的注册:RouteConfig.RegisterRoutes(RouteTable.Routes)。

路由注册方法只被Application_Start方法调用一次,静态方法、静态变量保证每次请求都能有效。

转到RouteConfig.RegisterRoutes,可以查看其内部的已经提供了一个默认的路由。

其中:

name: "Default", //Default是这个路由的名称

url: "{controller}/{action}/{id}" //路由的规则

defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

//缺省情况下,访问Home控制器下的Index这个Action,id的值从Url中获取,且是可选的,即可不传入。

没有id参数时,http://localhost:2575/ 等效于 http://localhost:2575/Home/Index

有id参数时,使用完整路由,如http://localhost:2575/Home/Index/2

2.2 注册多个路由

2.2.1 添加路由注册

在RouteConfig.RegisterRoutes中添加routes.MapRoute代码即可,如下添加了名为List和Item的两个路由:

 public static void RegisterRoutes(RouteCollection routes)

 {

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 

  routes.MapRoute(

name: "Default",

...

);

 

routes.MapRoute(

name: "List",

url: "{controller}/{action}/{section}/{category}",

defaults: new { controller = "Article", action = "List", section = UrlParameter.Optional, category = UrlParameter.Optional}

);

 

routes.MapRoute(

name: "Item",

url: "{controller}/{action}/{section}/{id}/html",

defaults: new { controller = "Article", action = "Item", section = UrlParameter.Optional, id = UrlParameter.Optional}

);

}

 

2.2.2 测试路由访问

对Article控制器下List的实现:

    // GET: Article/List/02/07

        public ActionResult List(string section,string category)

        {

            ViewBag.Section = section;

            ViewBag.Category = category;

            return View();

        }

 

视图代码:

<!DOCTYPE html>

<html>

<head>

    <meta name="viewport" content="width=device-width" />

    <title>List</title>

</head>

<body>

    <h3> 

        文章列表数据

    </h3>

    <div>栏目:@ViewBag.Section</div>

    <div>类别:@ViewBag.Category</div>

</body>

</html>

 

对Article控制器下Item的访问测试如下,代码略:

2.3 路由规则

注意:多种路由规则优先匹配前面的。

(1)伪静态的路由规则

routes.MapRoute(

              name: "Default",

              url: "{controller}/{action}/{id}.html",

              defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

            );

(2)2层路由规则

routes.MapRoute(

name: "Default",

url: "{controller}/{action}-{id}.html",

defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

);

 

(3)带命名空间的路由

     routes.MapRoute(

        name:"AdminControllers", // 路由名称

        url:"Admin/{controller}/{action}/{id}", // 带有参数的 URL

        defaults:new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // 参数默认值

        namespaces:new string[] { "Admin.Controllers" }//命名空间

   );

(4)带约束规则的路由:

    routes.MapRoute(

         "RuleControllers",

         "{controller}/{action}-{Year}-{Month}-{Day}}",

          new { controller = "Home", action = "Index", Year = "2010", Month = "04", Day = "21" },

         new { Year = @"^\d{4}", Month = @"\d{2}" } //4位数 2位数

     );

   第4行位约束规则,约束了参数Year为4位数,Month为2位数。

 

(5)捕获所有路由

      routes.MapRoute(

           "All", // 路由名称

           "{*Vauler}", // 带有参数的 URL

          new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值

     );

3.布局页

布局页的作用,相当于Asp.Net WebForm中的母板页。MVC中使用布局页的方法如下:

在Article控制器下写一个与Item实现完全一样的Action

public ActionResult LayoutItem(string section, int id)

{

ViewBag.Section = section;

ViewBag.Message = id.ToString();

return View();

}

创建视图时,选择使用布局文件:

 

生成的视图文件中,Layout这一项指定了布局页,且视图文件中不再包含html,head,body这些标签。

@{

    ViewBag.Title = "LayoutItem";

    Layout = "~/Views/Shared/_kl_layout.cshtml";

}

<div>栏目:@ViewBag.Section</div>

<div>

    第<label>@ViewBag.Message</label>篇文章

</div>

页面效果如下:

 

4.区域

4.1 添加区域

项目的右键菜单中添加-区域,在弹出的窗体输入区域名称,点击“添加”按钮即可。

4.2 路由处理控制器重名

创建一个Article控制器,控制器中定义名为List的Action,实现与之前的Article控制器一样。

AdminAreaRegistration下RegisterArea方法中添加路由规则

context.MapRoute(

               name: "Admin_List",

               url: " Admin/{controller}/{action}/{section}/{category}",

               defaults: new { controller = "Article", action = "List", section = UrlParameter.Optional, category = UrlParameter.Optional }

           );

访问原来Article下的List时,报如下错误:

   

  解决方案:在路由规则中添加命名空间,如下

   context.MapRoute(

               name: "Admin_List",

               url: " Admin/{controller}/{action}/{section}/{category}",

               defaults: new { controller = "Article", action = "List", section = UrlParameter.Optional, category = UrlParameter.Optional }

               namespaces: new string[] { "Admin.Controllers" }//命名空间

           );

5.控制器

5.1 控制器

5.1.2 控制器的跳转

RedirectToAction("Action name","Controller name");
return RedirectToAction("Index","Home");//跳转到首页。
第一个参数是action 的名字,第二个参数是控制器controller的名字,方法返回的是个ActionResult.也就是返回视图。

 

5.2 ActionResult及其子类对照表

ActionResult及其子类

说明

ViewResult

表示HTML的页面内容

EmptyResult

表示空白的页面内容

RedirectResult

表示定位到另外一个URL

JsonResult

表示可以运用到AJAX程序中JSON结果

JavaScriptResult

表示一个JavaScript对象

ContentResult

表示一个文本内容

FileContentResult

表示一个可以下载的、二进制内容的文件

FilePathResult

表示一个可以下载的、指定路径的文件

FileStreamResult

表示一个可以下载的、流式的文件

 

Controller中的方法

返回对象

View

ViewResult

Redirect

RedirectResult

RedirectToAction

RedirectToActionResult

RedirectToRoute

RedirectToRouteResult

Json

JsonResult

JavaScriptResult

JavaScriptResult

Content

ContentResult

File

FileContentResult、FilePathResult、FileStreamResult

 

5.3 为Action创建视图

在控制器的Action上点击右键,在右键菜单选择“添加视图”,即可弹出创建视图窗体。

如果是后台管理界面,可以选择根据创建、删除、编辑等选择相应的模板;同时可为该视图选择布局页:

6.视图

6.1 MVC传值

6.1.1 MVC视图引擎

Mvc3引用了一个新的视图引擎Razor,一个项目里面可同时支持aspx和Razor。

 

Razor引擎与aspx引擎语法格式对比(右侧是Razor引擎语法):写C#代码更简化。

6.1.2 ViewData传值

在Controller中定义如下:

ViewData[“Message”] = “Hello word!”;

在View中读取Controller中定义的ViewData数据,代码如下:

<% = Html.Encode(ViewData[“Message”]) %>

 

在Controller定义如下:

public ActionResult Index()

    {

Article art = new Article();

        art .Title = "标题";

        art .content = "文章内容";

        ViewData["hello"] = "hello!";

        return View(art );

     }

在View中读取,代码如下:

<% var user = this.ViewData.Model; %>

<%=user.Name %>

<%=user.Age %>

<% = Html.Encode(ViewData[“hello”]) %>

 

6.2 使用强类型数据

6.2.1 类型定义

namespace MvcApp.Models

{

    public class UserInfo

    {

        public string Name { get; set; }

        public int Id { get; set; }

        public string Address { get; set; }

        public string Phone { get; set; }

    }

}

6.2.2 往前端传递强类型数据

控制器:

    public ActionResult ShowUserInfo()

    {

        UserInfo userInfo = new UserInfo();

        userInfo.Id = 2;

        userInfo.Name = "<br/> ded";

        userInfo.Phone = "dsfdsfs";

        userInfo.Address = "公交站";

        ViewData.Model = userInfo;

        return View();

//或以上两行改为 return View(userInfo);

}

前台页面绑定:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MvcApp.Models.UserInfo>" %>

<body>

    <div>

    <%: Model.Id %>

    <span>

        <%: Model.Name %>

</span>

</div>

<div>

        @Model.Phone

    </div>

</body>

6.2.3 前端向后台提交数据

(1)页面中的元素:

   <div>

        <form id="frmSubUser" method="POST" action="/UserInfo/Create">

            姓名:<input type="text" name="Name"/><br/>

            编号:<input type="text" name="Id"/><br/>

            地址:<input type="text" name="Address"/><br/>

            电话:<input type="text" name="Phone"/><br/>  

            <input type="submit" value="提交"/>

        </form>

    </div>

(2)控制器中的处理方法:

    public ActionResult ProcessCreate(UserInfo user,string Id)

{

   if(String.isNullOrEmpty(Id))

   {

           AddUser(user);

        }

       else

  {

  UpdateUser(user);

   }

       return Content("ok");

    }

    如果元素名称与参数名或参数的属性名相同,post过来的数据会自动组装到对应的参数或属性

6.2.4 MVC4版本写法

@using KL.CMS.Model

@model KL.CMS.Model.Dat_article

<h2 >@Model.Title</h2> <!--使用@Model输出文本-->

<div >@Html.DisplayFor(model => model.CreateTime)</div><!--使用@Html和@model输出文本-->

<div id="divcontent" class="col-md-10">@Html.Raw(Model.Content)</div> <!--输出原生html,而不是文本-->

6.3 HtmlHelper

6.3.0 HtmlHelper控件清单

Html.ActionLink

Html.RouteLink

Html.TextBox

Html.Hidden

Html.TextArea

Html.CheckBox

Html.ListBox

Html.DropDownList

Html.BeginForm

Html.EndForm

Html.Partial  在视图内加载部分视图,如:@Html.Partial("_LoginPartial")

6.3.1 超链接

如果路由规则会变化,使用一个url.Action()方法来得到与路由规则匹配的url地址:

也可以使用HtmlHelper类得到超链接:

6.3.2 Form表单及单值表单元素

6.3.3 多值表单元素RadioButton

@Html.RadioButton("Gender","1")

@Html.RadioButton("Gender","2")

@Html.RadioButton("Gender","3") <br/>

 

@Html.RadioButton("Sex","1")

@Html.RadioButton("Sex", "2")<br/>

6.3.4 多值表单元素DropDownList

(1)控制器

public class HomeController : Controller

{

   public ActionResult Index()

   {

       ViewData["Message"] = "欢迎使用 ASP.NET MVC!";

       ViewData["ddl"] = new List<SelectListItem>

       {

            new SelectListItem(){Selected = false,Text = "北京",Value = "2"},

            new SelectListItem(){Selected = false,Text = "天津",Value = "3"},

            new SelectListItem(){Selected = true,Text = "西红柿",Value = "4"},

       };

       return View();

   }

}

(2)页面body中

   @Html.DropDownList("ddl")<br/>

   浏览页面即可显示控件及内容

6.4 Html编码处理

6.4.1 输出Html编码的字符串

即将字符串进行Html编码,让浏览器对其只做文本显示,而不作为Html解析和处理。

<% : %>语法相对于<%= %>,对后台的数据具有Html编码作用

<% : getString()%> 相当于以下这行

<%= Html.Encode(getString())%>

6.4.2 输出未经Html编码的字符串

即输出原生html,而不是文本。

在Razor Beta 2以前的版本可以:@(new HtmlString(mystring))

以后的版本可以:@Html.Raw(mystring)

6.5 表单验证

6.5.1 基本使用步骤

 与Asp.Net中使用方式基本相同,无侵入方式的。

(1)引入jquery.js和jquery.validate.js;

(2)写好表单frmUser及表单元素;

(3)在$(function(){});函数中定义校验规则和错误提醒消息。

效果如下:

6.5.2 修改提醒消息的样式

修改类样式.error,将颜色改为红色,如下:

7.过滤器

7.1 过滤器介绍

有时候想在调用Action方法之前或者之后处理一些逻辑,为了支持这个,ASP.NET MVC允许你创建Filter。

Action过滤器是自定义的Attributes,用来标记添加Action方法之前或者Action方法之后的行为到控制器类中的Action方法中。这些逻辑可以是:

日志,异常处理

身份验证和授权

输出缓存

网络爬虫的过滤

防盗链

本地化

7.2 Action过滤器

public class FilterNameAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//执行Action时
}

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//执行Action后

}


public override void OnResultExecuting(ResultExecutingContext filterContext)
{
  //执行结果时
 }

public override void OnResultExecuted(ResultExecutedContext filterContext)
{
//执行结果时后

}
}

 

[FilterName]

public ActionResult Index()

{

return View();

}

8.MVC调试:监视请求

8.1 MVC中设置启用跟踪

在页面Page指令中设置:Trace=”true”

8.2 浏览器中查看跟踪结果

F12开启开发人员工具监视

查看请求报文:

查看响应报文:

查看请求响应耗时:

9.MVC部署:连接问题

9.1 登录失败

报错信息:用户 'IIS APPPOOL\ASP.NET v4.0' 登录失败

因为程序连接SQLServer的连接字符串是用了windows集成登陆,可以改成用数据库帐号密码登陆。连接字符串的写法是:server=localhost;uid=sa;pwd=xxxx;database=master;

9.2 EF连接名已存在

修改连接字符串后,报如下错误。网上查到的说法可能是有重名的连接。

清缓存、重启、反复检查只有一个连接字符串,但始终报下面的错误:

The entry "TreasstockEntities" has already been added  

加上一句:<remove name="Security"/>或者<clear/> 也没有任何效果。

没有办法了,既然提示连接名已经添加了,干脆重新生成一个名为“TreasstockEntity”的EF上下文,所有用到“TreasstockEntities”类的地方都改为“TreasstockEntity”。重新发布到IIS,刷新,数据成功显示,问题解决!

9.3 'ViewBag' does not exist 

CS0103: The name 'ViewBag' does not exist in the current context

是因为View下的web.config文件被删除了,创建一个新的mvc项目,从中拷贝一个web.config过来,修改namespace为当前项目即可。