首页 后端开发 C#.Net教程 [ASP.NET MVC 小牛之路]09 - Controller 和 Action (1)

[ASP.NET MVC 小牛之路]09 - Controller 和 Action (1)

Dec 30, 2016 pm 04:00 PM

[ASP.NET
MVC 小牛之路]09 - Controller 和 Action (1)

我们知道,在 MVC 中每个请求都会提交到 Controller 进行处理。Controller 是和请求密切相关的,它包含了对请求的逻辑处理,能对 Model 进行操作并选择 View 呈现给用户,对于业务和数据的逻辑代码以及接口和辅助类库等一般都不放到 Controller 中。

Controller 和 Action 的内容较多,我把它分成了两篇,也可能会分成三篇。本篇介绍 Controller 的实现、Controller 对状态数据的获取、ActionResult 和 Action 的数据传递,后续将介绍 Controller 工厂、Action Invoker 和暂时还没想好或正在学习的一些较高级的特性。

本文目录


继承 IController 接口

在本系列前面的文章中,我们添加的 Controller 都是一个继承自抽象类 System.Web.Mvc.Controller 的普通类(请注意:controller(或Controller) 和 Controller 类在本文是两个意思,请在阅读本文时根据上下文理解)。Controller 抽象类封装了很多很实用的功能,让开发人员不用自己去写那些重复烦琐的处理代码。

如果不使用封装的 Controller 抽象类,我们也可以通过实现 IController 接口来创建自己的 controller。IController 接口中只有一个 Exctute 方法:

public interface IController { 
    void Execute(RequestContext requestContext); 
}
登录后复制

Controller 接口在 System.Web.Mvc 命名空间下,一个结构非常简单的接口。

当请求送到一个实现了 IController 接口的 controller 类时(路由系统通过请求的URL能够找到controller),Execute 方法被调用。

下面我们创建一个空的 MVC 应用程序,在 Controllers 文件夹下添加一个实现了 IController 的类,并做一些简单的操作,如下:

using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication1.Controllers {
    public class BasicController : IController {
        
        public void Execute(RequestContext requestContext) {
            
            string controller = (string)requestContext.RouteData.Values["controller"];
            string action = (string)requestContext.RouteData.Values["action"];
            
            requestContext.HttpContext.Response.Write(
                string.Format("Controller: {0}, Action: {1}", controller, action));
        }
    }
}
登录后复制

运行应用程序,URL 定位到 /Basic/Index(你可以把 Index 改成其他任意片段名称),结果如下:

790.png

实现了 IController 的类,MVC就会辨识它为一个 controller 类,根据 controller 名把对应的请求交给这个类处理。

但对于一个稍稍复杂的应用程序,自己实现 IController 接口是要做很多工作的,我们很少会这么做。通过这我们更好地理解了 controller 的运行,controller 中一切对请求的处理都是从 Execute 方法开始的。


继承 Controller 抽象类

MVC 允许我们自由地进行自定义和扩展,比如像上面讲的你可以实现 IController 接口来创建对各类请求的各种处理并生成结果。不喜欢 Action 方法或不关心 View,那么你可以自己动手写一个更好更快更优雅的 controller 来处理请求。但像前面说的,自己实现 IController 接口要做很多工作,最重要的是没有经过长期实践测试,代码的健壮性得不到保证, 一般不建议你这么做。MVC 框架的 System.Web.Mvc.Controller 类,提供了足够实用的特性来方便我们对请求的处理和返回结果。

继承 Controller 类的 controller 我们已经使用过很多次了,对它已经有一定的了解,它提供了如下几个关键的特性:

Action方法:一个 Controller,它的行为被分为多个方法,通常一个方法对应着一个请求,并且可以通过方法参数来取得请求传递过来的数据。
ActionResult:可以返回一个描述了 Action 方法执行结果的对象,这样的好处是想返回什么结果就指定对应的返回对象就行,不用关心怎么去执行并生成结果。
Filters:通过C#特性,对某一种行为的处理(比如授权和验证)进行封装,方便了在多个 Controller 和 Action 方法之间进行重用。

所以,如果你不是因为特殊的需求或闲得蛋疼,创建一个满足要求的 Controller 最好的途径是继承 Controller 抽象类。由于之前我们已经使用过多次,这里就不再进行具体的演示了,但我们还是来看一下它的代码结构。

在 Controllers 文件夹下添加一个 Controller,VS 已经把类的结构帮我们生成好了,如果你喜欢整洁,会习惯性地把不需要用到的引用删掉,代码如下:

using System.Web.Mvc;

namespace MvcApplication1.Controllers {
    
    public class DerivedController : Controller {
        
        public ActionResult Index() {
            ViewBag.Message = "Hello from the DerivedController Index method";
            return View("MyView");
        }
    }
}
登录后复制

我们可以查看 Controller 抽象类的定义,发现它是继承 ControllerBase 类的,在 ControllerBase 类中实现了 IController 接口的 Execute 方法,这个方法是MVC对请求进行处理的各个组件的入口,其中包括通过路由系统找到 Action 方法并调用。

Controller 类内部使用 Razor 视图系统来呈现 View,这里通过 View 方法,指定 View 的名称参数来告诉 MVC 选择 MyView 视图来返回给用户结果。


在 Controller 中获取状态数据

我们经常需要访问客户端提交过来的数据,比如 QueryString 值、表单值和通过路由系统来自 URL 的参数值,这些值都可称为状态数据。下面是 Controller 中获取状态数据的三个主要来源:

一系列的上下文对象。
传递给 Action 方法的参数。
显式的调用框架的模型绑定(Model Binding)特性。

从上下文对象中获取状态数据

获取状态数据最直接的方法就是从上下文对象中提取。当你创建了一个继承自 Controller 类的 Controller 时,可以通过一系列的属性可以方便的访问到和请求相关的数据,这些属性包括 Request、Response、RouteData、HttpContext 和 Server,每一个都提供了请求相关的不同类型的信息。下面列出了最常的上下文对象:


791.png

在 Action 方法中可以使用任意上下文对象来获取请求相关的信息,如下面在 Action 方法中所演示的:

...
public ActionResult RenameProduct() {
    //访问不同的上下文对象
    string userName = User.Identity.Name;
    string serverName = Server.MachineName;
    string clientIP = Request.UserHostAddress;
    DateTime dateStamp = HttpContext.Timestamp;
    AuditRequest(userName, serverName, clientIP, dateStamp, "Renaming product");
            
    //从POST请求提交的表单中获取数据
    string oldProductName = Request.Form["OldName"];
    string newProductName = Request.Form["NewName"];
    bool result = AttemptProductRename(oldProductName, newProductName);

    ViewData["RenameResult"] = result;
    return View("ProductRenamed");
}
...
登录后复制

这些上下对象不用特意去记,用的时候,你可以通过VS的智能提示来了解这些上下文对象。

使用 Action 方法参数获取状态数据

在本系列的前面的文章中,我们已经知识如何通过 Action 参数来接收数据,这种方法和上面的从上下文对象中获取相比,它更为简洁明了。比如,我们有下面这样一个使用上下文对象的 Action 方法:

public ActionResult ShowWeatherForecast() {
    string city = (string)RouteData.Values["city"];
    DateTime forDate = DateTime.Parse(Request.Form["forDate"]);
    // do something ... 
    return View();
}
登录后复制

我们可以像下面这样使用 Action 方法参数来重写它:

public ActionResult ShowWeatherForecast(string city, DateTime forDate) { 
    // do something ... 
    return View(); 
}
登录后复制

它不仅易读性强,也方便进行单元测试。

Action 方法的参数不允许使用 ref 和 out 参数,这是没有意义的。

MVC 框架通过检查上下文对象来为 Action 方法的参数提供值,它的名称是不区分大小写的,比如 Action 方法的 city 参数的值可以是通过 Request.Form["City"] 来获取的。

理解 Action 方法的参数是如何被赋值的

