Support a few more complex types with DefaultTempDataSerializer
Fixes https://github.com/aspnet/AspNetCore/issues/9540
This commit is contained in:
parent
117dd8cff4
commit
6c5274a09f
|
|
@ -50,8 +50,7 @@ namespace Identity.DefaultUI.WebSite
|
|||
.AddRoles<IdentityRole>()
|
||||
.AddEntityFrameworkStores<TContext>();
|
||||
|
||||
services.AddMvc()
|
||||
.AddNewtonsoftJson();
|
||||
services.AddMvc();
|
||||
|
||||
services.AddSingleton<IFileVersionProvider, FileVersionProvider>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,6 +235,34 @@ namespace Microsoft.AspNetCore.Mvc.NewtonsoftJson
|
|||
Assert.Equal(value.ToString(), roundTripValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RoundTripTest_ListOfDateTime()
|
||||
{
|
||||
// Documents the behavior of round-tripping a Guid value as a string
|
||||
// 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; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue