From b8731621dfa1796de5763aa5c7d82bff9cb06d4b Mon Sep 17 00:00:00 2001 From: dougbu Date: Tue, 15 Apr 2014 15:26:10 -0700 Subject: [PATCH] Add default `Display*()` templates - first get old code in correct spot - then get default templates working in new world - usual things: `[NotNull]`, `var`, internal -> public - provide a `HtmlHelper.GenerateOption()` static method - pass an `ViewDataDictionary` instance to `TemplateRenderer` constructor - run default templates synchronously with an IHtmlHelper - copy over resources - add Microsoft.Data.Entity reference for EntityState type - use default templates in MVC sample - remove most on-disk overrides of the default templates --- samples/MvcSample.Web/MvcSample.Web.kproj | 4 - .../Shared/DisplayTemplates/Boolean.cshtml | 22 -- .../Shared/DisplayTemplates/Decimal.cshtml | 5 +- .../Shared/DisplayTemplates/Int32.cshtml | 1 - .../Shared/DisplayTemplates/String.cshtml | 1 - .../Views/Shared/DisplayTemplates/User.cshtml | 5 - .../MvcSample.Web/Views/Shared/MyView.cshtml | 19 +- .../Microsoft.AspNet.Mvc.Core.kproj | 1 + .../Properties/Resources.Designer.cs | 64 ++++ .../Rendering/Html/DefaultDisplayTemplates.cs | 289 ++++++++++++++++++ .../Rendering/Html/HtmlHelper.cs | 10 +- .../Rendering/Html/TemplateBuilder.cs | 4 +- .../Rendering/Html/TemplateRenderer.cs | 57 +++- src/Microsoft.AspNet.Mvc.Core/Resources.resx | 14 +- 14 files changed, 431 insertions(+), 65 deletions(-) delete mode 100644 samples/MvcSample.Web/Views/Shared/DisplayTemplates/Boolean.cshtml delete mode 100644 samples/MvcSample.Web/Views/Shared/DisplayTemplates/Int32.cshtml delete mode 100644 samples/MvcSample.Web/Views/Shared/DisplayTemplates/String.cshtml delete mode 100644 samples/MvcSample.Web/Views/Shared/DisplayTemplates/User.cshtml create mode 100644 src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs diff --git a/samples/MvcSample.Web/MvcSample.Web.kproj b/samples/MvcSample.Web/MvcSample.Web.kproj index 8581f2626d..ec493b0ca7 100644 --- a/samples/MvcSample.Web/MvcSample.Web.kproj +++ b/samples/MvcSample.Web/MvcSample.Web.kproj @@ -28,11 +28,7 @@ - - - - diff --git a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Boolean.cshtml b/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Boolean.cshtml deleted file mode 100644 index e30d2aa704..0000000000 --- a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Boolean.cshtml +++ /dev/null @@ -1,22 +0,0 @@ -@using System.Globalization - -@functions { - private bool? Value { - get { - if (ViewData.Model == null) { - return null; - } - return Convert.ToBoolean(ViewData.Model, CultureInfo.InvariantCulture); - } - } -} - -@if (ViewData.ModelMetadata.IsNullableValueType) { - -} else { - -} \ No newline at end of file diff --git a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Decimal.cshtml b/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Decimal.cshtml index 9647bd7baa..8b2d217cef 100644 --- a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Decimal.cshtml +++ b/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Decimal.cshtml @@ -1,4 +1,5 @@ -@using System.Globalization +@* Override default Decimal template to display value in bold. *@ +@using System.Globalization @functions { private object FormattedValue { @@ -10,4 +11,4 @@ } } } -@Html.Encode(FormattedValue) \ No newline at end of file +@Html.Encode(FormattedValue) \ No newline at end of file diff --git a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Int32.cshtml b/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Int32.cshtml deleted file mode 100644 index 54ac8e0909..0000000000 --- a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/Int32.cshtml +++ /dev/null @@ -1 +0,0 @@ -@ViewData.TemplateInfo.FormattedModelValue \ No newline at end of file diff --git a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/String.cshtml b/samples/MvcSample.Web/Views/Shared/DisplayTemplates/String.cshtml deleted file mode 100644 index ae2dc6dec1..0000000000 --- a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/String.cshtml +++ /dev/null @@ -1 +0,0 @@ -@Html.Encode(ViewData.TemplateInfo.FormattedModelValue) \ No newline at end of file diff --git a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/User.cshtml b/samples/MvcSample.Web/Views/Shared/DisplayTemplates/User.cshtml deleted file mode 100644 index 5141f4c197..0000000000 --- a/samples/MvcSample.Web/Views/Shared/DisplayTemplates/User.cshtml +++ /dev/null @@ -1,5 +0,0 @@ -@using System.Linq - -

