前言

运营部门一直对公司官网SEO有意见,认为做得不好(说得好像运营做不好都是seo似的)。为此两部门老大还闹到CEO那去了。

也因为这事,工作计划终于排上日程。沟通一番后得知有如下几点需求:

1.所有链接都得是绝对地址。比如之前是/about.html,现在得变成http://xxx.com/about.html(你妹啊,这样我本地怎么测试)

2.所有目录最后都加/,没有的定久重定向到加/的。比如之前/xxx  ,现在得变成http://xxx.com/xxx/

3.图片必须加alt ,width height 属性

分析编码

前些天图片问题已经改完了,现在重点是链接。因为项目链接大多走的Url.Action,所以自然的想到得从这入手。

其实微软已经为我们提供了这个实现,即 @Url.Action("actionName","controllerName","routeValues","protocol","hostName")

全解决方案搜索Url.Action,一千多处。想到前面优化img标签加alt,才五百多处就花了一天半时间,这肯定是不能接受的。

mvc 不是开源了吗,把源码down下来看看,https://git01.codeplex.com/aspnetwebstack

分析源码定位到两个核心的类 UrlHelper WebViewPage

 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

 using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Web.Mvc.Properties;
using System.Web.Routing;
using System.Web.WebPages; namespace System.Web.Mvc
{
public class UrlHelper
{
/// <summary>
/// Key used to signify that a route URL generation request should include HTTP routes (e.g. Web API).
/// If this key is not specified then no HTTP routes will match.
/// </summary>
private const string HttpRouteKey = "httproute"; /// <summary>
/// Initializes a new instance of the <see cref="UrlHelper"/> class.
/// </summary>
/// <remarks>The default constructor is intended for use by unit testing only.</remarks>
public UrlHelper()
{
} public UrlHelper(RequestContext requestContext)
: this(requestContext, RouteTable.Routes)
{
} public UrlHelper(RequestContext requestContext, RouteCollection routeCollection)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
if (routeCollection == null)
{
throw new ArgumentNullException("routeCollection");
}
RequestContext = requestContext;
RouteCollection = routeCollection;
} public RequestContext RequestContext { get; private set; } public RouteCollection RouteCollection { get; private set; } public virtual string Action()
{
return RequestContext.HttpContext.Request.RawUrl;
} public virtual string Action(string actionName)
{
return GenerateUrl(null /* routeName */, actionName, null, (RouteValueDictionary)null /* routeValues */);
} public virtual string Action(string actionName, object routeValues)
{
return GenerateUrl(null /* routeName */, actionName, null /* controllerName */, TypeHelper.ObjectToDictionary(routeValues));
} public virtual string Action(string actionName, RouteValueDictionary routeValues)
{
return GenerateUrl(null /* routeName */, actionName, null /* controllerName */, routeValues);
} public virtual string Action(string actionName, string controllerName)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, (RouteValueDictionary)null /* routeValues */);
} public virtual string Action(string actionName, string controllerName, object routeValues)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, TypeHelper.ObjectToDictionary(routeValues));
} public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, routeValues);
} public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, null /* hostName */, null /* fragment */, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
} public virtual string Action(string actionName, string controllerName, object routeValues, string protocol)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, null /* hostName */, null /* fragment */, TypeHelper.ObjectToDictionary(routeValues), RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
} public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, hostName, null /* fragment */, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
} public virtual string Content(string contentPath)
{
return GenerateContentUrl(contentPath, RequestContext.HttpContext);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public static string GenerateContentUrl(string contentPath, HttpContextBase httpContext)
{
if (String.IsNullOrEmpty(contentPath))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentPath");
} if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
} if (contentPath[] == '~')
{
return UrlUtil.GenerateClientUrl(httpContext, contentPath);
}
else
{
return contentPath;
}
} //REVIEW: Should we have an overload that takes Uri?
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", Justification = "Needs to take same parameters as HttpUtility.UrlEncode()")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
public virtual string Encode(string url)
{
return HttpUtility.UrlEncode(url);
} private string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues)
{
return GenerateUrl(routeName, actionName, controllerName, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public static string GenerateUrl(string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues)
{
string url = GenerateUrl(routeName, actionName, controllerName, routeValues, routeCollection, requestContext, includeImplicitMvcValues); if (url != null)
{
if (!String.IsNullOrEmpty(fragment))
{
url = url + "#" + fragment;
} if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName))
{
Uri requestUrl = requestContext.HttpContext.Request.Url;
protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp;
hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host; string port = String.Empty;
string requestProtocol = requestUrl.Scheme; if (String.Equals(protocol, requestProtocol, StringComparison.OrdinalIgnoreCase))
{
port = requestUrl.IsDefaultPort ? String.Empty : (":" + Convert.ToString(requestUrl.Port, CultureInfo.InvariantCulture));
} url = protocol + Uri.SchemeDelimiter + hostName + port + url;
}
} return url;
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues)
{
if (routeCollection == null)
{
throw new ArgumentNullException("routeCollection");
} if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
} RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, requestContext.RouteData.Values, routeValues, includeImplicitMvcValues); VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues);
if (vpd == null)
{
return null;
} string modifiedUrl = UrlUtil.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);
return modifiedUrl;
} [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Response.Redirect() takes its URI as a string parameter.")]
public virtual bool IsLocalUrl(string url)
{
// TODO this should call the System.Web.dll API once it gets added to the framework and MVC takes a dependency on it.
return RequestExtensions.IsUrlLocalToHost(RequestContext.HttpContext.Request, url);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(object routeValues)
{
return RouteUrl(null /* routeName */, routeValues);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(RouteValueDictionary routeValues)
{
return RouteUrl(null /* routeName */, routeValues);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(string routeName)
{
return RouteUrl(routeName, (object)null /* routeValues */);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(string routeName, object routeValues)
{
return RouteUrl(routeName, routeValues, null /* protocol */);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(string routeName, RouteValueDictionary routeValues)
{
return RouteUrl(routeName, routeValues, null /* protocol */, null /* hostName */);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(string routeName, object routeValues, string protocol)
{
return GenerateUrl(routeName, null /* actionName */, null /* controllerName */, protocol, null /* hostName */, null /* fragment */, TypeHelper.ObjectToDictionary(routeValues), RouteCollection, RequestContext, false /* includeImplicitMvcValues */);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string RouteUrl(string routeName, RouteValueDictionary routeValues, string protocol, string hostName)
{
return GenerateUrl(routeName, null /* actionName */, null /* controllerName */, protocol, hostName, null /* fragment */, routeValues, RouteCollection, RequestContext, false /* includeImplicitMvcValues */);
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string HttpRouteUrl(string routeName, object routeValues)
{
return HttpRouteUrl(routeName, TypeHelper.ObjectToDictionary(routeValues));
} [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
public virtual string HttpRouteUrl(string routeName, RouteValueDictionary routeValues)
{
if (routeValues == null)
{
// If no route values were passed in at all we have to create a new dictionary
// so that we can add the extra "httproute" key.
routeValues = new RouteValueDictionary();
routeValues.Add(HttpRouteKey, true);
}
else
{
// Copy the dictionary to add the extra "httproute" key used by all Web API routes to
// disambiguate them from other MVC routes.
routeValues = new RouteValueDictionary(routeValues);
if (!routeValues.ContainsKey(HttpRouteKey))
{
routeValues.Add(HttpRouteKey, true);
}
} return GenerateUrl(routeName,
actionName: null,
controllerName: null,
protocol: null,
hostName: null,
fragment: null,
routeValues: routeValues,
routeCollection: RouteCollection,
requestContext: RequestContext,
includeImplicitMvcValues: false);
}
}
}

UrlHelper

 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

 using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Web.Mvc.Properties;
using System.Web.WebPages; namespace System.Web.Mvc
{
public abstract class WebViewPage : WebPageBase, IViewDataContainer, IViewStartPageChild
{
private ViewDataDictionary _viewData;
private DynamicViewDataDictionary _dynamicViewData;
private HttpContextBase _context;
private HtmlHelper<object> _html;
private AjaxHelper<object> _ajax; public override HttpContextBase Context
{
// REVIEW why are we forced to override this?
get { return _context ?? ViewContext.HttpContext; }
set { _context = value; }
} public HtmlHelper<object> Html
{
get
{
if (_html == null && ViewContext != null)
{
_html = new HtmlHelper<object>(ViewContext, this);
}
return _html;
}
set
{
_html = value;
}
} public AjaxHelper<object> Ajax
{
get
{
if (_ajax == null && ViewContext != null)
{
_ajax = new AjaxHelper<object>(ViewContext, this);
}
return _ajax;
}
set
{
_ajax = value;
}
} public object Model
{
get { return ViewData.Model; }
} internal string OverridenLayoutPath { get; set; } public TempDataDictionary TempData
{
get { return ViewContext.TempData; }
} public UrlHelper Url { get; set; } public dynamic ViewBag
{
get
{
if (_dynamicViewData == null)
{
_dynamicViewData = new DynamicViewDataDictionary(() => ViewData);
}
return _dynamicViewData;
}
} public ViewContext ViewContext { get; set; } [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This is the mechanism by which the ViewPage gets its ViewDataDictionary object.")]
public ViewDataDictionary ViewData
{
get
{
if (_viewData == null)
{
SetViewData(new ViewDataDictionary());
}
return _viewData;
}
set { SetViewData(value); }
} protected override void ConfigurePage(WebPageBase parentPage)
{
var baseViewPage = parentPage as WebViewPage;
if (baseViewPage == null)
{
// TODO : review if this check is even necessary.
// When this method is called by the framework parentPage should already be an instance of WebViewPage
// Need to review what happens if this method gets called in Plan9 pointing at an MVC view
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, MvcResources.CshtmlView_WrongViewBase, parentPage.VirtualPath));
} // Set ViewContext and ViewData here so that the layout page inherits ViewData from the main page
ViewContext = baseViewPage.ViewContext;
ViewData = baseViewPage.ViewData;
InitHelpers();
} public override void ExecutePageHierarchy()
{
// Change the Writer so that things like Html.BeginForm work correctly
TextWriter oldWriter = ViewContext.Writer;
ViewContext.Writer = Output; base.ExecutePageHierarchy(); // Overwrite LayoutPage so that returning a view with a custom master page works.
if (!String.IsNullOrEmpty(OverridenLayoutPath))
{
Layout = OverridenLayoutPath;
} // Restore the old View Context Writer
ViewContext.Writer = oldWriter;
} public virtual void InitHelpers()
{
// Html and Ajax helpers are lazily initialized since they are not directly visible to a Razor page.
// In order to ensure back-compat, in the event that this instance gets re-used, we'll reset these
// properties so they get reinitialized the very next time they get accessed.
Html = null;
Ajax = null;
Url = new UrlHelper(ViewContext.RequestContext);
} protected virtual void SetViewData(ViewDataDictionary viewData)
{
_viewData = viewData;
}
}
}

WebViewPage

上文中Url 实际上是UrlHelper 类型 在WebViewPage 中虚方法 InitHelpers 完成实例化。

转到UrlHelper看看,Action有九个重载。而项目中只用到了如下三个:

         public virtual string Action(string actionName, string controllerName)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, (RouteValueDictionary)null /* routeValues */);
} public virtual string Action(string actionName, string controllerName, object routeValues)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, TypeHelper.ObjectToDictionary(routeValues));
} public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, routeValues);
}

上文有提到一个可以生成绝对地址的重载

         public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName)
{
return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, hostName, null /* fragment */, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
}

