【问题标题】:Skip generation of readonly fields for Html.ActionLink跳过为 Html.ActionLink 生成只读字段
【发布时间】:2015-09-30 15:14:11
【问题描述】:

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

有什么想法可以跳过为操作链接生成只读字段吗?也许通过某种方式使用反射?

由 cmets 编辑

这行得通吗?

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

【问题讨论】:

  • 为什么要将整个请求对象作为助手中的第四个参数传递?
  • 应该传递什么?
  • 只有你需要路由的值,我猜它更像new {Id=request.id}
  • 但我不知道每个实现所需的值都可以拥有自己的值。或者我可以创建一个新的RouteValueDictionary 仅具有具体请求实现的属性并通过“手动”添加该区域?
  • 因此您将扩展 RequestBase 以包含更多属性。我懂了。我看不到您将任何属性定义为只读的位置,因此我看不到如何以编程方式将它们过滤掉。您也可以通过路由来处理其中的一些问题。

标签: c# .net asp.net-mvc reflection extension-methods


【解决方案1】:
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));
}

【讨论】:

  • HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes) 应该可以解决问题
  • 是的,只是检查以确保它是一个公共方法。
【解决方案2】:

在 Robert 的 cmets 之后,我想出了以下适合我的方法:

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

【讨论】:

  • 这应该也可以。我只是不喜欢使用反射,尤其是在低级别的事情上。反射并不是最快的事情(或者我认为,也许有一天我应该对它进行基准测试)。
  • @RobertMcKee 我知道反射在许多情况下可能不是最高效的解决方案。在我的情况下,我不打算创建数百个链接,所以我可以在这里进行反射;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-03
  • 2019-09-08
  • 1970-01-01
  • 2019-10-22
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
相关资源
最近更新 更多