1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.Collections.Generic;
\r
16 using System.Diagnostics.CodeAnalysis;
\r
17 using System.Globalization;
\r
21 using System.Web.Mvc.Resources;
\r
22 using System.Web.Routing;
\r
24 [SuppressMessage("Microsoft.Security", "CA2112:SecuredTypesShouldNotExposeFields",
\r
25 Justification = "Public fields for CSS names do not contain secure information.")]
\r
26 public class HtmlHelper {
\r
28 private delegate string HtmlEncoder(object value);
\r
29 private static readonly HtmlEncoder _htmlEncoder = GetHtmlEncoder();
\r
31 private static string _idAttributeDotReplacement;
\r
33 public static readonly string ValidationInputCssClassName = "input-validation-error";
\r
34 public static readonly string ValidationInputValidCssClassName = "input-validation-valid";
\r
35 public static readonly string ValidationMessageCssClassName = "field-validation-error";
\r
36 public static readonly string ValidationMessageValidCssClassName = "field-validation-valid";
\r
37 public static readonly string ValidationSummaryCssClassName = "validation-summary-errors";
\r
38 public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid";
\r
40 private AntiForgeryDataSerializer _serializer;
\r
42 public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)
\r
43 : this(viewContext, viewDataContainer, RouteTable.Routes) {
\r
46 public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection) {
\r
47 if (viewContext == null) {
\r
48 throw new ArgumentNullException("viewContext");
\r
50 if (viewDataContainer == null) {
\r
51 throw new ArgumentNullException("viewDataContainer");
\r
53 if (routeCollection == null) {
\r
54 throw new ArgumentNullException("routeCollection");
\r
56 ViewContext = viewContext;
\r
57 ViewDataContainer = viewDataContainer;
\r
58 RouteCollection = routeCollection;
\r
61 public static string IdAttributeDotReplacement {
\r
63 if (String.IsNullOrEmpty(_idAttributeDotReplacement)) {
\r
64 _idAttributeDotReplacement = "_";
\r
66 return _idAttributeDotReplacement;
\r
69 _idAttributeDotReplacement = value;
\r
73 public RouteCollection RouteCollection {
\r
78 internal AntiForgeryDataSerializer Serializer {
\r
80 if (_serializer == null) {
\r
81 _serializer = new AntiForgeryDataSerializer();
\r
86 _serializer = value;
\r
90 public ViewContext ViewContext {
\r
95 public ViewDataDictionary ViewData {
\r
97 return ViewDataContainer.ViewData;
\r
101 public IViewDataContainer ViewDataContainer {
\r
106 public MvcHtmlString AntiForgeryToken() {
\r
107 return AntiForgeryToken(null /* salt */);
\r
110 public MvcHtmlString AntiForgeryToken(string salt) {
\r
111 return AntiForgeryToken(salt, null /* domain */, null /* path */);
\r
114 public MvcHtmlString AntiForgeryToken(string salt, string domain, string path) {
\r
115 string formValue = GetAntiForgeryTokenAndSetCookie(salt, domain, path);
\r
116 string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
\r
118 TagBuilder builder = new TagBuilder("input");
\r
119 builder.Attributes["type"] = "hidden";
\r
120 builder.Attributes["name"] = fieldName;
\r
121 builder.Attributes["value"] = formValue;
\r
122 return builder.ToMvcHtmlString(TagRenderMode.SelfClosing);
\r
125 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
\r
126 Justification = "For consistency, all helpers are instance methods.")]
\r
127 public string AttributeEncode(string value) {
\r
128 return (!String.IsNullOrEmpty(value)) ? HttpUtility.HtmlAttributeEncode(value) : String.Empty;
\r
131 public string AttributeEncode(object value) {
\r
132 return AttributeEncode(Convert.ToString(value, CultureInfo.InvariantCulture));
\r
135 public void EnableClientValidation() {
\r
136 ViewContext.ClientValidationEnabled = true;
\r
139 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
\r
140 Justification = "For consistency, all helpers are instance methods.")]
\r
141 public string Encode(string value) {
\r
142 return (!String.IsNullOrEmpty(value)) ? HttpUtility.HtmlEncode(value) : String.Empty;
\r
145 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
\r
146 Justification = "For consistency, all helpers are instance methods.")]
\r
147 public string Encode(object value) {
\r
148 return _htmlEncoder(value);
\r
151 // method used if HttpUtility.HtmlEncode(object) method does not exist
\r
152 private static string EncodeLegacy(object value) {
\r
153 string stringVal = Convert.ToString(value, CultureInfo.CurrentCulture);
\r
154 return (!String.IsNullOrEmpty(stringVal)) ? HttpUtility.HtmlEncode(stringVal) : String.Empty;
\r
157 internal string EvalString(string key) {
\r
158 return Convert.ToString(ViewData.Eval(key), CultureInfo.CurrentCulture);
\r
161 internal bool EvalBoolean(string key) {
\r
162 return Convert.ToBoolean(ViewData.Eval(key), CultureInfo.InvariantCulture);
\r
165 internal static IView FindPartialView(ViewContext viewContext, string partialViewName, ViewEngineCollection viewEngineCollection) {
\r
166 ViewEngineResult result = viewEngineCollection.FindPartialView(viewContext, partialViewName);
\r
167 if (result.View != null) {
\r
168 return result.View;
\r
171 StringBuilder locationsText = new StringBuilder();
\r
172 foreach (string location in result.SearchedLocations) {
\r
173 locationsText.AppendLine();
\r
174 locationsText.Append(location);
\r
177 throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
\r
178 MvcResources.Common_PartialViewNotFound, partialViewName, locationsText));
\r
181 public static string GenerateIdFromName(string name) {
\r
182 return GenerateIdFromName(name, IdAttributeDotReplacement);
\r
185 public static string GenerateIdFromName(string name, string idAttributeDotReplacement) {
\r
186 if (name == null) {
\r
187 throw new ArgumentNullException("name");
\r
189 if (idAttributeDotReplacement == null) {
\r
190 throw new ArgumentNullException("idAttributeDotReplacement");
\r
193 return name.Replace(".", idAttributeDotReplacement);
\r
196 public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {
\r
197 return GenerateLink(requestContext, routeCollection, linkText, routeName, actionName, controllerName, null/* protocol */, null/* hostName */, null/* fragment */, routeValues, htmlAttributes);
\r
200 public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {
\r
201 return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, true /* includeImplicitMvcValues */);
\r
204 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) {
\r
205 string url = UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, routeCollection, requestContext, includeImplicitMvcValues);
\r
206 TagBuilder tagBuilder = new TagBuilder("a") {
\r
207 InnerHtml = (!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : String.Empty
\r
209 tagBuilder.MergeAttributes(htmlAttributes);
\r
210 tagBuilder.MergeAttribute("href", url);
\r
211 return tagBuilder.ToString(TagRenderMode.Normal);
\r
214 public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {
\r
215 return GenerateRouteLink(requestContext, routeCollection, linkText, routeName, null/* protocol */, null/* hostName */, null/* fragment */, routeValues, htmlAttributes);
\r
218 public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {
\r
219 return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, null /* actionName */, null /* controllerName */, protocol, hostName, fragment, routeValues, htmlAttributes, false /* includeImplicitMvcValues */);
\r
222 private string GetAntiForgeryTokenAndSetCookie(string salt, string domain, string path) {
\r
223 string cookieName = AntiForgeryData.GetAntiForgeryTokenName(ViewContext.HttpContext.Request.ApplicationPath);
\r
225 AntiForgeryData cookieToken;
\r
226 HttpCookie cookie = ViewContext.HttpContext.Request.Cookies[cookieName];
\r
227 if (cookie != null) {
\r
228 cookieToken = Serializer.Deserialize(cookie.Value);
\r
231 cookieToken = AntiForgeryData.NewToken();
\r
232 string cookieValue = Serializer.Serialize(cookieToken);
\r
234 HttpCookie newCookie = new HttpCookie(cookieName, cookieValue) { HttpOnly = true, Domain = domain };
\r
235 if (!String.IsNullOrEmpty(path)) {
\r
236 newCookie.Path = path;
\r
238 ViewContext.HttpContext.Response.Cookies.Set(newCookie);
\r
241 AntiForgeryData formToken = new AntiForgeryData(cookieToken) {
\r
243 Username = AntiForgeryData.GetUsername(ViewContext.HttpContext.User)
\r
245 string formValue = Serializer.Serialize(formToken);
\r
249 public static string GetFormMethodString(FormMethod method) {
\r
251 case FormMethod.Get:
\r
253 case FormMethod.Post:
\r
260 // selects the v3.5 (legacy) or v4 HTML encoder
\r
261 private static HtmlEncoder GetHtmlEncoder() {
\r
262 return TypeHelpers.CreateDelegate<HtmlEncoder>(TypeHelpers.SystemWebAssembly, "System.Web.HttpUtility", "HtmlEncode", null)
\r
266 public static string GetInputTypeString(InputType inputType) {
\r
267 switch (inputType) {
\r
268 case InputType.CheckBox:
\r
270 case InputType.Hidden:
\r
272 case InputType.Password:
\r
274 case InputType.Radio:
\r
276 case InputType.Text:
\r
283 internal object GetModelStateValue(string key, Type destinationType) {
\r
284 ModelState modelState;
\r
285 if (ViewData.ModelState.TryGetValue(key, out modelState)) {
\r
286 if (modelState.Value != null) {
\r
287 return modelState.Value.ConvertTo(destinationType, null /* culture */);
\r
293 public MvcHtmlString HttpMethodOverride(HttpVerbs httpVerb) {
\r
295 switch (httpVerb) {
\r
296 case HttpVerbs.Delete:
\r
297 httpMethod = "DELETE";
\r
299 case HttpVerbs.Head:
\r
300 httpMethod = "HEAD";
\r
302 case HttpVerbs.Put:
\r
303 httpMethod = "PUT";
\r
306 throw new ArgumentException(MvcResources.HtmlHelper_InvalidHttpVerb, "httpVerb");
\r
309 return HttpMethodOverride(httpMethod);
\r
312 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
\r
313 Justification = "For consistency, all helpers are instance methods.")]
\r
314 public MvcHtmlString HttpMethodOverride(string httpMethod) {
\r
315 if (String.IsNullOrEmpty(httpMethod)) {
\r
316 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "httpMethod");
\r
318 if (String.Equals(httpMethod, "GET", StringComparison.OrdinalIgnoreCase) ||
\r
319 String.Equals(httpMethod, "POST", StringComparison.OrdinalIgnoreCase)) {
\r
320 throw new ArgumentException(MvcResources.HtmlHelper_InvalidHttpMethod, "httpMethod");
\r
323 TagBuilder tagBuilder = new TagBuilder("input");
\r
324 tagBuilder.Attributes["type"] = "hidden";
\r
325 tagBuilder.Attributes["name"] = HttpRequestExtensions.XHttpMethodOverrideKey;
\r
326 tagBuilder.Attributes["value"] = httpMethod;
\r
328 return tagBuilder.ToMvcHtmlString(TagRenderMode.SelfClosing);
\r
331 internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, TextWriter writer, ViewEngineCollection viewEngineCollection) {
\r
332 if (String.IsNullOrEmpty(partialViewName)) {
\r
333 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
\r
336 ViewDataDictionary newViewData = null;
\r
338 if (model == null) {
\r
339 if (viewData == null) {
\r
340 newViewData = new ViewDataDictionary(ViewData);
\r
343 newViewData = new ViewDataDictionary(viewData);
\r
347 if (viewData == null) {
\r
348 newViewData = new ViewDataDictionary(model);
\r
351 newViewData = new ViewDataDictionary(viewData) { Model = model };
\r
355 ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View, newViewData, ViewContext.TempData, writer);
\r
356 IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection);
\r
357 view.Render(newViewContext, writer);
\r