也就是说,我只要自定义一个UrlHelper实现项目中重载版本间接调用这个生成绝对地址的重载版本即可。

Url 定义在WebViewPage中,意味着WebViewPage也得自定义。可问题是自定义如何用起来呢?搜索一番找到文章结尾三篇文章从中得到了我要答案。

编译发布。整站都浏览了一遍,只要走Url.Action的都是绝对地址了。 nice!无缝对接啊。

总结:

因为生成的绝对地址随iis域名端口自动变化,不会出现本地开发环境也是生产环境地址没法测试问题。项目几乎没什么变动,只需要修改下配置文件即可,无缝对接!

最终版核心代码

using System;
using System.Web.Mvc;
using System.Web.WebPages; namespace SF.MVC.Core
{ public abstract class WebViewPage<TModel> : System.Web.Mvc.WebViewPage<TModel>
{
public new CustomUrlHelper Url { get; set; } public override void InitHelpers()
{
base.InitHelpers();
Url = new CustomUrlHelper(ViewContext.RequestContext);
} } public abstract class WebViewPage : WebViewPage<dynamic>
{
} }

CustomWebViewPage

 using System;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.WebPages;
using System.Collections.Generic; namespace SF.MVC.Core
{
public class CustomUrlHelper : UrlHelper
{
public CustomUrlHelper(RequestContext requestContext)
: base(requestContext, RouteTable.Routes)
{
} public new string Action(string actionName, string controllerName)
{
var hostName = RequestContext.HttpContext.Request.Url.Host;
return GenerateUrl(null, actionName, controllerName, null, hostName, null, (RouteValueDictionary)null, RouteCollection, RequestContext, true);
} public new string Action(string actionName, string controllerName, object routeValues)
{
var hostName = RequestContext.HttpContext.Request.Url.Host;
return GenerateUrl(null, actionName, controllerName, null, hostName, null, new RouteValueDictionary(routeValues), RouteCollection, RequestContext, true);
} public new string RouteUrl(string routeName)
{
var hostName = RequestContext.HttpContext.Request.Url.Host;
return GenerateUrl(routeName, null, null, null, hostName, null, (RouteValueDictionary)null, RouteCollection, RequestContext, false); } public new static string GenerateUrl(string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues)
{
string url = GenerateUrl(routeName, actionName, controllerName, routeValues, routeCollection, requestContext, includeImplicitMvcValues); if (url != null)
{
if (!IsContain(url))
url += "/"; if (!String.IsNullOrEmpty(fragment))
{
url = url + "#" + fragment;
} if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName))
{
Uri requestUrl = requestContext.HttpContext.Request.Url;
protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp;
hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host; string port = String.Empty;
string requestProtocol = requestUrl.Scheme; if (String.Equals(protocol, requestProtocol, StringComparison.OrdinalIgnoreCase))
{
port = requestUrl.IsDefaultPort ? String.Empty : (":" + Convert.ToString(requestUrl.Port, CultureInfo.InvariantCulture));
} url = protocol + Uri.SchemeDelimiter + hostName + port + url;
}
} return url;
} /// <summary>
/// 判断字符串中是否包含某部分
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static bool IsContain(string input)
{
if (string.IsNullOrWhiteSpace(input)) return false; if (input == "/")
{
return true;
}
else if(input.Contains("articledetial"))
{
return true;
}
else if (input.Contains("special"))
{
return true;
}
else if(input.EndsWith(".html", StringComparison.CurrentCultureIgnoreCase))
{
return true;
} return false;
} }
}

