我有一个基本请求对象RequestBase
定义如下:
public abstract class RequestBase
{
public abstract string Area { get; }
public abstract string ActionName { get; }
public abstract string LinkName { get; }
public abstract string ControllerName { get; }
}
和它的子类,比如:
public class RequestTest : RequestBase
{
public Guid Id { get; set; }
public RequestTest()
{
Id = Guid.Empty;
}
#region implementation of RequestBase
public override string Area
{
get { return "MyArea"; }
}
public override string ActionName
{
get { return "Overview"; }
}
public override string ControllerName
{
get { return "Test"; }
}
public override string LinkName
{
get { return "Click me for awesome"; }
}
#endregion
}
问题。我想写一个帮助器来建立这样的链接:
@Html.ActionLinkByRequest(new RequestTest{Id = Guid.Empty})
我现在已经实现了
public static MvcHtmlString ActionLinkByRequest(this HtmlHelper helper, RequestBase request, object htmlAttributes = null)
{
return helper.ActionLink(request.LinkName, request.ActionName, request.ControllerName, request, htmlAttributes);
}
不幸的是它呈现为:
<a href="/MyArea/Test/Overview?EventId=00000000-0000-0000-0000-000000000000&ActionName=Overview&LinkName=Click%20me%20for%20awesome&ControllerName=Test">Click me for awesome</a>
但是我只想要
<a href="/MyArea/Test/Overview?EventId=00000000-0000-0000-0000-000000000000">Click me for awesome</a>
没有只读字段的。因为它们是只读的,所以我不需要在查询字符串中显式地使用它们,因为我的Action
等待具体实现RequestTest
,并且无论如何都会有它们:
public ActionResult Overview(RequestTest request)
{
// do things here
return View();
}
任何想法我可以跳过生成只读字段的actionlink?也许通过某种方式使用反射?
按注释编辑
这个可行吗?
public static MvcHtmlString ActionLinkByRequest(this HtmlHelper helper, RequestBase request, object htmlAttributes = null)
{
var rvd = new RouteValueDictionary();
foreach(var prop in request.GetType().GetProperties().Where(p => p.CanRead && p.CanWrite))
{
// add the property by name and the value
// rvd.Add(prop.Name, prop.GetValue());
}
// add the area (check if not already existing)
if(!rvd.ContainsKey("Area"))
rvd.Add("Area", request.AreaName);
return helper.ActionLink(request.LinkName, request.ActionName, request.ControllerName, request, htmlAttributes);
}
public static MvcHtmlString ActionLinkByRequest(this HtmlHelper helper, RequestBase request, object htmlAttributes = null)
{
var rvd = new RouteValueDictionary(request);
rvd.Remove("ActionName");
rvd.Remove("ControllerName");
rvd.Remove("LinkName");
return helper.ActionLink(request.LinkName, request.ActionName, request.ControllerName, rvd, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
看了Robert的评论后,我想出了以下适合我的方法:
public static MvcHtmlString ActionLinkByRequest(this HtmlHelper helper, RequestBase request, object htmlAttributes = null)
{
// create new value-dictionary to be passed
var rvd = new RouteValueDictionary();
// loop through properties of the request
foreach (var prop in request.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => p.CanRead && p.CanWrite))
{
// add name/value to route-dictionary
rvd.Add(prop.Name, prop.GetValue(request));
}
// check if area is needed
if (!rvd.ContainsKey("Area"))
{
rvd.Add("Area", request.Area);
}
return helper.ActionLink(request.LinkText, request.ActionName, request.ControllerName, rvd, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}