ASP.NET MVC 浅析

学习ASP.NET已经很久了,一直以来觉得ASP.NET 的MVC模式和WinForm的三层架构差不多。每次老师讲到MVC的时候都是略过不讲的,所以仅仅凭自己的一点点浅薄的认识,就以为MVC就是三层架构。这种想法不仅仅是错的,更是一种不负责任,不求甚解,人云亦云的不端正的科学态度。作为一名IT工作者,更应该以一种科学严谨的态度对待知识和学问,更应该学会独立的思考,而不是随波逐流,人云亦云。

这些天花了一些时间来把ASP.NET MVC 模式了解了下,觉得自己之前的认识实在是大错特错了。三层架构的模式在WinFom程序里边运用的比较多,现在的开发已经不拘于具体的模式了,甚至有N层架构的出现,我们要做的是如何在不拘于具体模式的前提下,提高软件系统的性能、开发的高效性、代码的复用性。MVC模式,ASP.NET MVC Framework是微软官方提供的MVC模式编写ASP.NET Web应用程序的一个框架,MVC(Model-View-Controller)用于表示一种软件架构模式.它把软件系统分为三个基本部分:模型(Model),视图(View)和控制器(Controller).,和三层架构的相似之处在于分层的思想,MVC模式很好的实现了UI、业务逻辑、数据库访问的分层,在mvc中这三部分分别被称之为视图(View)

控制器(Controller)和模型(Model),下面就这三部分的内容一一介绍。

与ASP.NET项目不同,ASP.NET MVC 项目建成之后项目文件目录如下:

(基本的文件夹的 用途):

  • App_Data :这个目录跟我们一般的ASP.NET website是一样的,用于存放数据。
  • Content :这个目录是建议用来存放一下资源文件的。例如CSS、JS、图片等等。当然你不愿意的话,完全可以不放到这里来。
  • Controllers :这个目录是建议将Controller类都放到这里来,方便管理。Controller类的命名必须以Controller结尾,例如一个名为Home的Controller则要命名为HomeController。
  • Models :这个目录是建议用来存放你的业务实体、数据访问层代码的类的。当然,更好的做法我觉得应该是将Models独立为一个类库。
  • Views :在默认情况下,所有的 view文件都必须放到这个目录下来,每一个Controller对应一个子目录,而且子目录的命名必须以Controller的命名一样。例如,HomeController的view就应该放到Home子目录中。我们见到Views目录下还有一个Shared的子目录,这个子目录是用于存放一些共享的view的,例如Error.aspx和Site.Master。Controller在Views\ControllerNmae 中找不到指定的view的时候,会到Shared中去寻找

下面进入具体的学习:

一、路由。

谈到MVC模式就不得不谈到路由,和传统的WebForm模式不同,WebFrom采用的是事件驱动模式,MVC采用的是路由驱动模式。ASP.NET路由模块负责将即将到来的浏览器请求映射到特定的MVC控制器动作,然后再由控制器进行调配,采取一些列的动作最后再将相应的视图呈现给大家。

在一个route中,通过在大括号中放一个占位符来定义( { and } )。当解析URL的时候,符号"/""."被作为一个定义符来解析,而定义符之间的值则匹配到占位符中。route定义中不在大括号中的信息则作为常量值。下面是一些示例URL

Valid route definitions

Examples of matching URL

{controller}/{action}/{id}

/Products/show/beverages

{table}/Details.aspx

/Products/Details.aspx

blog/{action}/{entry}

/blog/show/123

{reporttype}/{year}/{month}/{day}

/sales/2008/1/5

通常,我们在Global.asax文件中的Application_Start事件中添加routes,这确保routes在程序启动的时候就可用,而且也允许在你进行单元测试的时候直接调用该方法。

下面的示例是Global.asax中的代码,演示了添加一个包含两个URL参数actioncategoryName的Route对象:

    public class MvcApplication : System.Web.HttpApplication     {         public static void RegisterRoutes(RouteCollection routes)         {             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(                 "Default", // 路由名称                 "{controller}/{action}/{id}", // 带有参数的 URL                 new                 {                     controller = "Home",                     action = "Index",                     id = UrlParameter.Optional                 } // 参数默认值             );

        }

        protected void Application_Start()         {             AreaRegistration.RegisterAllAreas();

           //在程序启动的时候注册我们前面定义的Route规则

            RegisterRoutes(RouteTable.Routes);         } }

这些均为默认的设置

如果有特殊的需要也可以自定义配置路由规则,如下所示:(自定义路由)

routes.MapRoute(                "Category",                                              // Route name                "Category/{Detailid}",                           // URL with parameters                new{ controller ="Category", action ="Details" }  // Parameter defaults

            );

自定义路由添加到路由表中的路由顺序非常重要。新自定义Category路由在现有的Default路由前面。如果你将这个顺序颠倒过来,那么Default路由将总是被调用,而不是自定义路由。

当一个MVC应用程序首次运行时,会调用Application_Start()方法。这个方法随后调用了RegisterRoutes()方法。RegisterRoutes()方法创建了路由表。

默认的路由表包含了一个路由(名叫Default)。Default路由将URL的第一部分映射到控制器名,URL的第二部分映射到控制器动作,第三个部分映射到一个叫做id的参数。

假设你在浏览器的地址栏输入了下面的URL:

/Home/Index/1

默认的路由将这个URL映射为下面的参数:

Controller = Home

Action = Index

id = 1

当你请求URL /Home/Index/1时,将会执行下面的代码:

HomeController.Index(1)

Default路由包含了所有三个参数的默认值。如果你不提供控制器,那么控制器参数默认值为Home。如果你不提供动作,动作参数默认为值Index。最后,如果你不提供id,id参数默认为空字符串

此时对应的控制器中的方法为HomeController.cs

public ActionResult Index()         {              // imgDBEntity = new ImageDBEntity();             //ViewData["Message"] = "欢迎使用 ASP.NET MVC!";             //ViewData["Images"] = imgDBEntity.Imgs.ToList();             //return View(reporsitory.ListAll());

             return View();         }

另外在有些地方需要建立相应的路由约束,比如上面新添的路由Category,控制器公布的行动Details(int DetaillID)需要传入参数DetailID

public class ProductController : Controller     {         public ActionResult Details(int DetaillID)         {             return View();         }     } 代码会匹配:

/Category/12

/Category/333

等URL

但是如果有非数字字符出现的URL

/Category/abc

则会提示报错访问的URL不存在

另外比如你的Admin页不希望被访问到,这时就需要阻止某个路径匹配,这时候可以自定义一个路由,可以通过实现IRouteConstraint接口来实现一个自定义路由,它只描述了一个方法:

bool Match(     HttpContextBase httpContext,     Route route,     string parameterName,     RouteValueDictionary values,     RouteDirection routeDirection )

这个方法返回一个布尔值。如果返回了false,与约束相关联的路由将不会匹配浏览器请求

实现接口

public class LocalhostConstraint : IRouteConstraint     {         public bool Match             (                 HttpContextBase httpContext,                 Route route,                 string parameterName,                 RouteValueDictionary values,                 RouteDirection routeDirection             )         {             return httpContext.Request.IsLocal;         }

同时在Globle.cs中做如下配置

routes.MapRoute(                 "Admin",                 "Admin/{action}",                 new {controller="Admin"},                 new {isLocal=new LocalhostConstraint()}             );

这样如果不是本机访问就无法访问到Admin页。

二、视图(View)

与ASP.NET不同的是它本身并没有具体呈现的某个页,它仅仅是将要到达浏览器的URL请求映射为一个控制器动作,然后控制器动作进行一些列的动作将视图返回

例如:HomeController.cs中的Index动作

public ActionResult Index()         {             ViewData["Message"] = "欢迎使用 ASP.NET MVC!";             return View();         }

这个动作返回的是Index视图。我们所创建的大多动作都返回一个视图,但是动作是可以返回任何类型的动作结果的。

Index()动作包含了下面一行代码:

return View();

这行的代码返回了一个视图,该视图在服务器上的路径必须和下面的路径一样:

ViewsHomeIndex.aspx

视图的路径由控制器和控制器动作的名称推断得出。

与此同时你也可以显式地指明视图。下面一行代码返回了一个视图名为“Add”:

return View("Add");

当执行这行代码时,将会从下面的路径返回一个视图:

ViewsHomeAdd.aspx

接下来讲创建视图,视图的创建很简单,在View文件夹下建立和控制器同名的文件夹,比如本例的“Home”文件夹,然后在Home文件夹下点击右键添加,然后选择视图就可以了。

一般我们来向视图添加内容的时候会用到<%%>,在试图页,我们可以通过<%%>脚本执行一条或多条语句,例如:

<% Response.Write(DateTime.Now);%>

因为我们可能要频繁的使用Response.Wirte()这个方法,所以微软对此进行的封装<%= %>与<% Response.Write();%>是等效的。

除此之外,我们还可以通过HtmlHelper来生成视图内容,

例如:

<div >             <%using (Html.BeginForm())               { %>             <label for="firstName">First Name:</label>             <%=Html.TextBox("firstName")%>             <br />             <label for="lastName">Last Name:</label>             <%=Html.TextBox("lastName")%>             <%} %>             <br />             <input type="submit" value="Submit" />            </div>

生成如下效果:

在MVC3框架下可以直接这样用

@using (Html.BeginForm())         {             @Html.ValidationSummary()             <P>Your Name:@Html.TextBoxFor(x=>x.Name)</P>             <p>Your Email:@Html.TextBoxFor(x=>x.Email)</p>             <p>Your Phone:@Html.TextBoxFor(x=>x.Phone)</p>       }         <input type="submit" value="Submit RSVP" />       

在MVC中,构建数据是controller的工作,将数据作为HTML的呈现是View的工作,很明显这里有一个将数据从Controller传递到View的过程。可以通过ViewData属性来传递视图,

HomeController.cs中  

public ActionResult Index()         {             imgDBEntity = new ImageDBEntity();             ViewData["Message"] = "欢迎使用 ASP.NET MVC!";                         return View();         }

在Index.aspx页

    <h2><%= Html.Encode(ViewData["Message"]) %></h2>

这样就可以显示数据。

与此同时,其中的一种方式就是通过ViewBag,ViewBag是Controller基类的一个成员,它是一个动态的对象,我们可以给它赋予任意的属性值,并在View中呈现

public ViewResult Index()         {               ViewBag.Hello ="Olive";             return View();         }

在Index.aspx

    <h2><%= Html.Encode(ViewBag.Hello) %></h2>

三、控制器(Controller)

在MVC模式中,控制器就相当于一个分发器,通过响应相应的行为,然后和Model层进行交互,提取请求所需的内容,进而返回一个视图,或者另一个行为。

控制器的创建可以在项目的Controller文件下,点击右键添加Controller文件即可。

例如HomeController.cs

[HandleError]     public class HomeController : Controller     {         public ActionResult Index()         {             ViewData["Message"] = "欢迎使用 ASP.NET MVC!";             return View();         }         [AcceptVerbs(HttpVerbs.Post)]         public ActionResult Index(FormCollection formCollection)         {             var move=new  Movie();             move.ID = 3;             TryUpdateModel(move, new string[] { "firstName", "lastName" }, formCollection.ToValueProvider());             MoviesDataContext mv = new MoviesDataContext();             mv.Movie.InsertOnSubmit(move);                         return View("Index");

        }         public ActionResult Add()         {             return View();         }

我们上边所说的动作就是控制器的一个方法,当你在浏览器输入一个Url时,相应的控制器会执行相应的动作,也就是相应的方法。例如:

http://localhost/Home/Index

在本例中,Index()方法在HomeController类上被调用。一个控制器动作必须是控制器类的一个公共方法。控制器动作来使用的方法不能够重载。另外,控制器动作不能为静态方法。

控制器动作执行完以后需要返回给浏览器一些东西,即我们所说的控制动作结果

ASP.NET MVC框架支持六种标准类型的动作结果:

  1. ViewResult – 代表HTML及标记。
  2. EmptyResult – 代表无结果。
  3. RedirectResult – 代表重定向到一个新的URL。
  4. RedirectToRouteResult – 代表重定向到一个新的控制器动作。
  5. JsonResult – 代表一个JSON(Javascript Object Notation)结果,它可以用于AJAX应用程序。
  6. ContentResult – 代表着文本结果。

所有这些动作结果都继承自ActionResult基类。在大多数情况下,控制器动作 ViewResult。ContentResult动作结果很特别。你可以使用ContentResult动作结果来将动作结果作为纯文本返回。

四、模型(Model)

MVC模型包含了所有MVC视图或者MVC控制器没有包含的应用程序逻辑,一个MVC模型包含了所有的应用程序业务和数据访问逻辑,所以模型往往被称作是MVC的核心。

构建数据访问类的方法有很多,而且ASP.NET与任何数据访问都可以很好的融合,这里主要讲Liinq to Sql与MS数据库交互。

首先在App_Data文件夹下创建数据库,然后再创建一个文件表 Imgs,具体如下:

主键自增。

下边接着创建Linq to Sql 类,在Model文件夹下右键添加,然后选中左侧列表里的Data项,选中里边的Linq to Sql 将会立即出现“对象关系设计器(Object Relational Designer)”。此时,你可以将数据库表从“服务器资源管理器(Server Explorer)”窗口中拖曳到“对象关系设计器”中,来创建代表着特定数据库表的LINQ to SQL类。这里我们添加Imgs 表。如图:


          public ActionResult Index(){
               var dataContext = new ImgsDataContext();                var imgs = from m in dataContext.Imgs                     select m;                return View(imgs.ToList());           } 此时同时也要修改Index页的内容,进行数据的显示:

代码如下:Index.aspx

            <div>            <%foreach (Imgs im in (IEnumerable)ViewData.Model)//要注意此出需要将ViewData.Model进行强制转换下否则无法进行佛reach遍历              {%>              <%=im.Name %>              <%=im.Title %>           <img src=" <%=im.Url %> " />

<div>

同时还要在页面的开始部位引入<%@ Import Namespace="MVC1.Models" %>命名空间 这样就可以很好的显示数据了

效果如图:

后记:这篇算是对这几天的学习的一个总结和反思吧,希望能对有兴趣的朋友有一点帮助。如果有说的不对的地方还请拍砖!

原文地址:https://www.cnblogs.com/Olive116/p/MVC.html