CustomUrlHelper

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc; namespace SF.MVC.Core
{
public class PermanentRedirectFilter : ActionFilterAttribute
{ /// <summary>
/// 301永久重定向
/// </summary>
/// <param name="filterContext"></param>
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string url = filterContext.HttpContext.Request.Url.AbsolutePath; if (!url.EndsWith("/"))
{
filterContext.HttpContext.Response.AddHeader("Location", url + "/");
filterContext.HttpContext.Response.Status = "301 Moved Permanently";
filterContext.HttpContext.Response.StatusCode = ; } }
} }

301永久重定向

Views/Web.config如下节点:

  <system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="SF.MVC.Core.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization"/>
<add namespace="System.Web.Routing" />
<add namespace="SF.MVC.Core" />
</namespaces>
</pages>
</system.web.webPages.razor>

后记:

人算不如天算,本机、测试环境都测试通过了,没想到生产环境做了负载均衡,有端口号反而杯具了。 这样就会出现有时需要有时不需要问题,没办法只能加个配置项来控制了。

 using System;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.WebPages;
using System.Collections.Generic;
using MSP.Common.Tools; namespace SF.MVC.Core
{
public class CustomUrlHelper : UrlHelper
{
/// <summary>
/// 是否需要加端口号
/// </summary>
private static bool IsNeedProtocol = false; public CustomUrlHelper(RequestContext requestContext)
: base(requestContext, RouteTable.Routes)
{
ConfigManager config = new ConfigManager();
config.LoadConfig("common"); string configValue = config.GetConfig("NeedProtocol") == null ? "false" : config.GetConfig("NeedProtocol").Value; bool.TryParse(configValue, out IsNeedProtocol); } public new string Action(string actionName, string controllerName)
{
var hostName = RequestContext.HttpContext.Request.Url.Host;
return GenerateUrl(null, actionName, controllerName, null, hostName, null, (RouteValueDictionary)null, RouteCollection, RequestContext, true);
} public new string Action(string actionName, string controllerName, object routeValues)
{
var hostName = RequestContext.HttpContext.Request.Url.Host;
return GenerateUrl(null, actionName, controllerName, null, hostName, null, new RouteValueDictionary(routeValues), RouteCollection, RequestContext, true);
} public new string RouteUrl(string routeName)
{
var hostName = RequestContext.HttpContext.Request.Url.Host;
return GenerateUrl(routeName, null, null, null, hostName, null, (RouteValueDictionary)null, RouteCollection, RequestContext, false); } public new static string GenerateUrl(string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues)
{
string url = GenerateUrl(routeName, actionName, controllerName, routeValues, routeCollection, requestContext, includeImplicitMvcValues); if (url != null)
{
if (!IsContain(url))
url += "/"; if (!String.IsNullOrEmpty(fragment))
{
url = url + "#" + fragment;
} if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName))
{
Uri requestUrl = requestContext.HttpContext.Request.Url;
protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp;
hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host; string port = String.Empty;
string requestProtocol = requestUrl.Scheme; if (IsNeedProtocol && String.Equals(protocol, requestProtocol, StringComparison.OrdinalIgnoreCase))
{
port = requestUrl.IsDefaultPort ? String.Empty : (":" + Convert.ToString(requestUrl.Port, CultureInfo.InvariantCulture));
} url = protocol + Uri.SchemeDelimiter + hostName + port + url;
}
} return url;
} /// <summary>
/// 判断字符串中是否包含某部分
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static bool IsContain(string input)
{
if (string.IsNullOrWhiteSpace(input)) return false; if (input == "/")
{
return true;
}
else if(input.Contains("articledetial"))
{
return true;
}
else if (input.Contains("special"))
{
return true;
}
else if(input.EndsWith(".html", StringComparison.CurrentCultureIgnoreCase))
{
return true;
} return false;
} }
}

