Inject `HtmlHelper` property into `RazorView<T>`
- add `IHtmlHelper<T>` and `ICanHasViewContext` - adjust `HtmlHelper` and `HtmlHelper<T>` to match - throw if `ViewContext` accessed prior to `Contextualize` call - XML comments (from old world) all around Note - no current need for an `HtmlHelper` copy constructor or `Clone()` method - expect recursion code to get another injected `IHtmlHelper<T>` and then "contextualize" that instance with a new `ViewContext`
This commit is contained in:
parent
94db3c392a
commit
2b70156cf4
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
public ViewDataDictionary<TModel> ViewData { get; private set; }
|
public ViewDataDictionary<TModel> ViewData { get; private set; }
|
||||||
|
|
||||||
public HtmlHelper<TModel> Html { get; set; }
|
public IHtmlHelper<TModel> Html { get; set; }
|
||||||
|
|
||||||
public override Task RenderAsync([NotNull] ViewContext context)
|
public override Task RenderAsync([NotNull] ViewContext context)
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +46,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
private void InitHelpers(ViewContext context)
|
private void InitHelpers(ViewContext context)
|
||||||
{
|
{
|
||||||
Html = new HtmlHelper<TModel>(context.HttpContext, ViewData);
|
Html = context.ServiceProvider.GetService<IHtmlHelper<TModel>>();
|
||||||
|
|
||||||
|
var contextable = Html as ICanHasViewContext;
|
||||||
|
if (contextable != null)
|
||||||
|
{
|
||||||
|
contextable.Contextualize(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ using Microsoft.AspNet.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Rendering
|
namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
{
|
{
|
||||||
public class HtmlHelper
|
/// <summary>
|
||||||
|
/// Default implementation of non-generic portions of <see cref="IHtmlHelper{T}">.
|
||||||
|
/// </summary>
|
||||||
|
public class HtmlHelper : ICanHasViewContext
|
||||||
{
|
{
|
||||||
public static readonly string ValidationInputCssClassName = "input-validation-error";
|
public static readonly string ValidationInputCssClassName = "input-validation-error";
|
||||||
public static readonly string ValidationInputValidCssClassName = "input-validation-valid";
|
public static readonly string ValidationInputValidCssClassName = "input-validation-valid";
|
||||||
|
|
@ -17,11 +20,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
public static readonly string ValidationSummaryCssClassName = "validation-summary-errors";
|
public static readonly string ValidationSummaryCssClassName = "validation-summary-errors";
|
||||||
public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid";
|
public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid";
|
||||||
|
|
||||||
public HtmlHelper([NotNull] HttpContext httpContext, ViewDataDictionary viewData)
|
private ViewContext _viewContext;
|
||||||
{
|
|
||||||
HttpContext = httpContext;
|
|
||||||
ViewData = viewData;
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="HtmlHelper"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public HtmlHelper()
|
||||||
|
{
|
||||||
// Underscores are fine characters in id's.
|
// Underscores are fine characters in id's.
|
||||||
IdAttributeDotReplacement = "_";
|
IdAttributeDotReplacement = "_";
|
||||||
}
|
}
|
||||||
|
|
@ -30,10 +35,37 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
|
|
||||||
public HttpContext HttpContext { get; private set; }
|
public HttpContext HttpContext { get; private set; }
|
||||||
|
|
||||||
|
public ViewContext ViewContext
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_viewContext == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(Resources.HtmlHelper_NotContextualized);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _viewContext;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_viewContext = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public dynamic ViewBag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ViewContext.ViewBag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ViewDataDictionary ViewData
|
public ViewDataDictionary ViewData
|
||||||
{
|
{
|
||||||
get;
|
get
|
||||||
private set;
|
{
|
||||||
|
return ViewContext.ViewData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -71,6 +103,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void Contextualize([NotNull] ViewContext viewContext)
|
||||||
|
{
|
||||||
|
ViewContext = viewContext;
|
||||||
|
}
|
||||||
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
||||||
public string Encode(string value)
|
public string Encode(string value)
|
||||||
{
|
{
|
||||||
|
|
@ -88,6 +125,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
return TagBuilder.CreateSanitizedId(name, IdAttributeDotReplacement);
|
return TagBuilder.CreateSanitizedId(name, IdAttributeDotReplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the HTTP method that handles form input (GET or POST) as a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="method">The HTTP method that handles the form.</param>
|
||||||
|
/// <returns>The form method string, either "get" or "post".</returns>
|
||||||
public static string GetFormMethodString(FormMethod method)
|
public static string GetFormMethodString(FormMethod method)
|
||||||
{
|
{
|
||||||
switch (method)
|
switch (method)
|
||||||
|
|
@ -120,24 +162,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps HTML markup in an IHtmlString, which will enable HTML markup to be
|
|
||||||
/// rendered to the output without getting HTML encoded.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">HTML markup string.</param>
|
|
||||||
/// <returns>An IHtmlString that represents HTML markup.</returns>
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
||||||
public HtmlString Raw(string value)
|
public HtmlString Raw(string value)
|
||||||
{
|
{
|
||||||
return new HtmlString(value);
|
return new HtmlString(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Wraps HTML markup from the string representation of an object in an IHtmlString,
|
|
||||||
/// which will enable HTML markup to be rendered to the output without getting HTML encoded.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">object with string representation as HTML markup</param>
|
|
||||||
/// <returns>An IHtmlString that represents HTML markup.</returns>
|
|
||||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
||||||
public HtmlString Raw(object value)
|
public HtmlString Raw(object value)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,40 @@
|
||||||
using Microsoft.AspNet.Abstractions;
|
using System;
|
||||||
|
using Microsoft.AspNet.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Rendering
|
namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
{
|
{
|
||||||
public class HtmlHelper<TModel> : HtmlHelper
|
public class HtmlHelper<TModel> : HtmlHelper, IHtmlHelper<TModel>
|
||||||
{
|
{
|
||||||
public HtmlHelper([NotNull]HttpContext httpContext, ViewDataDictionary<TModel> viewData)
|
/// <summary>
|
||||||
: base(httpContext, viewData)
|
/// Initializes a new instance of the <see cref="HtmlHelper{TModel}"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public HtmlHelper()
|
||||||
|
: base()
|
||||||
{
|
{
|
||||||
ViewData = viewData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public new ViewDataDictionary<TModel> ViewData
|
/// <inheritdoc />
|
||||||
|
public new ViewDataDictionary<TModel> ViewData { get; private set;}
|
||||||
|
|
||||||
|
public override void Contextualize([NotNull] ViewContext viewContext)
|
||||||
{
|
{
|
||||||
get; private set;
|
if (viewContext.ViewData == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException(Resources.FormatArgumentPropertyNull("ViewData"), "viewContext");
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewData = viewContext.ViewData as ViewDataDictionary<TModel>;
|
||||||
|
if (ViewData == null)
|
||||||
|
{
|
||||||
|
// viewContext may contain a base ViewDataDictionary instance. So complain about that type, not TModel.
|
||||||
|
throw new ArgumentException(Resources.FormatArgumentPropertyUnexpectedType(
|
||||||
|
"ViewData",
|
||||||
|
viewContext.ViewData.GetType().FullName,
|
||||||
|
typeof(ViewDataDictionary<TModel>).FullName),
|
||||||
|
"viewContext");
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Contextualize(viewContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
|
{
|
||||||
|
public interface ICanHasViewContext
|
||||||
|
{
|
||||||
|
void Contextualize([NotNull] ViewContext viewContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="IHtmlHelper"/> for Linq expressions.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TModel">The <see cref="Type"/> of the model.</typeparam>
|
||||||
|
public interface IHtmlHelper<TModel>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the character that replaces periods in the ID attribute of an element.
|
||||||
|
/// </summary>
|
||||||
|
string IdAttributeDotReplacement { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the view bag.
|
||||||
|
/// </summary>
|
||||||
|
dynamic ViewBag { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the context information about the view.
|
||||||
|
/// </summary>
|
||||||
|
ViewContext ViewContext { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current view data.
|
||||||
|
/// </summary>
|
||||||
|
ViewDataDictionary<TModel> ViewData { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the value of the specified object to an HTML-encoded string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The object to encode.</param>
|
||||||
|
/// <returns>The HTML-encoded string.</returns>
|
||||||
|
string Encode(object value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified string to an HTML-encoded string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The string to encode.</param>
|
||||||
|
/// <returns>The HTML-encoded string.</returns>
|
||||||
|
string Encode(string value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an HTML element ID using the specified element name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the HTML element.</param>
|
||||||
|
/// <returns>The ID of the HTML element.</returns>
|
||||||
|
string GenerateIdFromName(string name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps HTML markup in an <see cref="HtmlString"/>, which will enable HTML markup to be
|
||||||
|
/// rendered to the output without getting HTML encoded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">HTML markup string.</param>
|
||||||
|
/// <returns>An <see cref="HtmlString"/> that represents HTML markup.</returns>
|
||||||
|
HtmlString Raw(string value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps HTML markup from the string representation of an object in an <see cref="HtmlString"/>,
|
||||||
|
/// which will enable HTML markup to be rendered to the output without getting HTML encoded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">object with string representation as HTML markup.</param>
|
||||||
|
/// <returns>An <see cref="HtmlString"/> that represents HTML markup.</returns>
|
||||||
|
HtmlString Raw(object value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,38 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentNullOrEmpty"), p0);
|
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentNullOrEmpty"), p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Property '{0}' must not be null.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ArgumentPropertyNull
|
||||||
|
{
|
||||||
|
get { return GetString("ArgumentPropertyNull"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Property '{0}' must not be null.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatArgumentPropertyNull(object p0)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentPropertyNull"), p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Property '{0}' is of type '{1}', but this method requires a value of type '{2}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ArgumentPropertyUnexpectedType
|
||||||
|
{
|
||||||
|
get { return GetString("ArgumentPropertyUnexpectedType"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Property '{0}' is of type '{1}', but this method requires a value of type '{2}'.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatArgumentPropertyUnexpectedType(object p0, object p1, object p2)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.CurrentCulture, GetString("ArgumentPropertyUnexpectedType"), p0, p1, p2);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The partial view '{0}' was not found or no view engine supports the searched locations. The following locations were searched:{1}
|
/// The partial view '{0}' was not found or no view engine supports the searched locations. The following locations were searched:{1}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -59,7 +91,23 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model item passed is null, but this ViewData instance requires a non-null model item of type '{0}'.
|
/// Must call 'Contextualize' method before using this HtmlHelper instance.
|
||||||
|
/// </summary>
|
||||||
|
internal static string HtmlHelper_NotContextualized
|
||||||
|
{
|
||||||
|
get { return GetString("HtmlHelper_NotContextualized"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Must call 'Contextualize' method before using this HtmlHelper instance.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatHtmlHelper_NotContextualized()
|
||||||
|
{
|
||||||
|
return GetString("HtmlHelper_NotContextualized");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The model item passed is null, but this ViewDataDictionary instance requires a non-null model item of type '{0}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ViewData_ModelCannotBeNull
|
internal static string ViewData_ModelCannotBeNull
|
||||||
{
|
{
|
||||||
|
|
@ -67,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model item passed is null, but this ViewData instance requires a non-null model item of type '{0}'.
|
/// The model item passed is null, but this ViewDataDictionary instance requires a non-null model item of type '{0}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatViewData_ModelCannotBeNull(object p0)
|
internal static string FormatViewData_ModelCannotBeNull(object p0)
|
||||||
{
|
{
|
||||||
|
|
@ -75,7 +123,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model item passed into the ViewData is of type '{0}', but this ViewData instance requires a model item of type '{1}'.
|
/// The model item passed into the ViewDataDictionary is of type '{0}', but this ViewDataDictionary instance requires a model item of type '{1}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ViewData_WrongTModelType
|
internal static string ViewData_WrongTModelType
|
||||||
{
|
{
|
||||||
|
|
@ -83,7 +131,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model item passed into the ViewData is of type '{0}', but this ViewData instance requires a model item of type '{1}'.
|
/// The model item passed into the ViewDataDictionary is of type '{0}', but this ViewDataDictionary instance requires a model item of type '{1}'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string FormatViewData_WrongTModelType(object p0, object p1)
|
internal static string FormatViewData_WrongTModelType(object p0, object p1)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -120,12 +120,21 @@
|
||||||
<data name="ArgumentNullOrEmpty" xml:space="preserve">
|
<data name="ArgumentNullOrEmpty" xml:space="preserve">
|
||||||
<value>The argument '{0}' is null or empty.</value>
|
<value>The argument '{0}' is null or empty.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ArgumentPropertyNull" xml:space="preserve">
|
||||||
|
<value>Property '{0}' must not be null.</value>
|
||||||
|
</data>
|
||||||
|
<data name="ArgumentPropertyUnexpectedType" xml:space="preserve">
|
||||||
|
<value>Property '{0}' is of type '{1}', but this method requires a value of type '{2}'.</value>
|
||||||
|
</data>
|
||||||
<data name="Common_PartialViewNotFound" xml:space="preserve">
|
<data name="Common_PartialViewNotFound" xml:space="preserve">
|
||||||
<value>The partial view '{0}' was not found or no view engine supports the searched locations. The following locations were searched:{1}</value>
|
<value>The partial view '{0}' was not found or no view engine supports the searched locations. The following locations were searched:{1}</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DynamicViewData_ViewDataNull" xml:space="preserve">
|
<data name="DynamicViewData_ViewDataNull" xml:space="preserve">
|
||||||
<value>ViewData value must not be null.</value>
|
<value>ViewData value must not be null.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="HtmlHelper_NotContextualized" xml:space="preserve">
|
||||||
|
<value>Must call 'Contextualize' method before using this HtmlHelper instance.</value>
|
||||||
|
</data>
|
||||||
<data name="ViewData_ModelCannotBeNull" xml:space="preserve">
|
<data name="ViewData_ModelCannotBeNull" xml:space="preserve">
|
||||||
<value>The model item passed is null, but this ViewDataDictionary instance requires a non-null model item of type '{0}'.</value>
|
<value>The model item passed is null, but this ViewDataDictionary instance requires a non-null model item of type '{0}'.</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,12 @@ namespace Microsoft.AspNet.Mvc
|
||||||
implementationInstance: null,
|
implementationInstance: null,
|
||||||
lifecycle: LifecycleKind.Transient);
|
lifecycle: LifecycleKind.Transient);
|
||||||
|
|
||||||
|
yield return
|
||||||
|
describe.Describe(
|
||||||
|
typeof(IHtmlHelper<>),
|
||||||
|
typeof(HtmlHelper<>),
|
||||||
|
implementationInstance: null,
|
||||||
|
lifecycle: LifecycleKind.Transient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue