通常,我会希望呈现一个带有数据库内容的ActionLink (想象一下Id/名称组合),因此我会将以下内容放在我的视图中:
@foreach (var row in Model)
{
<li>@Html.ActionLink(row.Name, "Action", "Controller", new { id = row.Id })</li>
}但是,如果名称是空字符串,则会引发异常。有没有办法阻止这件事。我想重写ActionLink,但是它是一个扩展,所以我不能重写。
有什么建议吗?
编辑:
首先,我不控制数据,否则我将确保Name字段是必需的,并且始终填充。不幸的是,情况并非如此。
其次,我意识到用户将没有什么可点击的,但我相信呈现一个空链接比给他们一个YSOD更好的选择。
发布于 2013-04-11 15:31:19
事实证明,与具有相同签名的扩展方法相比,实例方法始终是首选方法。
我能够加载一个CustomHtmlHelper并将实例方法ActionLink方法放入新的类中:
public abstract class CustomWebViewPage<T> : WebViewPage<T>
{
public new CustomHtmlHelper<T> Html { get; set; }
public override void InitHelpers()
{
Ajax = new AjaxHelper<T>(ViewContext, this);
Url = new UrlHelper(ViewContext.RequestContext);
//Load Custom Html Helper instead of Default
Html = new CustomHtmlHelper<T>(ViewContext, this);
}
}HtmlHelper如下所示(从Reflector复制的ActionLink方法没有LinkText错误检查):
public class CustomHtmlHelper<T> : HtmlHelper<T>
{
public CustomHtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer) :
base(viewContext, viewDataContainer)
{
}
//Instance methods will always be called instead of extension methods when both exist with the same signature...
public MvcHtmlString ActionLink(string linkText, string actionName)
{
return ActionLink(linkText, actionName, null, new RouteValueDictionary(), new RouteValueDictionary());
}
public MvcHtmlString ActionLink(string linkText, string actionName, object routeValues)
{
return ActionLink(linkText, actionName, null, new RouteValueDictionary(routeValues), new RouteValueDictionary());
}
public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName)
{
return ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(), new RouteValueDictionary());
}
public MvcHtmlString ActionLink(string linkText, string actionName, RouteValueDictionary routeValues)
{
return ActionLink(linkText, actionName, null, routeValues, new RouteValueDictionary());
}
public MvcHtmlString ActionLink(string linkText, string actionName, object routeValues, object htmlAttributes)
{
return ActionLink(linkText, actionName, null, new RouteValueDictionary(routeValues), AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public MvcHtmlString ActionLink(string linkText, string actionName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
return ActionLink(linkText, actionName, null, routeValues, htmlAttributes);
}
public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
{
return ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(routeValues), AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
return MvcHtmlString.Create(GenerateLink(ViewContext.RequestContext, RouteCollection, linkText, null, actionName, controllerName, routeValues, htmlAttributes));
}
public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes)
{
return ActionLink(linkText, actionName, controllerName, protocol, hostName, fragment, new RouteValueDictionary(routeValues), AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public MvcHtmlString ActionLink(string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
return MvcHtmlString.Create(GenerateLink(ViewContext.RequestContext, RouteCollection, linkText, null, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes));
}
}最后,将pageBaseType int Views/Web.config文件设置为使用新的自定义WebViewPage:
<system.web.webPages.razor>
...
<pages pageBaseType="Fully.Qualified.Namespace.CustomWebViewPage">
...
</pages>
</system.web.webPages.razor>希望这能帮到别人。
发布于 2013-04-11 15:06:19
您将遇到的问题是,如果名称为空,则UI中的用户没有什么可单击的。示例:<a href="someUrl"></a>没有提供可点击的对象。
更好的方法可能是,如果您可以为那些具有空字符串的行提供默认的"No Name“字符串。
@foreach (var row in Model)
{
<li>@Html.ActionLink(string.isNullOrEmpty(row.Name) ? "No Name" : row.Name, "Action", "Controller", new { id = row.Id })</li>
}编辑
如果不想在每个@Html.ActionLink中添加条件,则可以创建自己的@Html.Helper。
public static IHtmlString ActionLinkCheckNull(this HtmlHelper htmlHelper, string linkText, string action, string controller, object routeValues, object htmlAttributes)
{
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var anchor = new TagBuilder("a") { InnerHtml = string.IsNullOrEmpty(linkText) ? "No Name", linktext };
anchor.Attributes["href"] = urlHelper.Action(action, controller, routeValues);
anchor.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(anchor.ToString());
}然后,在视图文件夹web.config中,添加对您放置此扩展的命名空间的引用,这样您就不必在每个视图的顶部都有一个using语句。示例:
<add namespace="Core.Extensions"/>然后在您的视图中,使用
@Html.ActionLinkCheckNull(row.Name, "Action", "Controller", new { id = row.Id })发布于 2013-04-11 15:11:37
为了更具体地说明汤米的意思,我想包括一个最终被称为被保护的方法:
private static string GenerateLinkInternal(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool includeImplicitMvcValues)
{
string value = UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, routeCollection, requestContext, includeImplicitMvcValues);
TagBuilder tagBuilder = new TagBuilder("a")
{
InnerHtml = (!string.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : string.Empty
};
tagBuilder.MergeAttributes<string, object>(htmlAttributes);
tagBuilder.MergeAttribute("href", value);
return tagBuilder.ToString(TagRenderMode.Normal);
}因此,由于您正在构建链接,外部方法将抛出一个异常,因为将不会在屏幕上显示任何文本。的代码如下所示:
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
{
if (string.IsNullOrEmpty(linkText))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "linkText");
}
return MvcHtmlString.Create(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null, actionName, controllerName, routeValues, htmlAttributes));
}从技术上讲,代码不需要受到保护,但它是一种特性。
这里有一个解决办法,但是您需要像这样构建自己的ActionLink扩展方法,并将其放在项目的某个代码文件中:
using System;
using System.Collections.Generic;
using System.Web.Mvc.Resources;
using System.Web.Routing;
namespace System.Web.Mvc.Html
{
public static class MyLinkExtensions
{
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, int identifier)
{
return htmlHelper.ActionLink(string.IsNullOrEmpty(linkText) ? "some default text" : linkText, actionName, controllerName, new { id = identifier });
}
}
}现在你的标记看起来是这样的:
@foreach (var row in Model)
{
<li>@Html.ActionLink(row.Name, "Action", "Controller", row.Id)</li>
}您已经封装了转帐以确定linkText的状态,但仍然在一行中呈现您的链接。
https://stackoverflow.com/questions/15952240
复制相似问题