diff --git a/samples/MvcSample.Web/HomeController.cs b/samples/MvcSample.Web/HomeController.cs
index 6bf0088cd8..07f1863756 100644
--- a/samples/MvcSample.Web/HomeController.cs
+++ b/samples/MvcSample.Web/HomeController.cs
@@ -17,6 +17,11 @@ namespace MvcSample.Web
return View("MyView", CreateUser());
}
+ public IActionResult NullUser()
+ {
+ return View();
+ }
+
public ActionResult ValidationSummary()
{
ModelState.AddModelError("something", "Something happened, show up in validation summary.");
diff --git a/samples/MvcSample.Web/Views/Home/NullUser.cshtml b/samples/MvcSample.Web/Views/Home/NullUser.cshtml
new file mode 100644
index 0000000000..fdd8a4d8ca
--- /dev/null
+++ b/samples/MvcSample.Web/Views/Home/NullUser.cshtml
@@ -0,0 +1,42 @@
+@*
+ For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
+*@
+@{
+ // ViewBag.Title = "Home Page";
+}
+
+@using MvcSample.Web.Models
+@model User
+
+
+
+ EditorForModel:
+ @Html.EditorForModel()
+
+
+ Editor of empty string:
+ @Html.Editor("")
+
+
+ EditorFor of identity expression:
+ @Html.EditorFor(m => m)
+
+
+
+ DisplayForModel:
+ '@Html.DisplayForModel()'
+
+
+
+ Display:
+ for name '@Html.Display("Name")'
+ and alive '@Html.Display("Alive")'
+
+
+
+ Editor:
+ for name @Html.Editor("Name")
+ alive @Html.Editor("Alive")
+ and alive expression @Html.EditorFor(m => m.Alive)
+
+
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs b/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs
index 6b940b6e94..eca162da51 100644
--- a/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs
@@ -33,7 +33,8 @@ namespace Microsoft.AspNet.Mvc
}
///
- /// copy constructor for use when model type does not change.
+ /// copy constructor for use when model type does not change or caller will
+ /// immediately set the property.
///
public ViewDataDictionary([NotNull] ViewDataDictionary source)
: this(source, source.Model)
@@ -50,9 +51,15 @@ namespace Microsoft.AspNet.Mvc
new CopyOnWriteDictionary(source, StringComparer.OrdinalIgnoreCase),
new TemplateInfo(source.TemplateInfo))
{
- _modelMetadata = source.ModelMetadata;
- // If we're constructing a derived ViewDataDictionary (or any other value type),
- // SetModel will throw if we try to set it to null. We should not throw in that case.
+ // Avoid copying information about the object type. To do so when model==null would confuse the
+ // ViewDataDictionary.ModelMetadata getter.
+ if (source.ModelMetadata?.ModelType != typeof(object))
+ {
+ _modelMetadata = source.ModelMetadata;
+ }
+
+ // If we're constructing a derived ViewDataDictionary where TModel is a non-Nullable value type,
+ // SetModel will throw if we try to call it with null. We should not throw in that case.
if (model != null)
{
SetModel(model);
diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs
index c60429e34d..9d0df4a6ad 100644
--- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs
+++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using Microsoft.AspNet.FileSystems;
using Microsoft.CodeAnalysis;
@@ -174,7 +175,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
{
var metadata = _metadataFileCache.GetOrAdd(path, _ =>
{
- return AssemblyMetadata.CreateFromStream(File.OpenRead(path));
+ using (var stream = File.OpenRead(path))
+ {
+ var moduleMetadata = ModuleMetadata.CreateFromStream(stream, PEStreamOptions.PrefetchMetadata);
+ return AssemblyMetadata.Create(moduleMetadata);
+ }
});
return metadata.GetReference();
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs
index 7223b235bd..c7472c4fd1 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/ViewDataDictionaryTest.cs
@@ -159,6 +159,87 @@ namespace Microsoft.AspNet.Mvc.Core
Assert.IsType>(viewData.Data);
}
+ [Theory]
+ [InlineData(typeof(int))]
+ [InlineData(typeof(string))]
+ [InlineData(typeof(IEnumerable))]
+ [InlineData(typeof(List))]
+ [InlineData(typeof(string[]))]
+ [InlineData(typeof(Dictionary))]
+ public void CopyConstructors_CopyModelMetadata(Type type)
+ {
+ // Arrange
+ var metadataProvider = new EmptyModelMetadataProvider();
+ var metadata = metadataProvider.GetMetadataForType(() => null, type);
+ var source = new ViewDataDictionary(metadataProvider)
+ {
+ ModelMetadata = metadata,
+ };
+
+ // Act
+ var viewData1 = new ViewDataDictionary(source);
+ var viewData2 = new ViewDataDictionary(source, model: null);
+
+ // Assert
+ Assert.Same(metadata, viewData1.ModelMetadata);
+ Assert.Same(metadata, viewData2.ModelMetadata);
+ }
+
+ [Fact]
+ public void CopyConstructors_IgnoreModelMetadata_IfForTypeObject()
+ {
+ // Arrange
+ var metadataProvider = new EmptyModelMetadataProvider();
+ var metadata = metadataProvider.GetMetadataForType(() => null, typeof(object));
+ var source = new ViewDataDictionary(metadataProvider)
+ {
+ ModelMetadata = metadata,
+ };
+
+ // Act
+ var viewData1 = new ViewDataDictionary(source);
+ var viewData2 = new ViewDataDictionary(source, model: null);
+
+ // Assert
+ Assert.Null(viewData1.ModelMetadata);
+ Assert.Null(viewData2.ModelMetadata);
+ }
+
+ [Theory]
+ [InlineData(typeof(int), "test string", typeof(string))]
+ [InlineData(typeof(string), 23, typeof(int))]
+ [InlineData(typeof(IEnumerable), new[] { "1", "2", "3", }, typeof(object[]))]
+ [InlineData(typeof(List), new[] { 1, 2, 3, }, typeof(object[]))]
+ public void CopyConstructors_OverrideSourceMetadata_IfModelNonNull(
+ Type sourceType,
+ object instance,
+ Type expectedType)
+ {
+ // Arrange
+ var metadataProvider = new EmptyModelMetadataProvider();
+ var metadata = metadataProvider.GetMetadataForType(() => null, sourceType);
+ var source = new ViewDataDictionary(metadataProvider)
+ {
+ ModelMetadata = metadata,
+ };
+
+ // Act
+ var viewData1 = new ViewDataDictionary(source)
+ {
+ Model = instance,
+ };
+ var viewData2 = new ViewDataDictionary(source, model: instance);
+
+ // Assert
+ Assert.NotNull(viewData1.ModelMetadata);
+ Assert.Equal(expectedType, viewData1.ModelMetadata.ModelType);
+ Assert.Equal(expectedType, viewData1.ModelMetadata.RealModelType);
+
+ Assert.NotNull(viewData2.ModelMetadata);
+ Assert.Equal(expectedType, viewData2.ModelMetadata.ModelType);
+ Assert.Equal(expectedType, viewData2.ModelMetadata.RealModelType);
+ }
+
public static TheoryData