ASP.NET MVC . Controller

20895 ワード

Controllerは、さまざまなタイプのActionResultを返す多くの方法を提供しています.
1.Viewで最も一般的な1つで、「標準」ページを返すことができます.
protected internal virtual ViewResult View(string viewName, string masterName, object model){    if (model != null)    {        base.ViewData.Model = model;    }    return new ViewResult     {         ViewName = viewName,         MasterName = masterName,         ViewData = base.ViewData,         TempData = base.TempData     };}public class ViewResult : ViewResultBase{    protected override ViewEngineResult FindView(ControllerContext context)    {        ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);        if (result.View != null)        {            return result;        }        ...    }}

このページのデフォルトはViewPageです.また、独自に定義した他のテンプレートエンジンページでもあります.MVCはまた、強いタイプのViewPageを提供している.
public class User{    public string Name { get; set; }    public int Age { get; set; }}public class TestController : Controller{    public ActionResult Index()    {        ViewData["message"] = "Hello, World!";        var model = new User { Name = "Tom", Age = 13 };        return View(model);    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Learn.MVC.Controllers.User>" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title></head><body>    Name: <%= Model.Name %>; Age: <%= Model.Age %></body></html>

WebForm時代には、1つのページを複数のUserControlに分解することに慣れていましたが、今でもそうすることができます.htmlHelperはRenderPartialの拡張方法を専門に提供し、現在のビューディレクトリ(Viewsxxx)からダウンロードした.ascxページ.
public static class RenderPartialExtensions{    public static void RenderPartial(this HtmlHelper htmlHelper, partialViewName, model, viewData)    {        htmlHelper.RenderPartialInternal(partialViewName, viewData, model, ViewEngines.Engines);    }}public class HtmlHelper{    internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData,         object model, ViewEngineCollection viewEngineCollection)    {        ...        ViewDataDictionary newViewData = null;        if (model == null)        {            if (viewData == null)                newViewData = new ViewDataDictionary(ViewData);            else                newViewData = new ViewDataDictionary(viewData);        }        else        {            if (viewData == null)                newViewData = new ViewDataDictionary(model);            else                newViewData = new ViewDataDictionary(viewData) { Model = model };        }        ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View,             newViewData, ViewContext.TempData);        IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection);        view.Render(newViewContext, ViewContext.HttpContext.Response.Output);    }    internal static IView FindPartialView(viewContext, partialViewName, viewEngineCollection)    {        ViewEngineResult result = viewEngineCollection.FindPartialView(viewContext, partialViewName);        if (result.View != null)        {            return result.View;        }        ...    }}

RenderPartialInternalはFindParitialViewを呼び出してビューエンジンからロードする.ascxは、現在の環境パラメータを渡します.つまり、RenderPartialはビューレベルの動作にすぎず、Controller Action操作が再びトリガーされることはない.PartialView()は区別されます.Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Learn.MVC.Controllers.User>" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title></head><body>    Name: <%= Model.Name %>; Age: <%= Model.Age %>    <br />    <% Html.RenderPartial("Part"); %></body></html>

Part.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Learn.MVC.Controllers.User>" %><%= ViewData["message"] %> <br /><%= Model.Name %>

2.ContentContentは、出力(Response.Write)「静的」フラグメントに使用されます.
protected internal virtual ContentResult Content(content, contentType, contentEncoding){    return new ContentResult    {        Content = content,        ContentType = contentType,        ContentEncoding = contentEncoding    };}public class ContentResult : ActionResult{    public string Content { get; set; }            public override void ExecuteResult(ControllerContext context)    {        ...        HttpResponseBase response = context.HttpContext.Response;        if (!String.IsNullOrEmpty(ContentType))        {            response.ContentType = ContentType;        }        if (ContentEncoding != null)        {            response.ContentEncoding = ContentEncoding;        }        if (Content != null)        {            response.Write(Content);        }    }}

jQueryとの組み合わせを見てみましょう.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult Part()    {        return Content("<a href=\"http://www.rainsts.net\">Q.yuhen</a>");    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title>    <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script>    <script type="text/javascript">        $(function()        {            $("#div1").load("/test/part");        });    </script></head><body>    <div id="div1">    </div></body></html>

3. PartialViewController.PartialView()とHtmlHelper.RenderPartial()の違いは、前者がActionInvokeを再実行し、既存のViewContextを使用してビュークリップを表示するだけのActionResult結果を返すことです.ControllerとContent()の違いは、PartialView()がビューエンジンを使用して「動的」なascx結果を出力することです.
protected internal virtual PartialViewResult PartialView(string viewName, object model){    if (model != null)    {        ViewData.Model = model;    }    return new PartialViewResult    {        ViewName = viewName,        ViewData = ViewData,        TempData = TempData    };}public class PartialViewResult : ViewResultBase{    protected override ViewEngineResult FindView(ControllerContext context)    {        ViewEngineResult result = ViewEngineCollection.FindPartialView(context, ViewName);        if (result.View != null)        {            return result;        }                ...    }}

Content()と同様に、通常jQueryなどのAjaxフレームワークと組み合わせて使用します.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult Part()    {        ViewData["time"] = DateTime.Now;        var model = new User { Name = "Tom", Age = 13 };        return PartialView(model);    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title>    <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script>    <script type="text/javascript">        $(function()        {            $("#div1").load("/test/part");        });    </script></head><body>    <div id="div1">    </div></body></html>

Part.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Learn.MVC.Controllers.User>" %><%= ViewData["time"] %> <br /><%= Model.Name %>; <%= Model.Age %>

4.Redirect/RedirectToAction/RedirectToRouteControllerは、異なるAction間でジャンプする方法をいくつか提供しています.
public class MvcApplication : System.Web.HttpApplication{    public static void RegisterRoutes(RouteCollection routes)    {        ...        routes.MapRoute        (            "Test2",            "Test/T2/{name}/{age}",            new { controller = "Test", action = "T2", name = "", age = 0 }        );        ...    }}

方法1:Redirect()をそのままResponse.Redirect()urlジャンプを完了します.
public class TestController : Controller{    public ActionResult Index()    {        return Redirect("/Test/T2/Tom/23");    }    public ActionResult T2(User user)    {        return Content(user.Name);    }}

詳細:
protected internal virtual RedirectResult Redirect(string url){    ...    return new RedirectResult(url);}public class RedirectResult : ActionResult{    public override void ExecuteResult(ControllerContext context)    {        ...        string destinationUrl = UrlHelper.Content(Url, context.HttpContext);        context.HttpContext.Response.Redirect(destinationUrl, false /* endResponse */);    }}

方法2:RedirectToAction()は、直接ActionNameを使用してジャンプします.
public class TestController : Controller{    public ActionResult Index()    {        return RedirectToAction("T2", new { name = "Tom", age = 23 });    }    public ActionResult T2(User user)    {        return Content(user.Name);    }}

ターゲットアクションが現在のControllerクラスにない場合は、ターゲットController Nameを指定できます.
return RedirectToAction("T2", new { controller="Test2", name = "Tom", age = 23 });

詳細:
protected internal virtual RedirectToRouteResult RedirectToAction(string actionName,     string controllerName, RouteValueDictionary routeValues){    RouteValueDictionary mergedRouteValues;    if (RouteData == null)    {        mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName,             controllerName, null, routeValues, true /* includeImplicitMvcValues */);    }    else    {        mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName,             controllerName, RouteData.Values, routeValues, true /* includeImplicitMvcValues */);    }    return new RedirectToRouteResult(mergedRouteValues);}public class RedirectToRouteResult : ActionResult{    public override void ExecuteResult(ControllerContext context)    {        ...        string destinationUrl = UrlHelper.GenerateUrl(RouteName, null /* actionName */,             null /* controllerName */, RouteValues, Routes, context.RequestContext,             false /* includeImplicitMvcValues */);        ...        context.HttpContext.Response.Redirect(destinationUrl, false /* endResponse */);    }}

RedirectToRouteResultが見えます.ExecuteResultではRoute関連情報をターゲットUrlにつなぎ合わせてジャンプする.方法3:RedirectToRoute()はMapRouteで直接定義したRoute Nameでジャンプする.
public class TestController : Controller{    public ActionResult Index()    {        return RedirectToRoute("Test2", new { name = "Tom", age = 23 });    }}

詳細:
protected internal virtual RedirectToRouteResult RedirectToRoute(string routeName, RouteValueDictionary routeValues){    return new RedirectToRouteResult(routeName, RouteValuesHelpers.GetRouteValues(routeValues));}

