Add JsonExtensionData to ProblemDetails
Fixes https://github.com/aspnet/AspNetCore/issues/6202
This commit is contained in:
parent
b31bdd4373
commit
bed3542a9b
|
|
@ -59,7 +59,12 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||||
var writeStream = GetWriteStream(httpContext, selectedEncoding);
|
var writeStream = GetWriteStream(httpContext, selectedEncoding);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await JsonSerializer.WriteAsync(writeStream, context.Object, context.ObjectType, SerializerOptions);
|
// context.ObjectType reflects the declared model type when specified.
|
||||||
|
// For polymorphic scenarios where the user declares a return type, but returns a derived type,
|
||||||
|
// we want to serialize all the properties on the derived type. This keeps parity with
|
||||||
|
// the behavior you get when the user does not declare the return type and with Json.Net at least at the top level.
|
||||||
|
var objectType = context.Object?.GetType() ?? context.ObjectType;
|
||||||
|
await JsonSerializer.WriteAsync(writeStream, context.Object, objectType, SerializerOptions);
|
||||||
await writeStream.FlushAsync();
|
await writeStream.FlushAsync();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc
|
namespace Microsoft.AspNetCore.Mvc
|
||||||
{
|
{
|
||||||
|
|
@ -52,6 +53,7 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// The round-tripping behavior for <see cref="Extensions"/> is determined by the implementation of the Input \ Output formatters.
|
/// The round-tripping behavior for <see cref="Extensions"/> is determined by the implementation of the Input \ Output formatters.
|
||||||
/// In particular, complex types or collection types may not round-trip to the original type when using the built-in JSON or XML formatters.
|
/// In particular, complex types or collection types may not round-trip to the original type when using the built-in JSON or XML formatters.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
|
[JsonExtensionData]
|
||||||
public IDictionary<string, object> Extensions { get; } = new Dictionary<string, object>(StringComparer.Ordinal);
|
public IDictionary<string, object> Extensions { get; } = new Dictionary<string, object>(StringComparer.Ordinal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|
@ -17,24 +16,21 @@ using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
{
|
{
|
||||||
public class ApiBehaviorTest : IClassFixture<MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting>>
|
public abstract class ApiBehaviorTestBase<TStartup> : IClassFixture<MvcTestFixture<TStartup>> where TStartup : class
|
||||||
{
|
{
|
||||||
public ApiBehaviorTest(MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting> fixture)
|
protected ApiBehaviorTestBase(MvcTestFixture<TStartup> fixture)
|
||||||
{
|
{
|
||||||
Client = fixture.CreateDefaultClient();
|
var factory = fixture.Factories.FirstOrDefault() ?? fixture.WithWebHostBuilder(ConfigureWebHostBuilder);
|
||||||
|
Client = factory.CreateDefaultClient();
|
||||||
var factory = fixture.WithWebHostBuilder(ConfigureWebHostBuilder);
|
|
||||||
CustomInvalidModelStateClient = factory.CreateDefaultClient();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureWebHostBuilder(IWebHostBuilder builder) =>
|
private static void ConfigureWebHostBuilder(IWebHostBuilder builder) =>
|
||||||
builder.UseStartup<BasicWebSite.StartupWithCustomInvalidModelStateFactory>();
|
builder.UseStartup<TStartup>();
|
||||||
|
|
||||||
public HttpClient Client { get; }
|
public HttpClient Client { get; }
|
||||||
public HttpClient CustomInvalidModelStateClient { get; }
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ActionsReturnBadRequest_WhenModelStateIsInvalid()
|
public virtual async Task ActionsReturnBadRequest_WhenModelStateIsInvalid()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
using (new ActivityReplacer())
|
using (new ActivityReplacer())
|
||||||
|
|
@ -122,34 +118,6 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
Assert.Equal("Unsupported Media Type", problemDetails.Title);
|
Assert.Equal("Unsupported Media Type", problemDetails.Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async Task ActionsReturnBadRequest_UsesProblemDescriptionProviderAndApiConventionsToConfigureErrorResponse()
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var contactModel = new Contact
|
|
||||||
{
|
|
||||||
Name = "Abc",
|
|
||||||
City = "Redmond",
|
|
||||||
State = "WA",
|
|
||||||
Zip = "Invalid",
|
|
||||||
};
|
|
||||||
var expected = new Dictionary<string, string[]>
|
|
||||||
{
|
|
||||||
{"Name", new[] {"The field Name must be a string with a minimum length of 5 and a maximum length of 30."}},
|
|
||||||
{"Zip", new[] { @"The field Zip must match the regular expression '\d{5}'."}}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var response = await CustomInvalidModelStateClient.PostAsJsonAsync("/contact/PostWithVnd", contactModel);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await response.AssertStatusCodeAsync(HttpStatusCode.BadRequest);
|
|
||||||
Assert.Equal("application/vnd.error+json", response.Content.Headers.ContentType.MediaType);
|
|
||||||
var content = await response.Content.ReadAsStringAsync();
|
|
||||||
var actual = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(content);
|
|
||||||
Assert.Equal(expected, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public Task ActionsWithApiBehavior_InferFromBodyParameters()
|
public Task ActionsWithApiBehavior_InferFromBodyParameters()
|
||||||
=> ActionsWithApiBehaviorInferFromBodyParameters("ActionWithInferredFromBodyParameter");
|
=> ActionsWithApiBehaviorInferFromBodyParameters("ActionWithInferredFromBodyParameter");
|
||||||
|
|
@ -171,7 +139,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.PostAsJsonAsync($"/contact/{action}", input);
|
var response = await Client.PostAsJsonAsync($"/contact/{action}", input);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
var result = JsonConvert.DeserializeObject<Contact>(await response.Content.ReadAsStringAsync());
|
var result = JsonConvert.DeserializeObject<Contact>(await response.Content.ReadAsStringAsync());
|
||||||
Assert.Equal(input.ContactId, result.ContactId);
|
Assert.Equal(input.ContactId, result.ContactId);
|
||||||
Assert.Equal(input.Name, result.Name);
|
Assert.Equal(input.Name, result.Name);
|
||||||
|
|
@ -188,7 +156,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.PostAsync(url, new StringContent(string.Empty));
|
var response = await Client.PostAsync(url, new StringContent(string.Empty));
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
var result = JsonConvert.DeserializeObject<Contact>(await response.Content.ReadAsStringAsync());
|
var result = JsonConvert.DeserializeObject<Contact>(await response.Content.ReadAsStringAsync());
|
||||||
Assert.Equal(id, result.ContactId);
|
Assert.Equal(id, result.ContactId);
|
||||||
Assert.Equal(name, result.Name);
|
Assert.Equal(name, result.Name);
|
||||||
|
|
@ -208,7 +176,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.GetAsync(url);
|
var response = await Client.GetAsync(url);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
|
|
||||||
var result = await response.Content.ReadAsAsync<Contact>();
|
var result = await response.Content.ReadAsAsync<Contact>();
|
||||||
Assert.Equal(id, result.ContactId);
|
Assert.Equal(id, result.ContactId);
|
||||||
|
|
@ -229,7 +197,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.GetAsync(url);
|
var response = await Client.GetAsync(url);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
|
|
||||||
var result = await response.Content.ReadAsAsync<Contact>();
|
var result = await response.Content.ReadAsAsync<Contact>();
|
||||||
Assert.Equal(id, result.ContactId);
|
Assert.Equal(id, result.ContactId);
|
||||||
|
|
@ -247,7 +215,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.GetAsync("/contact/ActionWithInferredModelBinderType?foo=Hello!");
|
var response = await Client.GetAsync("/contact/ActionWithInferredModelBinderType?foo=Hello!");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
var result = await response.Content.ReadAsStringAsync();
|
var result = await response.Content.ReadAsStringAsync();
|
||||||
Assert.Equal(expected, result);
|
Assert.Equal(expected, result);
|
||||||
}
|
}
|
||||||
|
|
@ -262,13 +230,13 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
var response = await Client.GetAsync("/contact/ActionWithInferredModelBinderTypeWithExplicitModelName?bar=Hello!");
|
var response = await Client.GetAsync("/contact/ActionWithInferredModelBinderTypeWithExplicitModelName?bar=Hello!");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
await response.AssertStatusCodeAsync(HttpStatusCode.OK);
|
||||||
var result = await response.Content.ReadAsStringAsync();
|
var result = await response.Content.ReadAsStringAsync();
|
||||||
Assert.Equal(expected, result);
|
Assert.Equal(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ClientErrorResultFilterExecutesForStatusCodeResults()
|
public virtual async Task ClientErrorResultFilterExecutesForStatusCodeResults()
|
||||||
{
|
{
|
||||||
using (new ActivityReplacer())
|
using (new ActivityReplacer())
|
||||||
{
|
{
|
||||||
|
|
@ -296,7 +264,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SerializingProblemDetails_IgnoresNullValuedProperties()
|
public virtual async Task SerializingProblemDetails_IgnoresNullValuedProperties()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new[] { "status", "title", "traceId", "type" };
|
var expected = new[] { "status", "title", "traceId", "type" };
|
||||||
|
|
@ -314,7 +282,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SerializingProblemDetails_WithAllValuesSpecified()
|
public virtual async Task SerializingProblemDetails_WithAllValuesSpecified()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var expected = new[] { "detail", "instance", "status", "title", "tracking-id", "type" };
|
var expected = new[] { "detail", "instance", "status", "title", "tracking-id", "type" };
|
||||||
|
|
@ -330,7 +298,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SerializingValidationProblemDetails_WithExtensionData()
|
public virtual async Task SerializingValidationProblemDetails_WithExtensionData()
|
||||||
{
|
{
|
||||||
// Act
|
// Act
|
||||||
var response = await Client.GetAsync("/contact/ActionReturningValidationProblemDetails");
|
var response = await Client.GetAsync("/contact/ActionReturningValidationProblemDetails");
|
||||||
|
|
@ -364,4 +332,132 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ApiBehaviorTest : ApiBehaviorTestBase<BasicWebSite.StartupWithSystemTextJson>
|
||||||
|
{
|
||||||
|
public ApiBehaviorTest(MvcTestFixture<BasicWebSite.StartupWithSystemTextJson> fixture)
|
||||||
|
: base(fixture)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public override async Task ActionsReturnBadRequest_WhenModelStateIsInvalid()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using var _ = new ActivityReplacer();
|
||||||
|
|
||||||
|
var contactModel = new Contact
|
||||||
|
{
|
||||||
|
Name = "Abc",
|
||||||
|
City = "Redmond",
|
||||||
|
State = "WA",
|
||||||
|
Zip = "Invalid",
|
||||||
|
};
|
||||||
|
var contactString = JsonConvert.SerializeObject(contactModel);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await Client.PostAsJsonAsync("/contact", contactModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await response.AssertStatusCodeAsync(HttpStatusCode.BadRequest);
|
||||||
|
Assert.Equal("application/problem+json", response.Content.Headers.ContentType.MediaType);
|
||||||
|
var problemDetails = JsonConvert.DeserializeObject<ValidationProblemDetails>(
|
||||||
|
await response.Content.ReadAsStringAsync(),
|
||||||
|
new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
Converters = { new ValidationProblemDetailsConverter() }
|
||||||
|
});
|
||||||
|
Assert.Collection(
|
||||||
|
problemDetails.Errors.OrderBy(kvp => kvp.Key),
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("Name", kvp.Key);
|
||||||
|
var error = Assert.Single(kvp.Value);
|
||||||
|
Assert.Equal("The field Name must be a string with a minimum length of 5 and a maximum length of 30.", error);
|
||||||
|
},
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("Zip", kvp.Key);
|
||||||
|
var error = Assert.Single(kvp.Value);
|
||||||
|
Assert.Equal("The field Zip must match the regular expression '\\d{5}'.", error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.Collection(
|
||||||
|
problemDetails.Extensions,
|
||||||
|
kvp =>
|
||||||
|
{
|
||||||
|
Assert.Equal("extensions", kvp.Key);
|
||||||
|
var jObject = Assert.IsType<JObject>(kvp.Value);
|
||||||
|
Assert.Equal("traceId", Assert.Single(jObject.Properties()).Name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "https://github.com/dotnet/corefx/issues/38769")]
|
||||||
|
public override Task ClientErrorResultFilterExecutesForStatusCodeResults()
|
||||||
|
{
|
||||||
|
return base.ClientErrorResultFilterExecutesForStatusCodeResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "https://github.com/dotnet/corefx/issues/38769")]
|
||||||
|
public override Task SerializingProblemDetails_IgnoresNullValuedProperties()
|
||||||
|
{
|
||||||
|
return base.SerializingProblemDetails_IgnoresNullValuedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "https://github.com/dotnet/corefx/issues/38769")]
|
||||||
|
public override Task SerializingProblemDetails_WithAllValuesSpecified()
|
||||||
|
{
|
||||||
|
return base.SerializingProblemDetails_WithAllValuesSpecified();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact(Skip = "https://github.com/dotnet/corefx/issues/38769")]
|
||||||
|
public override Task SerializingValidationProblemDetails_WithExtensionData()
|
||||||
|
{
|
||||||
|
return base.SerializingValidationProblemDetails_WithExtensionData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ApiBehaviorTestNewtonsoftJson : ApiBehaviorTestBase<BasicWebSite.StartupWithoutEndpointRouting>
|
||||||
|
{
|
||||||
|
public ApiBehaviorTestNewtonsoftJson(MvcTestFixture<BasicWebSite.StartupWithoutEndpointRouting> fixture)
|
||||||
|
: base(fixture)
|
||||||
|
{
|
||||||
|
var factory = fixture.WithWebHostBuilder(ConfigureWebHostBuilder);
|
||||||
|
CustomInvalidModelStateClient = factory.CreateDefaultClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigureWebHostBuilder(IWebHostBuilder builder) =>
|
||||||
|
builder.UseStartup<BasicWebSite.StartupWithCustomInvalidModelStateFactory>();
|
||||||
|
|
||||||
|
public HttpClient CustomInvalidModelStateClient { get; }
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ActionsReturnBadRequest_UsesProblemDescriptionProviderAndApiConventionsToConfigureErrorResponse()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var contactModel = new Contact
|
||||||
|
{
|
||||||
|
Name = "Abc",
|
||||||
|
City = "Redmond",
|
||||||
|
State = "WA",
|
||||||
|
Zip = "Invalid",
|
||||||
|
};
|
||||||
|
var expected = new Dictionary<string, string[]>
|
||||||
|
{
|
||||||
|
{"Name", new[] {"The field Name must be a string with a minimum length of 5 and a maximum length of 30."}},
|
||||||
|
{"Zip", new[] { @"The field Zip must match the regular expression '\d{5}'."}}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await CustomInvalidModelStateClient.PostAsJsonAsync("/contact/PostWithVnd", contactModel);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await response.AssertStatusCodeAsync(HttpStatusCode.BadRequest);
|
||||||
|
Assert.Equal("application/vnd.error+json", response.Content.Headers.ContentType.MediaType);
|
||||||
|
var content = await response.Content.ReadAsStringAsync();
|
||||||
|
var actual = JsonConvert.DeserializeObject<Dictionary<string, string[]>>(content);
|
||||||
|
Assert.Equal(expected, actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FormatterWebSite.Controllers;
|
using FormatterWebSite.Controllers;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
|
|
@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(Skip = "Dictionary serialization does not correctly work.")]
|
[Fact(Skip = "https://github.com/aspnet/AspNetCore/issues/11459")]
|
||||||
public override Task SerializableErrorIsReturnedInExpectedFormat() => base.SerializableErrorIsReturnedInExpectedFormat();
|
public override Task SerializableErrorIsReturnedInExpectedFormat() => base.SerializableErrorIsReturnedInExpectedFormat();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -29,13 +30,27 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
Assert.Equal("\"Hello Mr. \\ud83e\\udd8a\"", await response.Content.ReadAsStringAsync());
|
Assert.Equal("\"Hello Mr. \\ud83e\\udd8a\"", await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact(Skip = "Dictionary serialization does not correctly work.")]
|
[Fact]
|
||||||
public override Task Formatting_DictionaryType() => base.Formatting_DictionaryType();
|
public override Task Formatting_DictionaryType() => base.Formatting_DictionaryType();
|
||||||
|
|
||||||
[Fact(Skip = "Dictionary serialization does not correctly work.")]
|
[Fact]
|
||||||
public override Task Formatting_ProblemDetails() => base.Formatting_ProblemDetails();
|
public override async Task Formatting_ProblemDetails()
|
||||||
|
{
|
||||||
|
using var _ = new ActivityReplacer();
|
||||||
|
|
||||||
[Fact(Skip = "https://github.com/dotnet/corefx/issues/36166")]
|
// Act
|
||||||
|
var response = await Client.GetAsync($"/JsonOutputFormatter/{nameof(JsonOutputFormatterController.ProblemDetailsResult)}");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
await response.AssertStatusCodeAsync(HttpStatusCode.NotFound);
|
||||||
|
|
||||||
|
var obj = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||||
|
Assert.Equal("https://tools.ietf.org/html/rfc7231#section-6.5.4", obj.Value<string>("type"));
|
||||||
|
Assert.Equal("Not Found", obj.Value<string>("title"));
|
||||||
|
Assert.Equal("404", obj.Value<string>("status"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
public override Task Formatting_PolymorphicModel() => base.Formatting_PolymorphicModel();
|
public override Task Formatting_PolymorphicModel() => base.Formatting_PolymorphicModel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,6 +14,8 @@ namespace BasicWebSite
|
||||||
services
|
services
|
||||||
.AddMvc()
|
.AddMvc()
|
||||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||||
|
|
||||||
|
services.AddSingleton<ContactsRepository>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
public void Configure(IApplicationBuilder app)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue