C# 跳过Html.ActionLink的只读字段的生成
我有一个基本请求对象C# 跳过Html.ActionLink的只读字段的生成,c#,.net,asp.net-mvc,reflection,extension-methods,C#,.net,Asp.net Mvc,Reflection,Extension Methods,我有一个基本请求对象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; } }
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>
有没有办法跳过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);
}
在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));
}
为什么要将整个请求对象作为助手中的第四个参数传递?应该传递什么?只有需要传递的值,我猜这更像是
new{Id=request.Id}
,但我不知道每个实现所需的值可以有自己的值。或者我可以创建一个新的RouteValueDictionary
,只包含具体请求实现的属性,并通过“手动”添加区域吗?这样您就可以扩展RequestBase以包含更多属性。我懂了。我看不出您在哪里将任何属性定义为只读,所以我看不出如何通过编程将它们过滤掉。您也可以通过路由来处理其中的一些问题。HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)
应该做些小动作,只是检查以确保它是一个公共方法。这也应该可以。我只是不太喜欢使用反射,尤其是在低层次的事情上。反射并不是最快的事情(或者我认为,也许有一天我真的应该对它进行基准测试)。@RobertMcKee我知道反射可能不是很多情况下最有效的解决方案。在我的例子中,我不会创建数百个链接,所以我对这里的反射非常满意;)
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));
}
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));
}