扩展方法实现服务器和客户端绑定的ActionLink

在开发Web应用程序时,经常需要在服务器端和客户端绑定数据。为了实现这一点,通常会使用一些库,比如Telerik的Grid组件。然而,标准的Grid组件并不总是提供想要的所有功能。例如,可能想要在Grid中添加一个"Open"链接,但是标准的Grid组件并没有提供这样的功能。

为了解决这个问题,可以编写一个扩展方法,这样就可以在服务器端和客户端绑定中使用相同的HTML。这样,就不需要为服务器端和客户端绑定编写两个不同的模板,从而避免了可能的错误。

下面是一个扩展方法的示例,它允许在服务器端和客户端绑定中使用相同的ActionLink。

public static GridTemplateColumnBuilder<T> ActionLink<T>(this GridColumnFactory<T> factory, string linkText, string action, Expression<Func<T, object>> routeValues) where T : class { return ActionLink(factory, linkText, action, string.Empty, routeValues); } public static GridTemplateColumnBuilder<T> ActionLink<T>(this GridColumnFactory<T> factory, string linkText, string action, string controller, Expression<Func<T, object>> routeValues) where T : class { if (string.IsNullOrEmpty(controller)) controller = factory.Container.ViewContext.Controller.GetType().Name.Replace("Controller", string.Empty); var urlHelper = new UrlHelper(factory.Container.ViewContext.RequestContext); var builder = factory.Template(x => { var actionUrl = urlHelper.Action(action, controller, routeValues.Compile().Invoke(x)); return string.Format(@"", actionUrl, linkText); }); if (!(routeValues.Body is NewExpression)) throw new ArgumentException("routeValues.Body must be a NewExpression"); RouteValueDictionary routeValueDictionary = ExtractClientTemplateRouteValues(((NewExpression)routeValues.Body)); var link = urlHelper.Action(action, controller, routeValueDictionary); var clientTemplate = string.Format(@"", link, linkText); return builder.ClientTemplate(clientTemplate); } private static RouteValueDictionary ExtractClientTemplateRouteValues(NewExpression newExpression) { RouteValueDictionary routeValueDictionary = new RouteValueDictionary(); for (int index = 0; index < newExpression.Arguments.Count; index++) { var argument = newExpression.Arguments[index]; var member = newExpression.Members[index]; object value; switch (argument.NodeType) { case ExpressionType.Constant: value = ((ConstantExpression)argument).Value; break; case ExpressionType.MemberAccess: MemberExpression memberExpression = (MemberExpression)argument; if (memberExpression.Expression is ParameterExpression) value = string.Format("<#= {0} #>", memberExpression.Member.Name); else value = GetValue(memberExpression); break; default: throw new InvalidOperationException("Unknown expression type!"); } routeValueDictionary.Add(member.Name, value); } return routeValueDictionary; } private static object GetValue(MemberExpression member) { var objectMember = Expression.Convert(member, typeof(object)); var getterLambda = Expression.Lambda<Func<object>>(objectMember); return getterLambda.Compile().Invoke(); }

这个扩展方法首先检查控制器名称是否为空,如果为空,则使用当前控制器的名称。然后,它创建一个新的UrlHelper对象,用于生成ActionLink的URL。接下来,它使用一个lambda表达式来生成服务器端的模板。

对于客户端模板,它解析routeValues表达式,生成一个包含路由值的RouteValueDictionary。然后,它使用这个字典来生成客户端模板。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485