跳过生成Html.ActionLink的只读字段

本文关键字:读字段 ActionLink Html | 更新日期: 2023-09-27 18:15:14

我有一个基本请求对象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);
}

跳过生成Html.ActionLink的只读字段

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));
}