首页 > 代码库 > 运用custom actionResults 进一步增强MVC3

运用custom actionResults 进一步增强MVC3

最近带我的师傅发给我一篇英文技术文档,抱着学习英文的心情我将原文翻译了一下。

原文链接:http://www.matthidinger.com/archive/2011/03/02/Progressive-enhancement-in-MVC-3-with-the-help-of-custom.aspx

具体内容如下:

 上周我写了一篇关于“运用custom actionResults 进一步增强MVC3”的教程,如果您对于一些概念还不熟悉,请略过此文章。

 一个评论人在我上一篇文章中提了个很好的问题,从而激发了我对源码的改进。非常感谢他的建议。

 概述如下

我们的目的是要建立一个能运行在所有浏览器上的“Contact Us”的Form,并且通过使能Javascript提供一个增强的体验。

运用javascript:

如图所示,当浏览者浏览我们的使能Javascript网站点击“Contact Us”链接,网站将展示给他们一个漂亮的jquery UI 对话框。浏览者可以填写form同时在对话框内得到一个漂亮的确认信息,最后,在不离开此页面的情况下关闭它。

不运用javascript:

不使用javascript时,访问者仍然能够享用同样的功能,仅仅是用户体验弱一些。没有javascript逻辑功能的“Contact Us”就像一个单调过时的超链接,将用户导航到一个新的页面。当填写完表单点击“Send Message”,网站将会有确认提示并且重新跳转到主页。

新的Controller:

依照评论人的意见,我将逻辑抽象为两个用户“ActionResults”名为: AjaxableViewResultAjaxableActionResult假设命名我们的视图时遵守一些约定,新的Controller将会更简洁可读性更强。

[HttpGet]

public ActionResult ContactUs()

{

return new AjaxableViewResult();

}

[HttpPost]

public ActionResult ContactUs(ContactUsInput input)

{

if (!ModelState.IsValid)

return new AjaxableViewResult(input);

// TODO: A real app would send some sort of email here

TempData["Message"] = string.Format("Thanks for the feedback, {0}! We will contact you shortly.", input.Name);

return new AjaxableActionResult

{

DefaultResult = () => RedirectToAction("Index"),

AjaxResult = () => PartialView("_ThanksForFeedback", input)

};

}

编码

通过下面的代码,您可以找到我们进一步增强的逻辑。如果您熟悉MVC中ActionResults的概念,下面的代码有记录的,且相对直接。

AjaxableActionResult:

/// <summary>

/// Executes a specific action result depending on whether the incoming request is an Ajax request or not

/// </summary>

public class AjaxableActionResult : ActionResult

{

/// <summary>

/// The result to execute for non-Ajax requests

/// </summary>

public Func<ActionResult> DefaultResult { get; set; }

/// <summary>

/// The result the execute for Ajax requests

/// </summary>

public Func<ActionResult> AjaxResult { get; set; }

public override void ExecuteResult(ControllerContext context)

{

if(DefaultResult == null)

throw new ArgumentException("The DefaultResult property must be set");

if (AjaxResult == null)

throw new ArgumentException("The AjaxResult property must be set");

if (context.HttpContext.Request.IsAjaxRequest())

{

AjaxResult().ExecuteResult(context);

}

else

{

DefaultResult().ExecuteResult(context);

}

}

}

AjaxableViewResult:

/// <summary>

/// Inspects the incoming request and returns a PartialViewResult for Ajax requests and a full ViewResult for non-Ajax requests

/// </summary>

public class AjaxableViewResult : ActionResult

{

/// <summary>

/// Determines the convention for looking up a PartialView for the incoming request.

/// The default convention looks for an underscore followed by the action name.

/// For example: _ContactUs.cshtml or _ContactUs.ascx

/// </summary>

public static Func<ControllerContext, string> AjaxViewNameConvention = context => "_" + context.RouteData.GetRequiredString("action");

/// <summary>

/// The view name for non-Ajax requests

/// </summary>

public string NonAjaxViewName { get; set; }

/// <summary>

/// The view name for Ajax requests

/// </summary>

public string AjaxViewName { get; set; }

/// <summary>

/// The model that is rendered to the view

/// </summary>

public object Model { get; set; }

/// <summary>

/// Creates a new AjaxableViewResult using the default conventions

/// </summary>

public AjaxableViewResult() : this(null, null, null)

{

}

/// <summary>

/// Creates a new AjaxableViewResult using the default conventions with custom model data

/// </summary>

public AjaxableViewResult(object model) : this(null, null, model)

{

}

/// <summary>

/// Creates a new AjaxableViewResult with a specific ajax partial view

/// </summary>

public AjaxableViewResult(string ajaxViewName) : this(ajaxViewName, null)

{

}

/// <summary>

/// Creates a new AjaxableViewResult with a specific ajax partial view and model

/// </summary>

public AjaxableViewResult(string ajaxViewName, object model) : this(ajaxViewName, null, model)

{

}

/// <summary>

/// Creates a new AjaxableViewResult with a specific ajax view, non-ajax view, and model

/// </summary>

public AjaxableViewResult(string ajaxViewName, string defaultViewName, object model)

{

NonAjaxViewName = defaultViewName;

AjaxViewName = ajaxViewName;

Model = model;

}

public override void ExecuteResult(ControllerContext context)

{

context.Controller.ViewData.Model = Model;

if (context.HttpContext.Request.IsAjaxRequest())

{

var view = new PartialViewResult

{

ViewName = GetAjaxViewName(context),

ViewData = context.Controller.ViewData

};

view.ExecuteResult(context);

}

else

{

var view = new ViewResult

{

ViewName = GetViewName(context),

ViewData = context.Controller.ViewData

};

view.ExecuteResult(context);

}

}

private string GetViewName(ControllerContext context)

{

return !string.IsNullOrEmpty(NonAjaxViewName) ? NonAjaxViewName : context.RouteData.GetRequiredString("action");

}

private string GetAjaxViewName(ControllerContext context)

{

return !string.IsNullOrEmpty(AjaxViewName) ? AjaxViewName : AjaxViewNameConvention(context);

}

}

 

重写惯例AjaxViewName:

为了完整,我决定添加一个简单的可扩展点来修改查找约定Ajax view。在您的Global.asax文件中,你可以用静态AjaxViewNameConvention来定义您自己的partial view约定,看起来是在action name前加了个下划线。