ホームページ  >  記事  >  バックエンド開発  >  [ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

黄舟
黄舟オリジナル
2016-12-30 16:00:031309ブラウズ

[ASP.NET
MVC Mavericks Road] 09 - コントローラーとアクション (1)

MVC では、各リクエストが処理のためにコントローラーに送信されることがわかっています。コントローラーにはリクエストのロジック処理が含まれており、モデルを操作したり、ユーザーに提示するビューを選択したりできます。通常、ビジネスやデータ、インターフェイス、補助クラス ライブラリなどのロジック コードは配置されません。コントローラー。

ControllerとActionは内容が多いので2記事に分けました、もしくは3記事に分ける場合もあります。この記事では、コントローラーの実装、コントローラーによるステータス データの取得、ActionResult と Action のデータ転送について説明します。その後、コントローラー ファクトリ、アクション インボーカー、およびまだ考えられていない高度な機能をいくつか紹介します。学習されています。

この記事の内容


IController インターフェイスを継承する

このシリーズの前の記事で、追加したコントローラーは、抽象クラス System.Web.Mvc.Controller から継承された共通クラスです (注意:コントローラーこの記事では (またはコントローラー) とコントローラー クラスの 2 つの異なる意味があります。この記事を読む際は文脈に応じて理解してください)。コントローラー抽象クラスは、多くの非常に実用的な関数をカプセル化しているため、開発者は反復的で面倒な処理コードを自分で記述する必要がありません。

カプセル化されたコントローラー抽象クラスを使用しない場合は、IController インターフェイスを実装して独自のコントローラーを作成することもできます。 IController インターフェイスには Exctute メソッドが 1 つだけあります:

public interface IController { 
    void Execute(RequestContext requestContext); 
}

Controller インターフェイスは System.Web.Mvc 名前空間の下にあり、非常に単純な構造を持つインターフェイスです。

IController インターフェイスを実装するコントローラー クラスにリクエストが送信されると (ルーティング システムはリクエストされた URL を通じてコン​​トローラーを見つけることができます)、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 を他のフラグメント名に変更できます)、結果は次のようになります:

[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

は IController クラスを実装し、MVC はそれをコントローラー クラスとして認識し、対応するリクエストをこのクラスに渡して、コントローラー名。

しかし、少し複雑なアプリケーションの場合、IController インターフェイスを自分で実装するには多大な作業が必要であり、それを行うことはほとんどありません。これにより、コントローラーのすべてのリクエスト処理が Execute メソッドから開始されることが理解できます。


Controller抽象クラスを継承します

MVCでは自由にカスタマイズ、拡張することができます。例えば、前述のように、IControllerインターフェイスを実装して、さまざまなリクエストに対してさまざまな処理を作成し、結果を生成できます。 Action メソッドが気に入らない場合、または View を気にしない場合は、リクエストを処理するための、より優れた、より高速で洗練されたコントローラーを自分で作成できます。ただし、前述したように、IController インターフェイスを自分で実装するには多くの作業が必要です。最も重要なことは、長期にわたる実践的なテストがなければコードの堅牢性を保証できないということです。これは一般的に推奨されません。 MVC フレームワークの System.Web.Mvc.Controller クラスは、リクエストの処理と結果の返しを容易にするのに十分な実用的な機能を提供します。

私たちは、Controller クラスを継承するコントローラーを何度も使用しており、次の主要な機能を備えています。

Action メソッド: コントローラー、その動作は複数のメソッドに分割されます。通常、メソッドは に対応します。リクエストによって渡されるデータは、メソッドのパラメータを通じて取得できます。
ActionResult: Action メソッドの実行結果を記述するオブジェクトを返すことができます。これの利点は、どのような結果を返したいかについて、対応する戻りオブジェクトを指定するだけで済み、心配する必要がないことです。それを実行して結果を生成する方法。
フィルター: C# 機能を通じて、特定の動作 (承認や検証など) の処理がカプセル化され、複数のコントローラーおよびアクション メソッド間での再利用が容易になります。

したがって、特別なニーズがない場合、または忙しすぎる場合、要件を満たすコントローラーを作成する最良の方法は、コントローラー抽象クラスを継承することです。これまでに何度も使用しているため、ここでは詳細なデモは行いませんが、コード構造を見てみましょう。

Controllers フォルダーにコントローラーを追加します。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,每一个都提供了请求相关的不同类型的信息。下面列出了最常的上下文对象:


[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

在 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;
        }
    }

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

[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

当运行在本机(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 类中都有简便的方法,下面列举了一些:

[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

除了该表列出来的,还有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 时的结果:

[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

[ASP.NET MVC Mavericks Road] 09 - コントローラーとアクション (1)

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

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


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。