[ASP.NET MVC]让Html.RenderAction支持Lamda表达式
今天在ASP.NET MVC代码时用到了Html.RenderAction,代码如下:
@{Html.RenderAction("RecentNews")}
通过字符串指定Action的名称,有两点不爽:
1. 输入时不能智能感知;
2. 输错了不能实时提示。
有这两点不爽,写代码的乐趣就大减。有享受感觉的代码应该是这样的:
@{Html.RenderAction<AggSiteController>(c => c.RecentNews());}
是的,Lamda,给你写代码带来畅快感觉的Lamda!
微软不让我们享受,我们就自己动手,丰衣足食。自己写一个支持Lamda表达式的Html.RenderAction,代码如下:
using System.Web.Mvc; using System.Web.Mvc.Html; using System.Linq.Expressions; namespace System.Web.Mvc.Html { public static class HtmlHelperExtensions { public static void RenderAction<TController>(this HtmlHelper htmlHelper, Expression<Action<TController>> operation) where TController : Controller { var actionName = ((MethodCallExpression)operation.Body).Method.Name; htmlHelper.RenderAction(actionName); } } }
注:其中"((MethodCallExpression)operation.Body).Method.Name"代码来自Get Method Name From Action。
顺带分享一篇文章When to use Html.RenderPartial and Html.RenderAction in ASP.NET MVC Razor Views,通过这篇文章你可以清楚的知道Html.RenderPartial与Html.RenderAction之间的区别。
比如:博客园首页的最新随笔列表就适合用Html.RenderPartial,而右侧的“新闻列表”就适合用Html.RenderAction。
简单的理解就是:Html.RenderPartial用的到PartialView只用一次(虽然实际可以多次使用,但比较麻烦,每次都要传Model),Html.RenderAction用的到PartialView被多个视图使用(有自己的Action提供Model)。
在评论中,向晚提到了Html.RenderAction的一个优点:
ChildAciton的优势是可以应用OutputCahce特性实现局部缓存。
我们当时用Html.RenderAction,而不用Html.RenderPartial,这也是一个重要原因。
总结一下ChildAciton+PartialView的优势:
- 可以在“不同Action相同View”中方便地被共享
- 可以在“不同Action不同View”中方便地被共享
- “可以应用OutputCahce特性实现局部缓存”
我们在解决另外一个问题时,发现它还有一个优势:
4. 可以用ChildAciton直接处理Ajax请求。
比如博客园首页加载“最新随笔列表”的应用场景,在用户打开页面时直接显示最新随笔(非ajax加载);在用户点击页面上的“刷新”链接时,通过ajax更新“最新随笔列表”。
使用ChildAciton+PartialView,在首页页面视图中只需Html.RenderAction即可。
@{ Html.RenderAction<AggSiteController>(c => c.PostList(1,20)); }
同样的ChildAction可以直接服务于Ajax请求,实现了ChildAciton+PartialView的重用。
这时,我们遇到了一个问题,在RenderAction的时候需要向Action传递参数,之前实现的简陋的Html.RenderAction并没有对此提供支持,需要改进一下。
从testzhangsan的评论中获知,ASP.NET MVC 4中已经在实现Lamda版Html.RenderAction。签出ASP.NET MVC 4的源代码一下,果然实现了,向Action传参数的问题自然也被微软解决了。参照那段代码,精简一下就能解决我们的问题。
向Action传参数,需要通过RouteValueDictionary,我们所要做的工作就是从Lamda表达式中获取参数名称与参数值,并还添加至RouteValueDictionary。
完整代码如下:
using System.Web.Mvc; using System.Web.Mvc.Html; using System.Linq.Expressions; using System.Web.Routing; namespace System.Web.Mvc.Html { public static class HtmlHelperExtensions { public static void RenderAction<TController>(this HtmlHelper htmlHelper, Expression<Action<TController>> operation) where TController : Controller { var controllerName = typeof(TController).Name; if (controllerName.EndsWith("Controller")) { controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length); } var call = operation.Body as MethodCallExpression; if (call != null) { var actionName = call.Method.Name; var parameters = call.Method.GetParameters(); if (parameters.Length > 0) { var routeValues = new RouteValueDictionary(); for (int i = 0; i < parameters.Length; i++) { var ce = call.Arguments[i] as ConstantExpression; if (ce != null) { routeValues.Add(parameters[i].Name, ce.Value); } else { var lambda = Expression.Lambda(call.Arguments[i], operation.Parameters); Delegate d = lambda.Compile(); var value = d.DynamicInvoke(new object[1]); routeValues.Add(parameters[i].Name, value); } } htmlHelper.RenderAction(actionName, controllerName, routeValues); } else { htmlHelper.RenderAction(actionName, controllerName); } } } } }
注:目前的这个实现不支持可空类型的参数,比如:public ActionResult PostList(int? pageIndex)。
开源,真好!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构