带你读开源—ASP.NET_MVC(十)
2016-09-09 21:02
316 查看
今天研究一下HtmlHelper,ASP.NET MVC框架有数量众多的Helper,包括内置的和用户自己定义的,这些Helper的存在,极大方便了实际开发。我们最为熟悉的莫过于HtmlHelper.ActionLink方法了,它用来在View中生成<a>标签,也就是超链接。在源码中找到其定义,发现它有很多个重载,我们找到其中比较常用的重载版本,见代码段1。
代码段 1
从代码段1中可以看出这个方法是HtmlHelper类的一个扩展方法,还可以发现代码段1的核心代码是HtmlHelper.GenerateLink方法,我们跟踪GenerateLink方法到最终实现(代码段2)。
代码段 2
在代码段2中,用UrlHelper.GenerateUrl方法得到了<a>标签的href属性,然后利用TagBuilder生成HTML标记。我们从语句【InnerHtml =(!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) :String.Empty】可以看出MVC对超链接的内容进行了Html编码,以满足安全方面的考量。下面着重看一下UrlHelper.GenerateUrl方法,见代码段3。
代码段 3
UrlHelper.GenerateUrl方法中,首先用另一个也叫GenerateUrl的重载方法[1]获取url,然后在该url的基础上,附加上“协议”、“主机名”、“端口号”等信息,构成一个完整的URL地址。我们进入上标[1]所示的方法定义(代码段4),发现该段代码首先用RouteValuesHelpers.MergeRouteValues方法得到一个包含路由信息的字典mergedRouteValues,再把该字典作为参数传给routeCollection.GetVirtualPathForArea方法,得到一个VirtualPathData类的对象,最后调用UrlUtil.GenerateClientUrl方法生成用户在浏览器端看到的超链接的URL。
代码段 4
我们进入UrlUtil.GenerateClientUrl方法的定义(代码段5)。
代码段 5
在代码段5中,进一步跟踪GenerateClientUrlInternal方法到其定义(代码段6),最终URL得以生成。
代码段 6
public static MvcHtmlStringActionLink(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"); } returnMvcHtmlString.Create(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext,htmlHelper.RouteCollection, linkText, null /* routeName */, actionName, controllerName,routeValues, htmlAttributes)); }
代码段 1
从代码段1中可以看出这个方法是HtmlHelper类的一个扩展方法,还可以发现代码段1的核心代码是HtmlHelper.GenerateLink方法,我们跟踪GenerateLink方法到最终实现(代码段2)。
private static stringGenerateLinkInternal(RequestContext requestContext, RouteCollectionrouteCollection, string linkText, string routeName, string actionName, stringcontrollerName, string protocol, string hostName, string fragment,RouteValueDictionary routeValues, IDictionary<string, object>htmlAttributes, bool includeImplicitMvcValues) { string url =UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol,hostName, fragment, routeValues, routeCollection, requestContext,includeImplicitMvcValues); TagBuilder tagBuilder = newTagBuilder("a") { InnerHtml =(!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) :String.Empty }; tagBuilder.MergeAttributes(htmlAttributes); tagBuilder.MergeAttribute("href", url); returntagBuilder.ToString(TagRenderMode.Normal); }
代码段 2
在代码段2中,用UrlHelper.GenerateUrl方法得到了<a>标签的href属性,然后利用TagBuilder生成HTML标记。我们从语句【InnerHtml =(!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) :String.Empty】可以看出MVC对超链接的内容进行了Html编码,以满足安全方面的考量。下面着重看一下UrlHelper.GenerateUrl方法,见代码段3。
[SuppressMessage("Microsoft.Design","CA1055:UriReturnValuesShouldNotBeStrings", Justification = "Asthe return value will used only for rendering, string return value is moreappropriate.")] public static string GenerateUrl(stringrouteName, string actionName, string controllerName, string protocol, stringhostName, string fragment, RouteValueDictionary routeValues, RouteCollectionrouteCollection, 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; }
代码段 3
UrlHelper.GenerateUrl方法中,首先用另一个也叫GenerateUrl的重载方法[1]获取url,然后在该url的基础上,附加上“协议”、“主机名”、“端口号”等信息,构成一个完整的URL地址。我们进入上标[1]所示的方法定义(代码段4),发现该段代码首先用RouteValuesHelpers.MergeRouteValues方法得到一个包含路由信息的字典mergedRouteValues,再把该字典作为参数传给routeCollection.GetVirtualPathForArea方法,得到一个VirtualPathData类的对象,最后调用UrlUtil.GenerateClientUrl方法生成用户在浏览器端看到的超链接的URL。
[SuppressMessage("Microsoft.Design","CA1055:UriReturnValuesShouldNotBeStrings", Justification = "Asthe return value will used only for rendering, string return value is moreappropriate.")] public static string GenerateUrl(stringrouteName, string actionName, string controllerName, RouteValueDictionaryrouteValues, RouteCollection routeCollection, RequestContext requestContext,bool includeImplicitMvcValues) { if (routeCollection == null) { throw newArgumentNullException("routeCollection"); } if (requestContext == null) { throw newArgumentNullException("requestContext"); } RouteValueDictionarymergedRouteValues = 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; }
代码段 4
我们进入UrlUtil.GenerateClientUrl方法的定义(代码段5)。
// this method can accept anapp-relative path or an absolute path for contentPath public static stringGenerateClientUrl(HttpContextBase httpContext, string contentPath) { if(String.IsNullOrEmpty(contentPath)) { return contentPath; } // many of the methods we callinternally can't handle query strings properly, so just strip it out for // the time being string query; contentPath =StripQuery(contentPath, out query); // many of the methods we callinternally can't handle query strings properly, so tack it on after processing // the virtual app path and urlrewrites if (String.IsNullOrEmpty(query)) { returnGenerateClientUrlInternal(httpContext, contentPath); } else { returnGenerateClientUrlInternal(httpContext, contentPath) + query; } }
代码段 5
在代码段5中,进一步跟踪GenerateClientUrlInternal方法到其定义(代码段6),最终URL得以生成。
private static stringGenerateClientUrlInternal(HttpContextBase httpContext, string contentPath) { if(String.IsNullOrEmpty(contentPath)) { return contentPath; } // can't callVirtualPathUtility.IsAppRelative since it throws on some inputs bool isAppRelative = contentPath[0]== '~'; if (isAppRelative) { string absoluteContentPath =VirtualPathUtility.ToAbsolute(contentPath,httpContext.Request.ApplicationPath); returnGenerateClientUrlInternal(httpContext, absoluteContentPath); } // we only want to manipulate thepath if URL rewriting is active for this request, else we risk breaking thegenerated URL bool wasRequestRewritten =_urlRewriterHelper.WasRequestRewritten(httpContext); if (!wasRequestRewritten) { return contentPath; } // Since the rawUrl represents whatthe user sees in his browser, it is what we want to use as the base // of our absolute paths. Forexample, consider mysite.example.com/foo, which is internally // rewritten tocontent.example.com/mysite/foo. When we want to generate a link to ~/bar, wewant to // base it from / instead of /foo,otherwise the user ends up seeing mysite.example.com/foo/bar, // which is incorrect. string relativeUrlToDestination =MakeRelative(httpContext.Request.Path, contentPath); string absoluteUrlToDestination =MakeAbsolute(httpContext.Request.RawUrl, relativeUrlToDestination); return absoluteUrlToDestination; }
代码段 6
相关文章推荐
- ASP.NET MVC 开源项目 收集
- 开源 ASP.NET MVC 1.0 项目
- 一起谈.NET技术,ASP.NET MVC 3 Beta新特性以及.Net开源的趋势----最新译文
- [ASP.NET MVC 3 系列] ASP.NET MVC 3 Beta新特性以及.Net开源的趋势----最新译文
- 推荐一款asp.net-MVC开源框架,完全开源免费使用
- asp.net mvc相关开源项目推荐
- asp.net mvc相关开源项目推荐
- Asp.net MVC 2.0 + Unity 2.0(IoC) + EF4.0 实例:RoRoWoBlog 开源项目框架代码
- 【转载】使用Json比用string返回数据更友好,也更面向对象一些 |Asp.net MVC 2.0 + Unity 2.0(IoC) + EF4.0 实例:RoRoWoBlog 开源项目框架代码
- 开源 Asp.net mvc 用户中心开发计划
- asp.net mvc 1.0 开源
- 看一下基于ASP.NET MVC的开源社区项目Orchard
- asp.net mvc相关开源项目
- vici 开源asp.net mvc支持asp.net2.0II6.0下部署 实例下载地址
- ASP.NET MVC学习资料 新增几个开源项目
- ASP.NET MVC 2的代码以MS-PL协议开源发布
- [转]asp.net mvc相关开源项目推荐
- ASP.NET MVC 开源项目Kigg解读(1)
- (转)看了一些ASP.NET MVC开源项目后的一些想法,关于ASP.NET MVC+Repository+Service架构的一些思考
- 我要学ASP.NET MVC 3.0(十九): MVC 3.0 实例之使用开源控件实现表格排序和分页