実行プロセスはRedirectToAction()と同じです.5.JsonJson()は、Ajaxを作成するときに非常に役立ち、EntityなどのオブジェクトをJSON形式にシーケンス化してJavascriptで使用することができます.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult GetUser(string name)    {        var user = new User { Name = name, Age = 23 };        return Json(user);    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title>    <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script>    <script type="text/javascript">        $(function()        {            $("#btnTest").click(function()            {                $.getJSON                (                    "/Test/GetUser",                     { name: "Tom" },                     function(json)                    {                        alert(json.Name + ";" + json.Age);                    }                );            });        });    </script></head><body>    <input type="button" id="btnTest" value="Test" /></body></html>

使いやすいですね.詳細を見てください.
protected internal virtual JsonResult Json(object data, string contentType, Encoding contentEncoding){    return new JsonResult    {        Data = data,        ContentType = contentType,        ContentEncoding = contentEncoding    };}public class JsonResult : ActionResult{    public override void ExecuteResult(ControllerContext context)    {        ...        if (Data != null)        {            JavaScriptSerializer serializer = new JavaScriptSerializer();            response.Write(serializer.Serialize(Data));        }    }}

Systemを使用します.Web.Script.Serialization.JavaScriptSerializerはJSONシーケンス化を完了します.つまり、ScriptIgnoreAttributeでいくつかの属性を除外することもできます.6.Javascript時々、いくつかの論理判断に基づいて異なるJavascriptコードをロードする必要があります.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult GetJs(int id)    {        switch (id)        {            case 1:                return JavaScript("alert('Hello, C#!');");                        case 2:                return JavaScript("alert('Hello, MVC!');");                        default:                return null;        }    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title>    <script src="http://www.cnblogs.com/Scripts/jquery-1.3.1.min.js" type="text/javascript"></script>    <script type="text/javascript">        $(function()        {            $("#btnTest").click(function()            {                var id = $("#txtId").val();                $.getScript("/Test/GetJs/" + id);            });        });    </script></head><body>    <input type="text" id="txtId" value="1" />    <input type="button" id="btnTest" value="Test" /></body></html>

ただ、このやり方では、ViewとControllerの結合が大きくなっているようですが・・・むしろJavascriptで直接処理したほうがいいです.
protected internal virtual JavaScriptResult JavaScript(string script){    return new JavaScriptResult { Script = script };}public class JavaScriptResult : ActionResult{    public override void ExecuteResult(ControllerContext context)    {        ...        HttpResponseBase response = context.HttpContext.Response;        response.ContentType = "application/x-javascript";        if (Script != null)        {            response.Write(Script);        }    }}

7.File(Download/Upload)File()は、Download機能を提供します.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult Download(int id)    {        var filename = String.Format("~/Content/Download/{0}.rar", id);        var fileDownloadName = String.Format("{0}.rar", id);        return File(filename, "application/octet-stream", fileDownloadName);    }}

ブラウザで「/Test/Download/1」を要求すると、ダウンロードウィンドウが開き、保存ファイル名が与えられます.
protected internal virtual FileContentResult File(byte[] fileContents, contentType, fileDownloadName){    return new FileContentResult(fileContents, contentType) { FileDownloadName = fileDownloadName };}public abstract class FileResult : ActionResult{    public override void ExecuteResult(ControllerContext context)    {        ...        HttpResponseBase response = context.HttpContext.Response;        response.ContentType = ContentType;        ...        WriteFile(response);    }    protected abstract void WriteFile(HttpResponseBase response);}public class FileContentResult : FileResult{    protected override void WriteFile(HttpResponseBase response)    {        response.OutputStream.Write(FileContents, 0, FileContents.Length);    }}

ファイルアップロードはもう一つの一般的なWebアプリケーションです.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult Upload(HttpPostedFileBase file)    {        var filename = Server.MapPath("~/Content/Upload/" + Path.GetFileName(file.FileName));        file.SaveAs(filename);        return null;    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title></head><body>    <form action="/Test/Upload" enctype="multipart/form-data" method="post">        <input type="file" name="file" />        <input type="submit" name="upload" />    </form></body></html>

MVCはHttpPostedFileBaseModelBinderがRequestを提供する.Filesの情報はActionの同名パラメータに直接マッピングされます.
public class HttpPostedFileBaseModelBinder : IModelBinder{    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)    {        ...        HttpPostedFileBase theFile = controllerContext.HttpContext.Request.Files[bindingContext.ModelName];        // case 1: there was no <input type="file" ... /> element in the post        if (theFile == null)        {            return null;        }        // case 2: there was an <input type="file" ... /> element in the post, but it was left blank        if (theFile.ContentLength == 0 && String.IsNullOrEmpty(theFile.FileName))        {            return null;        }        // case 3: the file was posted        return theFile;    }}

複数のファイルを一度にアップロードするデモを見てみましょう.
public class TestController : Controller{    public ActionResult Index()    {        return View();    }    public ActionResult Upload(HttpPostedFileBase file1, HttpPostedFileBase file2)    {        var html = String.Format("{0}:{1}<br />{2}:{3}",             file1.FileName, file1.InputStream.Length,            file2.FileName, file2.InputStream.Length);        return Content(html);    }}

Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">    <title>Index</title></head><body>    <form action="/Test/Upload" enctype="multipart/form-data" method="post">        <input type="file" name="file1" />        <input type="file" name="file2" />        <input type="submit" name="upload" />    </form></body></html>

[最終修正