diff --git a/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs b/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs index 14ae5b2db41e02ca0d4a841f1ad31fc970c51ca3..f3915ed44e14f256cea81e6f9a947760d013d1a4 100644 --- a/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs +++ b/src/Identity/testassets/Identity.DefaultUI.WebSite/StartupBase.cs @@ -50,8 +50,7 @@ namespace Identity.DefaultUI.WebSite .AddRoles<IdentityRole>() .AddEntityFrameworkStores<TContext>(); - services.AddMvc() - .AddNewtonsoftJson(); + services.AddMvc(); services.AddSingleton<IFileVersionProvider, FileVersionProvider>(); } diff --git a/src/Mvc/Mvc.NewtonsoftJson/test/BsonTempDataSerializerTest.cs b/src/Mvc/Mvc.NewtonsoftJson/test/BsonTempDataSerializerTest.cs index a2438b1b8b18d875a2ee7c2fc12cea12721d2fdf..5bfe813d196e19ac090c986bd5689fd3e35f475d 100644 --- a/src/Mvc/Mvc.NewtonsoftJson/test/BsonTempDataSerializerTest.cs +++ b/src/Mvc/Mvc.NewtonsoftJson/test/BsonTempDataSerializerTest.cs @@ -235,6 +235,33 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson Assert.Equal(value.ToString(), roundTripValue); } + [Fact] + public void RoundTripTest_ListOfDateTime() + { + // Arrange + var key = "test-key"; + var dateTime = new DateTime(2007, 1, 1); + var testProvider = GetTempDataSerializer(); + var value = new List<DateTime> + { + dateTime, + dateTime.AddDays(3), + }; + + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var bytes = testProvider.Serialize(input); + var values = testProvider.Deserialize(bytes); + + // Assert + var roundTripValue = Assert.IsType<DateTime[]>(values[key]); + Assert.Equal(value, roundTripValue); + } + private class TestItem { public int DummyInt { get; set; } diff --git a/src/Mvc/Mvc.ViewFeatures/src/Infrastructure/DefaultTempDataSerializer.cs b/src/Mvc/Mvc.ViewFeatures/src/Infrastructure/DefaultTempDataSerializer.cs index 27b30c9dc6d9d24d9acbbf04c26170b18fc4dbe3..a67670e595cb188f739e4d7cd91dae52bf7eb46a 100644 --- a/src/Mvc/Mvc.ViewFeatures/src/Infrastructure/DefaultTempDataSerializer.cs +++ b/src/Mvc/Mvc.ViewFeatures/src/Infrastructure/DefaultTempDataSerializer.cs @@ -63,6 +63,14 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure deserializedValue = null; break; + case JsonValueType.Array: + deserializedValue = DeserializeArray(item.Value); + break; + + case JsonValueType.Object: + deserializedValue = DeserializeDictionaryEntry(item.Value); + break; + default: throw new InvalidOperationException(Resources.FormatTempData_CannotDeserializeType(item.Value.Type)); } @@ -73,6 +81,53 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure return deserialized; } + private static object DeserializeArray(in JsonElement arrayElement) + { + if (arrayElement.GetArrayLength() == 0) + { + // We have to infer the type of the array by inspecting it's elements. + // If there's nothing to inspect, return a null value since we do not know + // what type the user code is expecting. + return null; + } + + if (arrayElement[0].Type == JsonValueType.String) + { + var array = new List<string>(); + + foreach (var item in arrayElement.EnumerateArray()) + { + array.Add(item.GetString()); + } + + return array.ToArray(); + } + else if (arrayElement[0].Type == JsonValueType.Number) + { + var array = new List<int>(); + + foreach (var item in arrayElement.EnumerateArray()) + { + array.Add(item.GetInt32()); + } + + return array.ToArray(); + } + + throw new InvalidOperationException(Resources.FormatTempData_CannotDeserializeType(arrayElement.Type)); + } + + private static object DeserializeDictionaryEntry(in JsonElement objectElement) + { + var dictionary = new Dictionary<string, string>(StringComparer.Ordinal); + foreach (var item in objectElement.EnumerateObject()) + { + dictionary[item.Name] = item.Value.GetString(); + } + + return dictionary; + } + public override byte[] Serialize(IDictionary<string, object> values) { if (values == null || values.Count == 0) @@ -126,6 +181,33 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure case Guid guid: writer.WriteString(key, guid); break; + + case ICollection<int> intCollection: + writer.WriteStartArray(key); + foreach (var element in intCollection) + { + writer.WriteNumberValue(element); + } + writer.WriteEndArray(); + break; + + case ICollection<string> stringCollection: + writer.WriteStartArray(key); + foreach (var element in stringCollection) + { + writer.WriteStringValue(element); + } + writer.WriteEndArray(); + break; + + case IDictionary<string, string> dictionary: + writer.WriteStartObject(key); + foreach (var element in dictionary) + { + writer.WriteString(element.Key, element.Value); + } + writer.WriteEndObject(); + break; } } writer.WriteEndObject(); @@ -150,7 +232,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure type == typeof(string) || type == typeof(bool) || type == typeof(DateTime) || - type == typeof(Guid); + type == typeof(Guid) || + typeof(ICollection<int>).IsAssignableFrom(type) || + typeof(ICollection<string>).IsAssignableFrom(type) || + typeof(IDictionary<string, string>).IsAssignableFrom(type); } } } diff --git a/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/DefaultTempDataSerializerTest.cs b/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/DefaultTempDataSerializerTest.cs index 982e9fc9f1871c6e9db4998d294b9aee74fabe49..22f2185fd1867ec704a1922f10cc16f952f6d309 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/DefaultTempDataSerializerTest.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/DefaultTempDataSerializerTest.cs @@ -34,5 +34,26 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure var roundTripValue = Assert.IsType<string>(values[key]); Assert.Equal(value.ToString("r"), roundTripValue); } + + [Fact] + public override void RoundTripTest_DictionaryOfInt() + { + // Arrange + var key = "test-key"; + var testProvider = GetTempDataSerializer(); + var value = new Dictionary<string, int> + { + { "Key1", 7 }, + { "Key2", 24 }, + }; + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var ex = Assert.Throws<InvalidOperationException>(() => testProvider.Serialize(input)); + Assert.Equal($"The '{testProvider.GetType()}' cannot serialize an object of type '{value.GetType()}'.", ex.Message); + } } } diff --git a/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/TempDataSerializerTestBase.cs b/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/TempDataSerializerTestBase.cs index 38a540f8e7ed180b792a43954fa9a6e5fd183da7..93fb4df0e2665f960703c57c6dc2ecce7b4aa2d9 100644 --- a/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/TempDataSerializerTestBase.cs +++ b/src/Mvc/Mvc.ViewFeatures/test/Infrastructure/TempDataSerializerTestBase.cs @@ -239,6 +239,119 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Infrastructure Assert.Equal(value, roundTripValue); } + [Fact] + public void RoundTripTest_CollectionOfInts() + { + // Arrange + var key = "test-key"; + var testProvider = GetTempDataSerializer(); + var value = new[] { 1, 2, 4, 3 }; + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var bytes = testProvider.Serialize(input); + var values = testProvider.Deserialize(bytes); + + // Assert + var roundTripValue = Assert.IsType<int[]>(values[key]); + Assert.Equal(value, roundTripValue); + } + + [Fact] + public void RoundTripTest_ArrayOfStringss() + { + // Arrange + var key = "test-key"; + var testProvider = GetTempDataSerializer(); + var value = new[] { "Hello", "world" }; + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var bytes = testProvider.Serialize(input); + var values = testProvider.Deserialize(bytes); + + // Assert + var roundTripValue = Assert.IsType<string[]>(values[key]); + Assert.Equal(value, roundTripValue); + } + + [Fact] + public void RoundTripTest_ListOfStringss() + { + // Arrange + var key = "test-key"; + var testProvider = GetTempDataSerializer(); + var value = new List<string> { "Hello", "world" }; + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var bytes = testProvider.Serialize(input); + var values = testProvider.Deserialize(bytes); + + // Assert + var roundTripValue = Assert.IsType<string[]>(values[key]); + Assert.Equal(value, roundTripValue); + } + + [Fact] + public void RoundTripTest_DictionaryOfString() + { + // Arrange + var key = "test-key"; + var testProvider = GetTempDataSerializer(); + var value = new Dictionary<string, string> + { + { "Key1", "Value1" }, + { "Key2", "Value2" }, + }; + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var bytes = testProvider.Serialize(input); + var values = testProvider.Deserialize(bytes); + + // Assert + var roundTripValue = Assert.IsType<Dictionary<string, string>>(values[key]); + Assert.Equal(value, roundTripValue); + } + + [Fact] + public virtual void RoundTripTest_DictionaryOfInt() + { + // Arrange + var key = "test-key"; + var testProvider = GetTempDataSerializer(); + var value = new Dictionary<string, int> + { + { "Key1", 7 }, + { "Key2", 24 }, + }; + var input = new Dictionary<string, object> + { + { key, value } + }; + + // Act + var bytes = testProvider.Serialize(input); + var values = testProvider.Deserialize(bytes); + + // Assert + var roundTripValue = Assert.IsType<Dictionary<string, int>>(values[key]); + Assert.Equal(value, roundTripValue); + } + protected abstract TempDataSerializer GetTempDataSerializer(); } } diff --git a/src/Mvc/MvcNoDeps.slnf b/src/Mvc/MvcNoDeps.slnf new file mode 100644 index 0000000000000000000000000000000000000000..f67bdb6d53a898a62656b220650b7a71d39d92c8 --- /dev/null +++ b/src/Mvc/MvcNoDeps.slnf @@ -0,0 +1,73 @@ +{ + "solution": { + "path": "Mvc.sln", + "projects": [ + "test\\WebSites\\BasicWebSite\\BasicWebSite.csproj", + "test\\WebSites\\RoutingWebSite\\Mvc.RoutingWebSite.csproj", + "test\\WebSites\\RazorWebSite\\RazorWebSite.csproj", + "test\\WebSites\\FormatterWebSite\\FormatterWebSite.csproj", + "test\\WebSites\\ApiExplorerWebSite\\ApiExplorerWebSite.csproj", + "test\\WebSites\\VersioningWebSite\\VersioningWebSite.csproj", + "test\\WebSites\\TagHelpersWebSite\\TagHelpersWebSite.csproj", + "test\\WebSites\\FilesWebSite\\FilesWebSite.csproj", + "test\\WebSites\\ApplicationModelWebSite\\ApplicationModelWebSite.csproj", + "test\\WebSites\\HtmlGenerationWebSite\\HtmlGenerationWebSite.csproj", + "test\\WebSites\\ErrorPageMiddlewareWebSite\\ErrorPageMiddlewareWebSite.csproj", + "test\\WebSites\\XmlFormattersWebSite\\XmlFormattersWebSite.csproj", + "test\\WebSites\\ControllersFromServicesWebSite\\ControllersFromServicesWebSite.csproj", + "test\\WebSites\\ControllersFromServicesClassLibrary\\ControllersFromServicesClassLibrary.csproj", + "test\\WebSites\\CorsWebSite\\CorsWebSite.csproj", + "samples\\MvcSandbox\\MvcSandbox.csproj", + "test\\WebSites\\SimpleWebSite\\SimpleWebSite.csproj", + "test\\WebSites\\SecurityWebSite\\SecurityWebSite.csproj", + "test\\WebSites\\RazorPagesWebSite\\RazorPagesWebSite.csproj", + "benchmarks\\Microsoft.AspNetCore.Mvc.Performance\\Microsoft.AspNetCore.Mvc.Performance.csproj", + "test\\WebSites\\RazorBuildWebSite\\RazorBuildWebSite.csproj", + "test\\WebSites\\RazorBuildWebSite.Views\\RazorBuildWebSite.Views.csproj", + "Mvc.Analyzers\\src\\Microsoft.AspNetCore.Mvc.Analyzers.csproj", + "Mvc.Analyzers\\test\\Mvc.Analyzers.Test.csproj", + "test\\WebSites\\RazorPagesClassLibrary\\RazorPagesClassLibrary.csproj", + "shared\\Mvc.Views.TestCommon\\Microsoft.AspNetCore.Mvc.Views.TestCommon.csproj", + "Mvc.Api.Analyzers\\test\\Mvc.Api.Analyzers.Test.csproj", + "Mvc.Api.Analyzers\\src\\Microsoft.AspNetCore.Mvc.Api.Analyzers.csproj", + "test\\WebSites\\GenericHostWebSite\\GenericHostWebSite.csproj", + "Mvc\\src\\Microsoft.AspNetCore.Mvc.csproj", + "Mvc\\test\\Microsoft.AspNetCore.Mvc.Test.csproj", + "Mvc.Abstractions\\src\\Microsoft.AspNetCore.Mvc.Abstractions.csproj", + "Mvc.Abstractions\\test\\Microsoft.AspNetCore.Mvc.Abstractions.Test.csproj", + "Mvc.ApiExplorer\\src\\Microsoft.AspNetCore.Mvc.ApiExplorer.csproj", + "Mvc.ApiExplorer\\test\\Microsoft.AspNetCore.Mvc.ApiExplorer.Test.csproj", + "Mvc.Core\\src\\Microsoft.AspNetCore.Mvc.Core.csproj", + "Mvc.Core\\test\\Microsoft.AspNetCore.Mvc.Core.Test.csproj", + "Mvc.Cors\\src\\Microsoft.AspNetCore.Mvc.Cors.csproj", + "Mvc.Cors\\test\\Microsoft.AspNetCore.Mvc.Cors.Test.csproj", + "Mvc.DataAnnotations\\src\\Microsoft.AspNetCore.Mvc.DataAnnotations.csproj", + "Mvc.DataAnnotations\\test\\Microsoft.AspNetCore.Mvc.DataAnnotations.Test.csproj", + "Mvc.Formatters.Json\\src\\Microsoft.AspNetCore.Mvc.Formatters.Json.csproj", + "Mvc.Formatters.Xml\\src\\Microsoft.AspNetCore.Mvc.Formatters.Xml.csproj", + "Mvc.Formatters.Xml\\test\\Microsoft.AspNetCore.Mvc.Formatters.Xml.Test.csproj", + "Mvc.Localization\\src\\Microsoft.AspNetCore.Mvc.Localization.csproj", + "Mvc.Localization\\test\\Microsoft.AspNetCore.Mvc.Localization.Test.csproj", + "Mvc.Razor\\src\\Microsoft.AspNetCore.Mvc.Razor.csproj", + "Mvc.Razor\\test\\Microsoft.AspNetCore.Mvc.Razor.Test.csproj", + "Mvc.RazorPages\\src\\Microsoft.AspNetCore.Mvc.RazorPages.csproj", + "Mvc.RazorPages\\test\\Microsoft.AspNetCore.Mvc.RazorPages.Test.csproj", + "Mvc.TagHelpers\\src\\Microsoft.AspNetCore.Mvc.TagHelpers.csproj", + "Mvc.TagHelpers\\test\\Microsoft.AspNetCore.Mvc.TagHelpers.Test.csproj", + "Mvc.ViewFeatures\\src\\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj", + "Mvc.ViewFeatures\\test\\Microsoft.AspNetCore.Mvc.ViewFeatures.Test.csproj", + "test\\Mvc.FunctionalTests\\Microsoft.AspNetCore.Mvc.FunctionalTests.csproj", + "test\\Mvc.IntegrationTests\\Microsoft.AspNetCore.Mvc.IntegrationTests.csproj", + "shared\\Mvc.TestDiagnosticListener\\Microsoft.AspNetCore.Mvc.TestDiagnosticListener.csproj", + "Mvc.Testing\\src\\Microsoft.AspNetCore.Mvc.Testing.csproj", + "shared\\Mvc.Core.TestCommon\\Microsoft.AspNetCore.Mvc.Core.TestCommon.csproj", + "Mvc.NewtonsoftJson\\src\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.csproj", + "Mvc.NewtonsoftJson\\test\\Microsoft.AspNetCore.Mvc.NewtonsoftJson.Test.csproj", + "Mvc.Razor.RuntimeCompilation\\src\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.csproj", + "Mvc.Razor.RuntimeCompilation\\test\\Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation.Test.csproj", + "test\\WebSites\\RazorBuildWebSite.PrecompiledViews\\RazorBuildWebSite.PrecompiledViews.csproj", + "Mvc.Components.Prerendering\\src\\Microsoft.AspNetCore.Mvc.Components.Prerendering.csproj", + "Mvc.Components.Prerendering\\test\\Microsoft.AspNetCore.Mvc.Components.Prerendering.Test.csproj", + ] + } +}