修改后CustomUrlHelper

代码中构造函数读取配置您需要改写成自己的实现逻辑。

参考:

Changing Base Type Of A Razor View

Create Your Own Custom ViewWebPage for ASP.NET MVC

MVC中自定义ViewPage和WebViewPage

自定义WebViewPage,实现Url.Action生成绝对地址的更多相关文章

  1. ASP.NET MVC 视图层-生成链接相关(Html.ActionLink,Url.Action)

    1. @Html.ActionLink()  参考 也是使用在chtml模板中,返回参数中指定controller.指定action的所生成的超链接标签<a>标签html文本.如果没有指定 ...

  2. ASP.NET MVC cs类中根据Controller和Action生成URL

    var Url = new UrlHelper(HttpContext.Current.Request.RequestContext); Url.Action("AnnounceDetail ...

  3. MVC 中与链接相关的辅助方法(Html.ActionLink,Html.RouteLink , Url.Action , Url.Content ,Url.RouteUrl)

    Html.ActionLink 与 Url.Action  1.两者者是根据给定的Controller,Action 生成链接, 但是Html.ActionLink 返回的是MvcHtmlString ...

  4. HTML.ActionLink 和Html.Action和 Url.Action 的区别

    1. html.ActionLink生成一个<a href=".."></a>标记..例如:@Html.ActionLink(“链接文本”.“someact ...

  5. HTML.ActionLink 和 Url.Action 的区别

    html.ActionLink生成一个<a href=".."></a>标记.而Url.Action只返回一个url.例如:@Html.ActionLink ...

  6. Html.Action、html.ActionLink与Url.Action的区别

    1.html.ActionLink返回的指向指定controller.指定action的超链接标签<a>标签.如果没有指定controller,则默认为本页面对应的Controller. ...

  7. Html.ActionLink与Url.Action区别

    一.@Html.ActionLink()概述 在MVC的Rasor视图引擎中,微软采用一种全新的方式来表示从前的超链接方式,它代替了从前的繁杂的超链接标签,让代码看起来更加简洁.通过浏览器依然会解析成 ...

  8. XAF 框架中,自定义参数动作(Action),输入参数的控件可定义,用于选择组织及项目

    XAF 框架中,如何生成一个自定义参数动作(Action),输入参数的控件可定义? 参考文档:https://documentation.devexpress.com/eXpressAppFramew ...

  9. Font Combiner – 自定义网页字体和图标生成工具

    Font Combiner 是一个功能丰富的 Web 字体生成工具和字体改进工具,提供字距调整.构造子集.各种提示选项和自定义字体字形组合.您可以生成您自己的自定义字体的格式和文件大小. 另外还有成千 ...

随机推荐

  1. codevs1163访问艺术馆 树形dp

    算裸的树形dp吧 回来复习一波 #include<cstdio> #include<cstring> #include<algorithm> #include< ...

  2. 设计模式之笔记--简单工厂模式(Simple Factory)

    简单工厂模式(Simple Factory) 类图 描述 简单工厂: 一个抽象产品类,可以派生多个具体产品类: 一个具体工厂类: 工厂只能创建一个具体产品. 应用场景 汽车接口 public inte ...

  3. idea配置maven自动下载 源码和文档

    勾上图中红框处,即可

  4. ECharts问题--散点图中对散点添加点击事件

    1. 我们这次就没有先讲解怎么使用散点图了,这个跟之前的一些图还是很类似的,不会的可以去官网上面查看 API 使用.我们这次讲解的是为散点图中的散点添加点击事件,然后在图表之外的一个 div 里面显示 ...

  5. P2654 原核生物培养

    P2654 原核生物培养 题目描述 W教授最近正在研究一种原核生物,这种生物的生长方式很奇特,只能通过吃掉同类而生长.两个该种生物相遇,较大质量的会把较小的吃掉(相同的话就看RP了),吃掉后较大的生物 ...

  6. JavaScript的字符串详解

    #转载请留言联系 字符串合并 + var str1="chi"; var str2="chung"; console.log(str1+str2) 输出:chi ...

  7. python常用内置函数整理

    1.最常见的内置函数是print print("Hello World!") 2.数学运算 abs(-5) # 取绝对值,也就是5 round(2.6) # 四舍五入取整,也就是3 ...

  8. 自动监控tomcat脚本并且执行重启操作

    #!/bin/sh # func:自动监控tomcat脚本并且执行重启操作 # author:reed # date:// # 定义环境变量 MYPATH=/usr/local/jdk/bin exp ...

  9. 常用的LUA片段

    生成TS的办法 local t=ngx.now(); local n=os.date(,); n=n..-string.len(n)); ngx.say(n); 产生101至200的所有素数 func ...

  10. 更换介质:请把标有…… DVD 的盘片插入驱动器“/media/cdrom/”再按回车键“ 解决方法

    https://blog.csdn.net/no7oor/article/details/12776815