前言

运营部门一直对公司官网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

  1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2 
  3 using System.Diagnostics.CodeAnalysis;
  4 using System.Globalization;
  5 using System.Web.Mvc.Properties;
  6 using System.Web.Routing;
  7 using System.Web.WebPages;
  8 
  9 namespace System.Web.Mvc
 10 {
 11     public class UrlHelper
 12     {
 13         /// <summary>
 14         /// Key used to signify that a route URL generation request should include HTTP routes (e.g. Web API).
 15         /// If this key is not specified then no HTTP routes will match.
 16         /// </summary>
 17         private const string HttpRouteKey = "httproute";
 18 
 19         /// <summary>
 20         /// Initializes a new instance of the <see cref="UrlHelper"/> class.
 21         /// </summary>
 22         /// <remarks>The default constructor is intended for use by unit testing only.</remarks>
 23         public UrlHelper()
 24         {
 25         }
 26 
 27         public UrlHelper(RequestContext requestContext)
 28             : this(requestContext, RouteTable.Routes)
 29         {
 30         }
 31 
 32         public UrlHelper(RequestContext requestContext, RouteCollection routeCollection)
 33         {
 34             if (requestContext == null)
 35             {
 36                 throw new ArgumentNullException("requestContext");
 37             }
 38             if (routeCollection == null)
 39             {
 40                 throw new ArgumentNullException("routeCollection");
 41             }
 42             RequestContext = requestContext;
 43             RouteCollection = routeCollection;
 44         }
 45 
 46         public RequestContext RequestContext { get; private set; }
 47 
 48         public RouteCollection RouteCollection { get; private set; }
 49 
 50         public virtual string Action()
 51         {
 52             return RequestContext.HttpContext.Request.RawUrl;
 53         }
 54 
 55         public virtual string Action(string actionName)
 56         {
 57             return GenerateUrl(null /* routeName */, actionName, null, (RouteValueDictionary)null /* routeValues */);
 58         }
 59 
 60         public virtual string Action(string actionName, object routeValues)
 61         {
 62             return GenerateUrl(null /* routeName */, actionName, null /* controllerName */, TypeHelper.ObjectToDictionary(routeValues));
 63         }
 64 
 65         public virtual string Action(string actionName, RouteValueDictionary routeValues)
 66         {
 67             return GenerateUrl(null /* routeName */, actionName, null /* controllerName */, routeValues);
 68         }
 69 
 70         public virtual string Action(string actionName, string controllerName)
 71         {
 72             return GenerateUrl(null /* routeName */, actionName, controllerName, (RouteValueDictionary)null /* routeValues */);
 73         }
 74 
 75         public virtual string Action(string actionName, string controllerName, object routeValues)
 76         {
 77             return GenerateUrl(null /* routeName */, actionName, controllerName, TypeHelper.ObjectToDictionary(routeValues));
 78         }
 79 
 80         public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues)
 81         {
 82             return GenerateUrl(null /* routeName */, actionName, controllerName, routeValues);
 83         }
 84 
 85         public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol)
 86         {
 87             return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, null /* hostName */, null /* fragment */, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
 88         }
 89 
 90         public virtual string Action(string actionName, string controllerName, object routeValues, string protocol)
 91         {
 92             return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, null /* hostName */, null /* fragment */, TypeHelper.ObjectToDictionary(routeValues), RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
 93         }
 94 
 95         public virtual string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName)
 96         {
 97             return GenerateUrl(null /* routeName */, actionName, controllerName, protocol, hostName, null /* fragment */, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
 98         }
 99 
100         public virtual string Content(string contentPath)
101         {
102             return GenerateContentUrl(contentPath, RequestContext.HttpContext);
103         }
104 
105         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
106         public static string GenerateContentUrl(string contentPath, HttpContextBase httpContext)
107         {
108             if (String.IsNullOrEmpty(contentPath))
109             {
110                 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "contentPath");
111             }
112 
113             if (httpContext == null)
114             {
115                 throw new ArgumentNullException("httpContext");
116             }
117 
118             if (contentPath[0] == '~')
119             {
120                 return UrlUtil.GenerateClientUrl(httpContext, contentPath);
121             }
122             else
123             {
124                 return contentPath;
125             }
126         }
127 
128         //REVIEW: Should we have an overload that takes Uri?
129         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", Justification = "Needs to take same parameters as HttpUtility.UrlEncode()")]
130         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
131         public virtual string Encode(string url)
132         {
133             return HttpUtility.UrlEncode(url);
134         }
135 
136         private string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues)
137         {
138             return GenerateUrl(routeName, actionName, controllerName, routeValues, RouteCollection, RequestContext, true /* includeImplicitMvcValues */);
139         }
140 
141         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
142         public static string GenerateUrl(string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues)
143         {
144             string url = GenerateUrl(routeName, actionName, controllerName, routeValues, routeCollection, requestContext, includeImplicitMvcValues);
145 
146             if (url != null)
147             {
148                 if (!String.IsNullOrEmpty(fragment))
149                 {
150                     url = url + "#" + fragment;
151                 }
152 
153                 if (!String.IsNullOrEmpty(protocol) || !String.IsNullOrEmpty(hostName))
154                 {
155                     Uri requestUrl = requestContext.HttpContext.Request.Url;
156                     protocol = (!String.IsNullOrEmpty(protocol)) ? protocol : Uri.UriSchemeHttp;
157                     hostName = (!String.IsNullOrEmpty(hostName)) ? hostName : requestUrl.Host;
158 
159                     string port = String.Empty;
160                     string requestProtocol = requestUrl.Scheme;
161 
162                     if (String.Equals(protocol, requestProtocol, StringComparison.OrdinalIgnoreCase))
163                     {
164                         port = requestUrl.IsDefaultPort ? String.Empty : (":" + Convert.ToString(requestUrl.Port, CultureInfo.InvariantCulture));
165                     }
166 
167                     url = protocol + Uri.SchemeDelimiter + hostName + port + url;
168                 }
169             }
170 
171             return url;
172         }
173 
174         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
175         public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, RouteCollection routeCollection, RequestContext requestContext, bool includeImplicitMvcValues)
176         {
177             if (routeCollection == null)
178             {
179                 throw new ArgumentNullException("routeCollection");
180             }
181 
182             if (requestContext == null)
183             {
184                 throw new ArgumentNullException("requestContext");
185             }
186 
187             RouteValueDictionary mergedRouteValues = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, requestContext.RouteData.Values, routeValues, includeImplicitMvcValues);
188 
189             VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues);
190             if (vpd == null)
191             {
192                 return null;
193             }
194 
195             string modifiedUrl = UrlUtil.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);
196             return modifiedUrl;
197         }
198 
199         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "Response.Redirect() takes its URI as a string parameter.")]
200         public virtual bool IsLocalUrl(string url)
201         {
202             // TODO this should call the System.Web.dll API once it gets added to the framework and MVC takes a dependency on it.
203             return RequestExtensions.IsUrlLocalToHost(RequestContext.HttpContext.Request, url);
204         }
205 
206         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
207         public virtual string RouteUrl(object routeValues)
208         {
209             return RouteUrl(null /* routeName */, routeValues);
210         }
211 
212         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
213         public virtual string RouteUrl(RouteValueDictionary routeValues)
214         {
215             return RouteUrl(null /* routeName */, routeValues);
216         }
217 
218         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
219         public virtual string RouteUrl(string routeName)
220         {
221             return RouteUrl(routeName, (object)null /* routeValues */);
222         }
223 
224         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
225         public virtual string RouteUrl(string routeName, object routeValues)
226         {
227             return RouteUrl(routeName, routeValues, null /* protocol */);
228         }
229 
230         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
231         public virtual string RouteUrl(string routeName, RouteValueDictionary routeValues)
232         {
233             return RouteUrl(routeName, routeValues, null /* protocol */, null /* hostName */);
234         }
235 
236         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
237         public virtual string RouteUrl(string routeName, object routeValues, string protocol)
238         {
239             return GenerateUrl(routeName, null /* actionName */, null /* controllerName */, protocol, null /* hostName */, null /* fragment */, TypeHelper.ObjectToDictionary(routeValues), RouteCollection, RequestContext, false /* includeImplicitMvcValues */);
240         }
241 
242         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
243         public virtual string RouteUrl(string routeName, RouteValueDictionary routeValues, string protocol, string hostName)
244         {
245             return GenerateUrl(routeName, null /* actionName */, null /* controllerName */, protocol, hostName, null /* fragment */, routeValues, RouteCollection, RequestContext, false /* includeImplicitMvcValues */);
246         }
247 
248         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
249         public virtual string HttpRouteUrl(string routeName, object routeValues)
250         {
251             return HttpRouteUrl(routeName, TypeHelper.ObjectToDictionary(routeValues));
252         }
253 
254         [SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
255         public virtual string HttpRouteUrl(string routeName, RouteValueDictionary routeValues)
256         {
257             if (routeValues == null)
258             {
259                 // If no route values were passed in at all we have to create a new dictionary
260                 // so that we can add the extra "httproute" key.
261                 routeValues = new RouteValueDictionary();
262                 routeValues.Add(HttpRouteKey, true);
263             }
264             else
265             {
266                 // Copy the dictionary to add the extra "httproute" key used by all Web API routes to
267                 // disambiguate them from other MVC routes.
268                 routeValues = new RouteValueDictionary(routeValues);
269                 if (!routeValues.ContainsKey(HttpRouteKey))
270                 {
271                     routeValues.Add(HttpRouteKey, true);
272                 }
273             }
274 
275             return GenerateUrl(routeName,
276                 actionName: null,
277                 controllerName: null,
278                 protocol: null,
279                 hostName: null,
280                 fragment: null,
281                 routeValues: routeValues,
282                 routeCollection: RouteCollection,
283                 requestContext: RequestContext,
284                 includeImplicitMvcValues: false);
285         }
286     }
287 }
UrlHelper

相关文章: