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 HtmlHelper<TModel> Html { get; set; }
|
||||
public IHtmlHelper<TModel> Html { get; set; }
|
||||
|
||||
public override Task RenderAsync([NotNull] ViewContext context)
|
||||
{
|
||||
|
|
@ -46,7 +46,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
|
||||
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
|
||||
{
|
||||
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 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 ValidationSummaryValidCssClassName = "validation-summary-valid";
|
||||
|
||||
public HtmlHelper([NotNull] HttpContext httpContext, ViewDataDictionary viewData)
|
||||
{
|
||||
HttpContext = httpContext;
|
||||
ViewData = viewData;
|
||||
private ViewContext _viewContext;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HtmlHelper"/> class.
|
||||
/// </summary>
|
||||
public HtmlHelper()
|
||||
{
|
||||
// Underscores are fine characters in id's.
|
||||
IdAttributeDotReplacement = "_";
|
||||
}
|
||||
|
|
@ -30,10 +35,37 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
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
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
get
|
||||
{
|
||||
return ViewContext.ViewData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -71,6 +103,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
return result;
|
||||
}
|
||||
|
||||
public virtual void Contextualize([NotNull] ViewContext viewContext)
|
||||
{
|
||||
ViewContext = viewContext;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")]
|
||||
public string Encode(string value)
|
||||
{
|
||||
|
|
@ -88,6 +125,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
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)
|
||||
{
|
||||
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.")]
|
||||
public HtmlString Raw(string 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.")]
|
||||
public HtmlString Raw(object value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,18 +1,40 @@
|
|||
using Microsoft.AspNet.Abstractions;
|
||||
using System;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
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)
|
||||
: base(httpContext, viewData)
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// The partial view '{0}' was not found or no view engine supports the searched locations. The following locations were searched:{1}
|
||||
/// </summary>
|
||||
|
|
@ -59,7 +91,23 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
/// <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>
|
||||
internal static string ViewData_ModelCannotBeNull
|
||||
{
|
||||
|
|
@ -67,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
/// <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>
|
||||
internal static string FormatViewData_ModelCannotBeNull(object p0)
|
||||
{
|
||||
|
|
@ -75,7 +123,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
/// <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>
|
||||
internal static string ViewData_WrongTModelType
|
||||
{
|
||||
|
|
@ -83,7 +131,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
/// <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>
|
||||
internal static string FormatViewData_WrongTModelType(object p0, object p1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -120,12 +120,21 @@
|
|||
<data name="ArgumentNullOrEmpty" xml:space="preserve">
|
||||
<value>The argument '{0}' is null or empty.</value>
|
||||
</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">
|
||||
<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 name="DynamicViewData_ViewDataNull" xml:space="preserve">
|
||||
<value>ViewData value must not be null.</value>
|
||||
</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">
|
||||
<value>The model item passed is null, but this ViewDataDictionary instance requires a non-null model item of type '{0}'.</value>
|
||||
</data>
|
||||
|
|
|
|||
|
|
@ -88,7 +88,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
typeof(NestedProviderManagerAsync<>),
|
||||
implementationInstance: null,
|
||||
lifecycle: LifecycleKind.Transient);
|
||||
|
||||
|
||||
yield return
|
||||
describe.Describe(
|
||||
typeof(IHtmlHelper<>),
|
||||
typeof(HtmlHelper<>),
|
||||
implementationInstance: null,
|
||||
lifecycle: LifecycleKind.Transient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue