当action方法不采用原始类型时,使用强类型的ActionLink [英] Using a strongly typed ActionLink when the action method doesn't take a primitive type
问题描述
有人知道我该怎么做:
Html.ActionLink(c => c.SomeAction(new MessageObject {Id = 1}))
Html.ActionLink(c => c.SomeAction(new MessageObject { Id = 1 } ))
这应该输出带有 / Controller / SomeAction / 1网址的链接,并指向以下行中的ActionMethod:
This should output a link with the url of "/Controller/SomeAction/1", pointing at an ActionMethod along the lines of:
public Controller : Controller
{
public ActionResult SomeMethod(MessageObject message)
{
// do something with the message
return View();
}
}
我写了一些类似的形式来生成表格,但是不需要在网址末尾包含Id值。基本上,我想在路线中进行某种反向查找,但找不到有关如何执行此操作的文档。我有一个ModelBinder设置,可以从GET和POST参数构建一个MessageObject,但是我不确定如何反转该过程。
I've written something similar for generating forms, but that doens't need to include the Id value on the end of the Url. Basically I want to do some sort of reverse lookup in my routes but I can't find any doco on how I might go about doing that. I have a ModelBinder setup that is able to build a MessageObject from GET and POST parameters, but I'm not sure how I can reverse the process.
谢谢,
Matt
Thanks, Matt
推荐答案
最后,我最终将以下代码包装在HtmlHelper扩展方法中。这将允许我使用
Html.ActionLink(c => c.SomeAction(new MessageObject {Id = 1}))
In the end I ended up wrapping the following code in an HtmlHelper extension method. This would allow me to use something like Html.ActionLink(c => c.SomeAction(new MessageObject { Id = 1 } ))
public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action)
where TController : Controller
{
Guard.Against<ArgumentNullException>(action == null, @"Action passed to GetRouteValuesFromExpression cannot be null.");
MethodCallExpression methodCall = action.Body as MethodCallExpression;
Guard.Against<InvalidOperationException>(methodCall == null, @"Action passed to GetRouteValuesFromExpression must be method call");
string controllerName = typeof(TController).Name;
Guard.Against<InvalidOperationException>(!controllerName.EndsWith("Controller"), @"Controller passed to GetRouteValuesFromExpression is incorrect");
RouteValueDictionary rvd = new RouteValueDictionary();
rvd.Add("Controller", controllerName.Substring(0, controllerName.Length - "Controller".Length));
rvd.Add("Action", methodCall.Method.Name);
AddParameterValuesFromExpressionToDictionary(rvd, methodCall);
return rvd;
}
/// <summary>
/// Adds a route value for each parameter in the passed in expression. If the parameter is primitive it just uses its name and value
/// if not, it creates a route value for each property on the object with the property's name and value.
/// </summary>
/// <param name="routeValues"></param>
/// <param name="methodCall"></param>
private static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary routeValues, MethodCallExpression methodCall)
{
ParameterInfo[] parameters = methodCall.Method.GetParameters();
methodCall.Arguments.Each(argument =>
{
int index = methodCall.Arguments.IndexOf(argument);
ConstantExpression constExpression = argument as ConstantExpression;
if (constExpression != null)
{
object value = constExpression.Value;
routeValues.Add(parameters[index].Name, value);
}
else
{
object actualArgument = argument;
MemberInitExpression expression = argument as MemberInitExpression;
if (expression != null)
{
actualArgument = Expression.Lambda(argument).Compile().DynamicInvoke();
}
// create a route value for each property on the object
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(actualArgument))
{
object obj2 = descriptor.GetValue(actualArgument);
routeValues.Add(descriptor.Name, obj2);
}
}
});
}
这篇关于当action方法不采用原始类型时,使用强类型的ActionLink的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!