This is the DisplayForModel output. Once default templates are implemented this should go away.

-

User Name: @ViewData.Model.Name

-

User Model Metadata Property Count: @ViewData.ModelMetadata.Properties.Count()

\ No newline at end of file diff --git a/samples/MvcSample.Web/Views/Shared/MyView.cshtml b/samples/MvcSample.Web/Views/Shared/MyView.cshtml index 24c5019118..1cde356de0 100644 --- a/samples/MvcSample.Web/Views/Shared/MyView.cshtml +++ b/samples/MvcSample.Web/Views/Shared/MyView.cshtml @@ -85,7 +85,7 @@
-
+
@@ -145,15 +145,11 @@
- -
+
@await Component.InvokeAsync("Tags", 15)

'@ViewBag.Title' should match page heading (still)

-
- -
-
+
@using (Html.BeginForm(controllerName: "Home", actionName: "Hello", method: FormMethod.Post)) { @Html.HiddenFor(m => m.Age) @@ -273,10 +269,7 @@ @{ Html.EndForm(); }
-
- -
-
+
@@ -328,7 +321,7 @@
-
+
@@ -381,7 +374,7 @@
-
+
@Html.DisplayForModel()
diff --git a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj index 0488dfdae9..5c6d047837 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj +++ b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj @@ -152,6 +152,7 @@ + diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs index 7674c4ac67..90da94d467 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs @@ -362,6 +362,54 @@ namespace Microsoft.AspNet.Mvc.Core return string.Format(CultureInfo.CurrentCulture, GetString("Common_ValueNotValidForProperty"), p0); } + /// + /// False + /// + internal static string Common_TriState_False + { + get { return GetString("Common_TriState_False"); } + } + + /// + /// False + /// + internal static string FormatCommon_TriState_False() + { + return GetString("Common_TriState_False"); + } + + /// + /// Not Set + /// + internal static string Common_TriState_NotSet + { + get { return GetString("Common_TriState_NotSet"); } + } + + /// + /// Not Set + /// + internal static string FormatCommon_TriState_NotSet() + { + return GetString("Common_TriState_NotSet"); + } + + /// + /// True + /// + internal static string Common_TriState_True + { + get { return GetString("Common_TriState_True"); } + } + + /// + /// True + /// + internal static string FormatCommon_TriState_True() + { + return GetString("Common_TriState_True"); + } + /// /// ViewData value must not be null. /// @@ -474,6 +522,22 @@ namespace Microsoft.AspNet.Mvc.Core return string.Format(CultureInfo.CurrentCulture, GetString("HtmlHelper_WrongSelectDataType"), p0, p1, p2); } + /// + /// The '{0}' template was used with an object of type '{1}', which does not implement '{2}'. + /// + internal static string Templates_TypeMustImplementIEnumerable + { + get { return GetString("Templates_TypeMustImplementIEnumerable"); } + } + + /// + /// The '{0}' template was used with an object of type '{1}', which does not implement '{2}'. + /// + internal static string FormatTemplates_TypeMustImplementIEnumerable(object p0, object p1, object p2) + { + return string.Format(CultureInfo.CurrentCulture, GetString("Templates_TypeMustImplementIEnumerable"), p0, p1, p2); + } + /// /// Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions. /// diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs new file mode 100644 index 0000000000..4d86784918 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using Microsoft.AspNet.DependencyInjection; +using Microsoft.AspNet.Mvc.Core; +using Microsoft.AspNet.Mvc.ModelBinding; + +namespace Microsoft.AspNet.Mvc.Rendering +{ + public static class DefaultDisplayTemplates + { + public static string BooleanTemplate(IHtmlHelper html) + { + bool? value = null; + if (html.ViewData.Model != null) + { + value = Convert.ToBoolean(html.ViewData.Model, CultureInfo.InvariantCulture); + } + + return html.ViewData.ModelMetadata.IsNullableValueType ? + BooleanTemplateDropDownList(html, value) : + BooleanTemplateCheckbox(value ?? false); + } + + private static string BooleanTemplateCheckbox(bool value) + { + var inputTag = new TagBuilder("input"); + inputTag.AddCssClass("check-box"); + inputTag.Attributes["disabled"] = "disabled"; + inputTag.Attributes["type"] = "checkbox"; + if (value) + { + inputTag.Attributes["checked"] = "checked"; + } + + return inputTag.ToString(TagRenderMode.SelfClosing); + } + + private static string BooleanTemplateDropDownList(IHtmlHelper html, bool? value) + { + var selectTag = new TagBuilder("select"); + selectTag.AddCssClass("list-box"); + selectTag.AddCssClass("tri-state"); + selectTag.Attributes["disabled"] = "disabled"; + + var builder = new StringBuilder(); + builder.Append(selectTag.ToString(TagRenderMode.StartTag)); + + foreach (var item in TriStateValues(value)) + { + var encodedText = html.Encode(item.Text); + var option = HtmlHelper.GenerateOption(item, encodedText); + builder.Append(option); + } + + builder.Append(selectTag.ToString(TagRenderMode.EndTag)); + return builder.ToString(); + } + + // Will soon need to be shared with the default editor templates implementations. + internal static List TriStateValues(bool? value) + { + return new List + { + new SelectListItem + { + Text = Resources.Common_TriState_NotSet, + Value = string.Empty, + Selected = !value.HasValue + }, + new SelectListItem + { + Text = Resources.Common_TriState_True, + Value = "true", + Selected = (value == true), + }, + new SelectListItem + { + Text = Resources.Common_TriState_False, + Value = "false", + Selected = (value == false), + }, + }; + } + + public static string CollectionTemplate(IHtmlHelper html) + { + var model = html.ViewData.ModelMetadata.Model; + if (model == null) + { + return string.Empty; + } + + var collection = model as IEnumerable; + if (collection == null) + { + // Only way we could reach here is if user passed templateName: "Collection" to a Display() overload. + throw new InvalidOperationException(Resources.FormatTemplates_TypeMustImplementIEnumerable( + "Collection", model.GetType().FullName, typeof(IEnumerable).FullName)); + } + + var typeInCollection = typeof(string); + var genericEnumerableType = collection.GetType().ExtractGenericInterface(typeof(IEnumerable<>)); + if (genericEnumerableType != null) + { + typeInCollection = genericEnumerableType.GetGenericArguments()[0]; + } + + var typeInCollectionIsNullableValueType = typeInCollection.IsNullableValueType(); + + var oldPrefix = html.ViewData.TemplateInfo.HtmlFieldPrefix; + + try + { + html.ViewData.TemplateInfo.HtmlFieldPrefix = string.Empty; + + var fieldNameBase = oldPrefix; + var result = new StringBuilder(); + + var serviceProvider = html.ViewContext.HttpContext.RequestServices; + var metadataProvider = serviceProvider.GetService(); + var viewEngine = serviceProvider.GetService(); + + var index = 0; + foreach (var item in collection) + { + var itemType = typeInCollection; + if (item != null && !typeInCollectionIsNullableValueType) + { + itemType = item.GetType(); + } + + var metadata = metadataProvider.GetMetadataForType(() => item, itemType); + var fieldName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++); + + var templateBuilder = new TemplateBuilder( + viewEngine, + html.ViewContext, + html.ViewData, + metadata, + htmlFieldName: fieldName, + templateName: null, + readOnly: true, + additionalViewData: null); + + var output = templateBuilder.Build(); + result.Append(output); + } + + return result.ToString(); + } + finally + { + html.ViewData.TemplateInfo.HtmlFieldPrefix = oldPrefix; + } + } + + public static string DecimalTemplate(IHtmlHelper html) + { + if (html.ViewData.TemplateInfo.FormattedModelValue == html.ViewData.ModelMetadata.Model) + { + html.ViewData.TemplateInfo.FormattedModelValue = + string.Format(CultureInfo.CurrentCulture, "{0:0.00}", html.ViewData.ModelMetadata.Model); + } + + return StringTemplate(html); + } + + public static string EmailAddressTemplate(IHtmlHelper html) + { + var uriString = "mailto:" + ((html.ViewData.Model == null) ? string.Empty : html.ViewData.Model.ToString()); + var linkedText = (html.ViewData.TemplateInfo.FormattedModelValue == null) ? + string.Empty : + html.ViewData.TemplateInfo.FormattedModelValue.ToString(); + + return HyperlinkTemplate(uriString, linkedText); + } + + public static string HiddenInputTemplate(IHtmlHelper html) + { + // TODO: add ModelMetadata.HideSurroundingHtml and use here (return string.Empty) + return StringTemplate(html); + } + + public static string HtmlTemplate(IHtmlHelper html) + { + return html.ViewData.TemplateInfo.FormattedModelValue.ToString(); + } + + public static string ObjectTemplate(IHtmlHelper html) + { + var viewData = html.ViewData; + var templateInfo = viewData.TemplateInfo; + var modelMetadata = viewData.ModelMetadata; + var builder = new StringBuilder(); + + if (modelMetadata.Model == null) + { + return modelMetadata.NullDisplayText; + } + + if (templateInfo.TemplateDepth > 1) + { + // TODO: add ModelMetadata.SimpleDisplayText and use here (return SimpleDisplayText) + return modelMetadata.Model.ToString(); + } + + var serviceProvider = html.ViewContext.HttpContext.RequestServices; + var viewEngine = serviceProvider.GetService(); + + foreach (var propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo))) + { + var divTag = new TagBuilder("div"); + + // TODO: add ModelMetadata.HideSurroundingHtml and use here (skip this block) + { + var label = propertyMetadata.GetDisplayName(); + if (!string.IsNullOrEmpty(label)) + { + divTag.SetInnerText(label); + divTag.AddCssClass("display-label"); + builder.AppendLine(divTag.ToString(TagRenderMode.Normal)); + + // Reset divTag for reuse. + divTag.Attributes.Clear(); + } + + divTag.AddCssClass("display-field"); + builder.Append(divTag.ToString(TagRenderMode.StartTag)); + } + + var templateBuilder = new TemplateBuilder( + viewEngine, + html.ViewContext, + html.ViewData, + propertyMetadata, + htmlFieldName: propertyMetadata.PropertyName, + templateName: null, + readOnly: true, + additionalViewData: null); + + builder.Append(templateBuilder.Build()); + + // TODO: add ModelMetadata.HideSurroundingHtml and use here (skip this block) + { + builder.AppendLine(divTag.ToString(TagRenderMode.EndTag)); + } + } + + return builder.ToString(); + } + + private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo) + { + // TODO: add ModelMetadata.ShowForDisplay and include in this calculation (first) + return + !metadata.IsComplexType && + !templateInfo.Visited(metadata); + } + + public static string StringTemplate(IHtmlHelper html) + { + return html.Encode(html.ViewData.TemplateInfo.FormattedModelValue); + } + + public static string UrlTemplate(IHtmlHelper html) + { + var uriString = (html.ViewData.Model == null) ? string.Empty : html.ViewData.Model.ToString(); + var linkedText = (html.ViewData.TemplateInfo.FormattedModelValue == null) ? + string.Empty : + html.ViewData.TemplateInfo.FormattedModelValue.ToString(); + + return HyperlinkTemplate(uriString, linkedText); + } + + // Neither uriString nor linkedText need be encoded prior to calling this method. + private static string HyperlinkTemplate(string uriString, string linkedText) + { + var hyperlinkTag = new TagBuilder("a"); + hyperlinkTag.MergeAttribute("href", uriString); + hyperlinkTag.SetInnerText(linkedText); + + return hyperlinkTag.ToString(TagRenderMode.Normal); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs index b8646ad9b6..9dd50c5bdf 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs @@ -301,7 +301,7 @@ namespace Microsoft.AspNet.Mvc.Rendering ViewContext, ViewData, metadata, - templateName, + htmlFieldName, templateName, readOnly: true, additionalViewData: additionalViewData); @@ -1134,10 +1134,16 @@ namespace Microsoft.AspNet.Mvc.Rendering } private string GenerateOption(SelectListItem item) + { + var encodedText = Encode(item.Text); + return GenerateOption(item, encodedText); + } + + internal static string GenerateOption(SelectListItem item, string encodedText) { var builder = new TagBuilder("option") { - InnerHtml = Encode(item.Text) + InnerHtml = encodedText, }; if (item.Value != null) diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateBuilder.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateBuilder.cs index ab1605cb2e..d534a72ad9 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateBuilder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateBuilder.cs @@ -62,7 +62,7 @@ namespace Microsoft.AspNet.Mvc.Rendering return string.Empty; } - var viewData = new ViewDataDictionary(_viewData) + var viewData = new ViewDataDictionary(_viewData) { Model = _metadata.Model, ModelMetadata = _metadata @@ -86,7 +86,5 @@ namespace Microsoft.AspNet.Mvc.Rendering return templateRenderer.Render(); } - - } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateRenderer.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateRenderer.cs index 6091dbc860..1b966928ea 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateRenderer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/TemplateRenderer.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.Mvc.Core; @@ -15,15 +14,30 @@ namespace Microsoft.AspNet.Mvc.Rendering private static readonly string DisplayTemplateViewPath = "DisplayTemplates"; private static readonly string EditorTemplateViewPath = "EditorTemplates"; + private static readonly Dictionary, string>> _defaultDisplayActions = + new Dictionary, string>>(StringComparer.OrdinalIgnoreCase) + { + { "EmailAddress", DefaultDisplayTemplates.EmailAddressTemplate }, + { "HiddenInput", DefaultDisplayTemplates.HiddenInputTemplate }, + { "Html", DefaultDisplayTemplates.HtmlTemplate }, + { "Text", DefaultDisplayTemplates.StringTemplate }, + { "Url", DefaultDisplayTemplates.UrlTemplate }, + { "Collection", DefaultDisplayTemplates.CollectionTemplate }, + { typeof(bool).Name, DefaultDisplayTemplates.BooleanTemplate }, + { typeof(decimal).Name, DefaultDisplayTemplates.DecimalTemplate }, + { typeof(string).Name, DefaultDisplayTemplates.StringTemplate }, + { typeof(object).Name, DefaultDisplayTemplates.ObjectTemplate }, + }; + private ViewContext _viewContext; - private ViewDataDictionary _viewData; + private ViewDataDictionary _viewData; private IViewEngine _viewEngine; private string _templateName; private bool _readOnly; public TemplateRenderer([NotNull] IViewEngine viewEngine, [NotNull] ViewContext viewContext, - [NotNull] ViewDataDictionary viewData, + [NotNull] ViewDataDictionary viewData, string templateName, bool readOnly) { @@ -61,22 +75,29 @@ namespace Microsoft.AspNet.Mvc.Rendering } } - Func, Task> defaultAction; + Func, string> defaultAction; if (defaultActions.TryGetValue(viewName, out defaultAction)) { - // Right now there's no IhtmlHelper pass in or default templates so this will be - // changed once a decision has been reached. - return defaultAction(null).Result; + return defaultAction(MakeHtmlHelper(_viewContext, _viewData)); } } - throw new InvalidOperationException(Resources.FormatTemplateHelpers_NoTemplate(_viewData.ModelMetadata.RealModelType.FullName)); + throw new InvalidOperationException( + Resources.FormatTemplateHelpers_NoTemplate(_viewData.ModelMetadata.RealModelType.FullName)); } - private Dictionary, Task>> GetDefaultActions() + private Dictionary, string>> GetDefaultActions() { - // TODO: Implement default templates - return new Dictionary, Task>>(StringComparer.OrdinalIgnoreCase); + if (_readOnly) + { + return _defaultDisplayActions; + } + else + { + // TODO: Support Editor() and its default templates. + // (No resource for this message because this line _must_ be very short-lived.) + throw new NotImplementedException("No default editor templates yet"); + } } private IEnumerable GetViewNames() @@ -148,5 +169,19 @@ namespace Microsoft.AspNet.Mvc.Rendering } } } + + private static IHtmlHelper MakeHtmlHelper(ViewContext viewContext, ViewDataDictionary viewData) + { + var newHelper = viewContext.HttpContext.RequestServices.GetService>(); + + var contextable = newHelper as ICanHasViewContext; + if (contextable != null) + { + var newViewContext = new ViewContext(viewContext, viewContext.View, viewData, viewContext.Writer); + contextable.Contextualize(newViewContext); + } + + return newHelper; + } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx index 791f8551f2..5a44abefac 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx @@ -183,6 +183,15 @@ The value '{0}' is invalid. + + False + + + Not Set + + + True + ViewData value must not be null. @@ -204,6 +213,9 @@ The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'. + + The '{0}' template was used with an object of type '{1}', which does not implement '{2}'. + Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions. @@ -231,4 +243,4 @@ The view '{0}' was not found. The following locations were searched:{1}. - \ No newline at end of file +