Controller 类通过 MVC 框架的 value provider 和 model binder 组件来为 Action 方法获取参数的值。

value provider 提供了一系列Controller中可以访问到的值,在内部它通过从 Request.Form、Request.QueryString、Request.Files 和 RouteData.Values 等上下文对象中提取数据(键值集合),然后把数据传递给 model binder,model binder 试图将这些数据与Action方法的参数进行匹配。默认的 model binder 可以创建和赋值给任何.NET类型对象参数(即 Action 方法的参数),包括集合和自定义的类型。

在这不对 model binder 进行介绍,我将在本系列的后续博文中对其进行专门的介绍。


理解 ActionResult

ActionResult 是描述 Action 方法执行结果的对象,它的好处是想返回什么结果就指定对应的返回对象就行,不用关心如何使用Response对象来组织和生成结果。ActionResult 是一个命令模式的例子,这种模式通过存储和传递对象来描述操作。

当 MVC 框架从 Action 方法中接收到一个 ActionResult 对象,它调用这个对象的 ExecuteResult 方法,其内部是通过 Response 对象来返回我们想要的输出结果。

为了更好的理解,我们通过继承 ActionResult 类来自定义一个 ActionResult。在MVC工程中添加一个Infrastructure文件夹,在里面创建一个名为 CustomRedirectResult 的类文件,代码如下:

using System.Web.Mvc;

namespace MvcApplication1.Infrastructure {
    
    public class CustomRedirectResult : ActionResult {
        
        public string Url { get; set; }

        public override void ExecuteResult(ControllerContext context) {
            string fullUrl = UrlHelper.GenerateContentUrl(Url, context.HttpContext);
            context.HttpContext.Response.Redirect(fullUrl);
        }
    }
}
登录后复制

当我们创建一个 CustomRedirectResult 类的实例时,我们可以传递想要跳转的 URL。当 Action 方法执行结束时,MVC 框架调用 ExecuteResult 方法,ExecuteResult 方法通过 ControllerContext 对象获得 Response 对象,然后调用 Redirect 方法。

下面我们在 Controller 中使用自定义的 CustomRedirectResult:

public class DerivedController : Controller {
    ...
    public ActionResult ProduceOutput() {
        if (Server.MachineName == "WL-PC") {
            return new CustomRedirectResult { Url = "/Basic/Index" };
        }
        else {
            Response.Write("Controller: Derived, Action: ProduceOutput");
            return null;
        }
    }
登录后复制

运行后我们看到如下结果:

792.png

当运行在本机(WL-PC)时直接重定向到了指定的/Basic/Index。

上面我们通过自定义 CustomRedirectResult 来实现重定向,我们可以用 MVC 框架提供的方法,如下:

... 
public ActionResult ProduceOutput() { 
    return new RedirectResult("/Basic/Index"); 
}
登录后复制

为了使用方便,Controller 类中为大部分类型的 ActionResult 提供简便的方法,如上面的可像下面这样简写:

... 
public ActionResult ProduceOutput() { 
    return Redirect("/Basic/Index"); 
}
登录后复制

MVC框架包含了许多 ActionResult 类型,这些类型都继承自 ActionResult 类,大部分在 Controller 类中都有简便的方法,下面列举了一些:

793.png

除了该表列出来的,还有ContentResult、FileResult、JsonResult 和 JavaScriptResult。具体每种ActionResult类型的用法这里就不讲了,大家可以看看蒋老师的了解ASP.NET
MVC几种ActionResult的本质系列的文章。


几种从 Action 传递数据到 View 的方式

我们经常需要在 Action 方法中传递数据到一个 View 中,MVC 框架为此提供了一些很方便的操作。下面简单简介几种常用的方式。

View Model 对象

通过 View Model 对象传递数据给View,这是最常用的一种,在 Acton 方法执行结束时通过 View 方法传递 View Model 对象给 View,如下代码所示:

... 
public ViewResult Index() { 
    DateTime date = DateTime.Now; 
    return View(date); 
}
登录后复制

在 View 中我们通过 Model 属性来使用传递过来的 View Model 对象,如下:

@model DateTime 

@{ 
    ViewBag.Title = "Index"; 
}

<h2>Index</h2> 
The day is: @Model.DayOfWeek
登录后复制

在 Razor 视图引擎中,@model 的作用是声明 odel 属性的类型,省去了类型转换的麻烦,而 @Model 是V iew Model 对象的引用。

ViewBag、ViewData 和 TempData 属性

ViewBag、ViewData 和 TempData 都是 Controller 和 View 中能访问到的属性,都是用来存储小量的数据,他们的区别如下:

ViewBag,是一个动态(dynamic)的弱类型,在程序运行的时候解析,是 MVC3 中新增的特性,只在当前View有效。
ViewData,是一个字典集合,也是只在当前View有效,性能比 ViewBag 高,但是使用的时候需要类型转换。
TempData,也是字典集合,一般用于两个请求之间临时缓存内容或页面间传递消息,保存在 Session 中,使用完以后则从 Session 中被清除。

下面是三者使用的例子,先在 Controller 中分别用三者存储小数据:

public class DerivedController : Controller {

    public ActionResult Index() {
        ViewBag.DayOfWeek = DateTime.Now.DayOfWeek;
        ViewData["DayOfMonth"] = DateTime.Now.Day;
        return View();
    }

    public ActionResult ProduceOutput() {
        TempData["Message"] = "Warning message from Derived Controller.";
        return Redirect("/Home/Index");
    }
}
登录后复制

在 Views/Derived 目录下的 Index.cshtml 中,取出 ViewBag 和 ViewData 中的存储的数据:

...
Day of week from ViewBag: @ViewBag.DayOfWeek
<p /> 
Day of month from ViewData: @ViewData["DayOfMonth"]
登录后复制

在 Views/Home 目录下的 Index.cshtml 中,取 TempData 中的数据如下:

...
@TempData["Message"]
登录后复制

当请求 /Derived/ProduceOutput 时,ProduceOutput 方法将一条消息存到 TempData 中,并跳转到 /Home/Index。

下面是分别是将URL定位到 /Derived/Index 和 /Derived/ProduceOutput 时的结果:

794.png

795.png

一般在当前 View 中使用 ViewBag 或 ViewData,在两个请求之间传递临时数据用 TempData。由于 TempData 被使用后即被释放,所以如果要二次使用 TempData 中的数据就需要将其存到其他变量中。

 以上就是[ASP.NET MVC 小牛之路]09 - Controller 和 Action (1)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP MVC 架构:构建面向未来的 Web 应用程序 PHP MVC 架构:构建面向未来的 Web 应用程序 Mar 03, 2024 am 09:01 AM

引言在当今快速发展的数字世界中,构建健壮、灵活且可维护的WEB应用程序至关重要。PHPmvc架构提供了实现这一目标的理想解决方案。MVC(模型-视图-控制器)是一种广泛使用的设计模式,可以将应用程序的各个方面分离为独立的组件。MVC架构的基础MVC架构的核心原理是分离关注点:模型:封装应用程序的数据和业务逻辑。视图:负责呈现数据并处理用户交互。控制器:协调模型和视图之间的交互,管理用户请求和业务逻辑。PHPMVC架构phpMVC架构遵循传统MVC模式,但也引入了语言特定的功能。以下是PHPMVC

PHP MVC 架构的进阶指南:解锁高级功能 PHP MVC 架构的进阶指南:解锁高级功能 Mar 03, 2024 am 09:23 AM

mvc架构(模型-视图-控制器)是PHP开发中最流行的模式之一,因为它为组织代码和简化WEB应用程序的开发提供了清晰的结构。虽然基本的MVC原理对于大多数Web应用程序来说已经足够,但对于需要处理复杂数据或实现高级功能的应用程序,它存在一些限制。分离模型层分离模型层是高级MVC架构中常见的一种技术。它涉及将模型类分解为更小的子类,每个子类专注于特定功能。例如,对于一个电子商务应用程序,您可以将主模型类分解为订单模型、产品模型和客户模型。这种分离有助于提高代码的可维护性和可重用性。使用依赖注入依赖

如何使用PHP实现MVC模式 如何使用PHP实现MVC模式 Jun 07, 2023 pm 03:40 PM

MVC(Model-View-Controller)模式是一种常用的软件设计模式,可以帮助开发人员更好地组织和管理代码。MVC模式将应用程序分为三部分:模型(Model)、视图(View)和控制器(Controller),每个部分都有自己的角色和职责。在本文中,我们将讨论如何使用PHP实现MVC模式。模型(Model)模型代表应用程序的数据和数据处理。通常,

揭秘SpringMVC框架的成功:它为何广受欢迎 揭秘SpringMVC框架的成功:它为何广受欢迎 Jan 24, 2024 am 08:39 AM

SpringMVC框架解密:为什么它如此受欢迎,需要具体代码示例引言:在当今的软件开发领域中,SpringMVC框架已经成为开发者非常喜爱的一种选择。它是基于MVC架构模式的Web框架,提供了灵活、轻量级、高效的开发方式。本文将深入探讨SpringMVC框架的魅力所在,并通过具体的代码示例来展示其强大之处。一、SpringMVC框架的优势灵活的配置方式Spr

PHP中如何使用MVC架构设计项目 PHP中如何使用MVC架构设计项目 Jun 27, 2023 pm 12:18 PM

在Web开发中,MVC(Model-View-Controller)是一种常用的架构模式,用于处理和管理应用程序的数据、用户界面和控制逻辑。PHP作为流行的Web开发语言,也可以借助MVC架构来设计和构建Web应用程序。本文将介绍如何在PHP中使用MVC架构设计项目,并解释其优点和注意事项。什么是MVCMVC是一种软件架构模式,通常用于Web应用程序中。MV

PHP8框架开发MVC:初学者需要知道的重要概念和技巧 PHP8框架开发MVC:初学者需要知道的重要概念和技巧 Sep 11, 2023 am 09:43 AM

PHP8框架开发MVC:初学者需要知道的重要概念和技巧引言:随着互联网的快速发展,Web开发在当今的软件开发行业中扮演着重要的角色。PHP被广泛用于Web开发,并且有许多成熟的框架可以帮助开发人员更高效地构建应用程序。其中,MVC(Model-View-Controller)架构是最常见且广泛使用的模式之一。本文将介绍初学者在使用PHP8框架开发MVC应用程

PHP8框架开发MVC:逐步指南 PHP8框架开发MVC:逐步指南 Sep 11, 2023 am 10:05 AM

PHP8框架开发MVC:逐步指南引言:MVC(Model-View-Controller)是一种常用的软件架构模式,用于将应用程序的逻辑、数据和用户界面分离。它提供了一种将应用程序分成三个不同组件的结构,以便更好地管理和维护代码。在本文中,我们将探讨如何使用PHP8框架来开发一个符合MVC模式的应用程序。第一步:理解MVC模式在开始开发MVC应用程序之前,我

揭秘 PHP MVC 架构的秘密:让你的网站飞起来 揭秘 PHP MVC 架构的秘密:让你的网站飞起来 Mar 03, 2024 am 09:25 AM

模型-视图-控制器(mvc)架构是一种强大的设计模式,用于构建可维护且可扩展的WEB应用程序。PHPMVC架构将应用程序逻辑分解为三个不同的组件:模型:表示应用程序中的数据和业务逻辑。视图:负责呈现数据给用户。控制器:充当模型和视图之间的桥梁,处理用户请求并协调其他组件。MVC架构的优势:代码分离:MVC将应用程序逻辑与表示层分离,提高了可维护性和可扩展性。可重用性:视图和模型组件可以跨不同的应用程序重用,减少重复代码。性能优化:MVC架构允许缓存视图和模型结果,从而提高网站速度。测试友好:分离

See all articles