我正在寻找'概括'.NET 3.5 MVC应用程序中的一些代码并且遇到了问题。
背景
我有一个带有一些操作的 SomeController 类:
public ActionResult Renew(string qualification, int tierId) { ... }
public ActionResult Reinstate(string qualification, int tierId) { ... }
public ActionResult Withdraw(string qualification, int tierId) { ... }
在视图中,我使用强类型扩展辅助方法来创建 ActionLink (此通用方法来自Microsoft.Web.Mvc.dll
)。样品使用将是
Html.ActionLink<SomeController>(c=>c.Renew(Model.Qualification, Model.TierId),"Renew")
只有我在视图上有一个属性才能定义方法调用的表达式,所以我可以这样做:
Html.ActionLink(Model.Action,"Renew")
视图模型上的操作属性具有以下签名
public Expression<Action<SomeController>> Action { get; set; }
当我在控制器动作中创建视图时,我可以使用以下代码:
model.Action = c => c.Renew(dto.Qualification.Name, t.Id)
方法
到目前为止一直很好,所有强类型和工作都很好,但这是我的问题开始的地方。我希望能够使用传递给组装视图模型的方法的参数替换对c => c.Renew(dto.Qualification.Name, t.Id)
的显式调用。
我希望做到以下几点:
private SomeViewModel CreateViewModel(SomeDto dto, Tier t, Func<string, int, ActionResult>> actionToCall) {
return new SomeViewModel {
...
Action = a => actionToCall(dto.Qualification.Name, t.Id),
}
}
然后使用此方法构造模型并将适当的控制器操作作为参数传递
var model = CreateViewModel(dto,tier,this.Reinstate)
问题
这个解决方案可以编译,但是当我开始渲染ActionLink时,我得到了一个预期,因为作为一个动作传入的表达式不是MethodCallExpression
类型。来自View的Html.ActionLink扩展方法抛出此异常。
答案 0 :(得分:2)
我认为您希望CreateViewModel接受表达式树而不是委托。 ActionLink似乎假设它传递了一个表达式树,它是一个lambda,它的主体是对参数的方法调用。如果对传递给CreateViewModel的表达式做出相同的假设,则可以通过执行以下操作来拉出MethodInfo对象并手动构造表达式树:
private SomeViewModel CreateViewModel(SomeDto dto, Tier t,
Expression<Func<string, int, ActionResult>> actionToCall)
{
var methodCallExpression = (MethodCallExpression)actionToCall.Body;
var param = Expression.Parameter(typeof(SomeController), null);
return new SomeViewModel()
{
Action =
Expression.Lambda<Action<SomeController>>(
Expression.Call(
param,
methodCallExpression.Method,
Expression.Constant(dto.Qualification.Name),
Expression.Constant(t.Id)),
param)
};
}
答案 1 :(得分:0)
这个帮助程序的工作方式是它尝试根据lambda表达式确定URL,该表达式应始终是控制器上的方法调用。这样它就知道传递的动作名称和参数。如果lambda表达式不再是MethodCallExpression
,则无法确定URL。