自定义WebViewPage,实现Url.Action生成绝对地址
前言
运营部门一直对公司官网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
自定义WebViewPage,实现Url.Action生成绝对地址的更多相关文章
- ASP.NET MVC 视图层-生成链接相关(Html.ActionLink,Url.Action)
1. @Html.ActionLink() 参考 也是使用在chtml模板中,返回参数中指定controller.指定action的所生成的超链接标签<a>标签html文本.如果没有指定 ...
- ASP.NET MVC cs类中根据Controller和Action生成URL
var Url = new UrlHelper(HttpContext.Current.Request.RequestContext); Url.Action("AnnounceDetail ...
- MVC 中与链接相关的辅助方法(Html.ActionLink,Html.RouteLink , Url.Action , Url.Content ,Url.RouteUrl)
Html.ActionLink 与 Url.Action 1.两者者是根据给定的Controller,Action 生成链接, 但是Html.ActionLink 返回的是MvcHtmlString ...
- HTML.ActionLink 和Html.Action和 Url.Action 的区别
1. html.ActionLink生成一个<a href=".."></a>标记..例如:@Html.ActionLink(“链接文本”.“someact ...
- HTML.ActionLink 和 Url.Action 的区别
html.ActionLink生成一个<a href=".."></a>标记.而Url.Action只返回一个url.例如:@Html.ActionLink ...
- Html.Action、html.ActionLink与Url.Action的区别
1.html.ActionLink返回的指向指定controller.指定action的超链接标签<a>标签.如果没有指定controller,则默认为本页面对应的Controller. ...
- Html.ActionLink与Url.Action区别
一.@Html.ActionLink()概述 在MVC的Rasor视图引擎中,微软采用一种全新的方式来表示从前的超链接方式,它代替了从前的繁杂的超链接标签,让代码看起来更加简洁.通过浏览器依然会解析成 ...
- XAF 框架中,自定义参数动作(Action),输入参数的控件可定义,用于选择组织及项目
XAF 框架中,如何生成一个自定义参数动作(Action),输入参数的控件可定义? 参考文档:https://documentation.devexpress.com/eXpressAppFramew ...
- Font Combiner – 自定义网页字体和图标生成工具
Font Combiner 是一个功能丰富的 Web 字体生成工具和字体改进工具,提供字距调整.构造子集.各种提示选项和自定义字体字形组合.您可以生成您自己的自定义字体的格式和文件大小. 另外还有成千 ...
随机推荐
- github 下载某一文件夹
作者:知乎用户链接:https://www.zhihu.com/question/25369412/answer/96174755来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...
- Flask 基础知识一
Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后 ...
- 浅谈redux 中间件的原理
在使用redux管理异步数据流的时候,我们会使用中间件,以redux-thunk中间件为例,我们做一下分析: 首先是构建store,我们需要以下代码进行揉入中间件的类似creatStore函数的构造: ...
- Ubunt 服务教程集锦
1.Ubuntu管理服务安装(强烈推荐最好用Xshell和Xftp): 序号 服务名 介绍 教程地址 windows客户端 1 VNC 可以图形界面管理Ubuntu ubuntu安装vncserver ...
- Android之进程通信--Binder
Cilent从ServiceManger哪里获得BnMediaService的BnBinder引用就可以调用BnMediaPlayerService的方法了,BnMediaPlayerService是 ...
- OC学习——OC中的@protocol(@required、@optional)、代理设计模式
一.什么是协议? 1.协议声明了可以被任何类实现的方法 2.协议不是类,它是定义了一个其他对象可以实现的接口 3.如果在某个类中实现了协议中的某个方法,也就是这个类实现了那个协议. 4.协 ...
- NumPy、SciPy 等Python包在Windows下的whl安装包下载
http://www.lfd.uci.edu/~gohlke/pythonlibs/ 感谢加利福尼亚大学尔湾分校(University of California, Irvine)荧光动力实验室(瞎翻 ...
- [BZOJ2151] 种树 贪心
2151: 种树 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 1151 Solved: 613[Submit][Status][Discuss] ...
- bash特性
(1)shell简介 shell是系统的用户界面,提供用户与内核进行交互操作的一种接口,它接收用户输入的命令并把它送入内核去执行.实际上shell是一个命令解释器 (2)shell语法 语法:命令 选 ...
- spark技术热点问题互动问答
决胜云计算大数据时代” Spark亚太研究院100期公益大讲堂 [第4期互动问答分享] Q1:Spark SQL和Shark有啥区别? Shark需要依赖于Hadoop上Hive去做SQL语句的解析 ...