Use compat flag to drive XML ProblemDetails formatting
This commit is contained in:
parent
164d14064c
commit
a40c1f2d02
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -14,6 +14,29 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// </summary>
|
||||
public static class MvcXmlMvcBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds configuration of <see cref="MvcXmlOptions"/> for the application.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <param name="setupAction">The <see cref="MvcXmlOptions"/> which need to be configured.</param>
|
||||
public static IMvcBuilder AddXmlOptions(
|
||||
this IMvcBuilder builder,
|
||||
Action<MvcXmlOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (setupAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(setupAction));
|
||||
}
|
||||
|
||||
builder.Services.Configure(setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML DataContractSerializer formatters to MVC.
|
||||
/// </summary>
|
||||
|
|
@ -30,6 +53,31 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML DataContractSerializer formatters to MVC.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <param name="setupAction">The <see cref="MvcXmlOptions"/> which need to be configured.</param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
|
||||
public static IMvcBuilder AddXmlDataContractSerializerFormatters(
|
||||
this IMvcBuilder builder,
|
||||
Action<MvcXmlOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (setupAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(setupAction));
|
||||
}
|
||||
|
||||
AddXmlDataContractSerializerFormatterServices(builder.Services);
|
||||
builder.Services.Configure(setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML Serializer formatters to MVC.
|
||||
/// </summary>
|
||||
|
|
@ -46,18 +94,44 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML Serializer formatters to MVC.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcBuilder"/>.</param>
|
||||
/// <param name="setupAction">The <see cref="MvcXmlOptions"/> which need to be configured.</param>
|
||||
/// <returns>The <see cref="IMvcBuilder"/>.</returns>
|
||||
public static IMvcBuilder AddXmlSerializerFormatters(
|
||||
this IMvcBuilder builder,
|
||||
Action<MvcXmlOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
AddXmlSerializerFormatterServices(builder.Services);
|
||||
builder.Services.Configure(setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal static void AddXmlDataContractSerializerFormatterServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcXmlDataContractSerializerMvcOptionsSetup>());
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal static void AddXmlSerializerFormatterServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcXmlSerializerMvcOptionsSetup>());
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
@ -14,6 +14,30 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
/// </summary>
|
||||
public static class MvcXmlMvcCoreBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds configuration of <see cref="MvcXmlOptions"/> for the application.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
|
||||
/// <param name="setupAction">The <see cref="MvcXmlOptions"/> which need to be configured.</param>
|
||||
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
|
||||
public static IMvcCoreBuilder AddXmlOptions(
|
||||
this IMvcCoreBuilder builder,
|
||||
Action<MvcXmlOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (setupAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(setupAction));
|
||||
}
|
||||
|
||||
builder.Services.Configure(setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML DataContractSerializer formatters to MVC.
|
||||
/// </summary>
|
||||
|
|
@ -30,6 +54,31 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML DataContractSerializer formatters to MVC.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
|
||||
/// <param name="setupAction">The <see cref="MvcXmlOptions"/> which need to be configured.</param>
|
||||
/// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
|
||||
public static IMvcCoreBuilder AddXmlDataContractSerializerFormatters(
|
||||
this IMvcCoreBuilder builder,
|
||||
Action<MvcXmlOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
if (setupAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(setupAction));
|
||||
}
|
||||
|
||||
AddXmlDataContractSerializerFormatterServices(builder.Services);
|
||||
builder.Services.Configure(setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML Serializer formatters to MVC.
|
||||
/// </summary>
|
||||
|
|
@ -46,18 +95,44 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the XML Serializer formatters to MVC.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="IMvcCoreBuilder"/>.</param>
|
||||
/// <param name="setupAction">The <see cref="MvcXmlOptions"/> which need to be configured.</param>
|
||||
/// /// <returns>The <see cref="IMvcCoreBuilder"/>.</returns>
|
||||
public static IMvcCoreBuilder AddXmlSerializerFormatters(
|
||||
this IMvcCoreBuilder builder,
|
||||
Action<MvcXmlOptions> setupAction)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
AddXmlSerializerFormatterServices(builder.Services);
|
||||
builder.Services.Configure(setupAction);
|
||||
return builder;
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal static void AddXmlDataContractSerializerFormatterServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcXmlDataContractSerializerMvcOptionsSetup>());
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlDataContractSerializerMvcOptionsSetup>());
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
||||
}
|
||||
|
||||
// Internal for testing.
|
||||
internal static void AddXmlSerializerFormatterServices(IServiceCollection services)
|
||||
{
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcXmlSerializerMvcOptionsSetup>());
|
||||
ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, XmlSerializerMvcOptionsSetup>());
|
||||
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IPostConfigureOptions<MvcXmlOptions>, MvcXmlOptionsConfigureCompatibilityOptions>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides configuration for XML formatters.
|
||||
/// </summary>
|
||||
public class MvcXmlOptions : IEnumerable<ICompatibilitySwitch>
|
||||
{
|
||||
private readonly CompatibilitySwitch<bool> _allowRfc7807CompliantProblemDetailsFormat;
|
||||
private readonly IReadOnlyList<ICompatibilitySwitch> _switches;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="MvcXmlOptions"/>.
|
||||
/// </summary>
|
||||
public MvcXmlOptions()
|
||||
{
|
||||
_allowRfc7807CompliantProblemDetailsFormat = new CompatibilitySwitch<bool>(nameof(AllowRfc7807CompliantProblemDetailsFormat));
|
||||
|
||||
_switches = new ICompatibilitySwitch[]
|
||||
{
|
||||
_allowRfc7807CompliantProblemDetailsFormat,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value inidicating whether <see cref="ProblemDetails"/> and <see cref="ValidationProblemDetails"/>
|
||||
/// are serialized in a format compliant with the RFC 7807 specification (https://tools.ietf.org/html/rfc7807).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The default value is <see langword="true"/> if the version is
|
||||
/// <see cref="CompatibilityVersion.Version_2_2"/> or later; <see langword="false"/> otherwise.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This property is associated with a compatibility switch and can provide a different behavior depending on
|
||||
/// the configured compatibility version for the application. See <see cref="CompatibilityVersion"/> for
|
||||
/// guidance and examples of setting the application's compatibility version.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Configuring the desired value of the compatibility switch by calling this property's setter will take
|
||||
/// precedence over the value implied by the application's <see cref="CompatibilityVersion"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// lower then this setting will have the value <see langword="false"/> unless explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_2"/> or
|
||||
/// higher then this setting will have the value <see langword="true"/> unless explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool AllowRfc7807CompliantProblemDetailsFormat
|
||||
{
|
||||
get => _allowRfc7807CompliantProblemDetailsFormat.Value;
|
||||
set => _allowRfc7807CompliantProblemDetailsFormat.Value = value;
|
||||
}
|
||||
|
||||
public IEnumerator<ICompatibilitySwitch> GetEnumerator() => _switches.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc
|
||||
{
|
||||
internal sealed class MvcXmlOptionsConfigureCompatibilityOptions : ConfigureCompatibilityOptions<MvcXmlOptions>
|
||||
{
|
||||
public MvcXmlOptionsConfigureCompatibilityOptions(
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<MvcCompatibilityOptions> compatibilityOptions)
|
||||
: base(loggerFactory, compatibilityOptions)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IReadOnlyDictionary<string, object> DefaultValues
|
||||
{
|
||||
get
|
||||
{
|
||||
var values = new Dictionary<string, object>();
|
||||
|
||||
if (Version >= CompatibilityVersion.Version_2_2)
|
||||
{
|
||||
values[nameof(MvcXmlOptions.AllowRfc7807CompliantProblemDetailsFormat)] = true;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper class for <see cref="Mvc.ProblemDetails"/> to enable it to be serialized by the xml formatters.
|
||||
/// </summary>
|
||||
[XmlRoot(nameof(ProblemDetails))]
|
||||
[Obsolete("This type is deprecated and will be removed in a future version")]
|
||||
public class ProblemDetails21Wrapper : IXmlSerializable, IUnwrappable
|
||||
{
|
||||
protected static readonly string EmptyKey = SerializableErrorWrapper.EmptyKey;
|
||||
|
||||
public ProblemDetails21Wrapper()
|
||||
: this(new ProblemDetails())
|
||||
{
|
||||
}
|
||||
|
||||
public ProblemDetails21Wrapper(ProblemDetails problemDetails)
|
||||
{
|
||||
ProblemDetails = problemDetails;
|
||||
}
|
||||
|
||||
internal ProblemDetails ProblemDetails { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public XmlSchema GetSchema() => null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void ReadXml(XmlReader reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reader));
|
||||
}
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return;
|
||||
}
|
||||
|
||||
reader.ReadStartElement();
|
||||
while (reader.NodeType != XmlNodeType.EndElement)
|
||||
{
|
||||
var key = XmlConvert.DecodeName(reader.LocalName);
|
||||
ReadValue(reader, key);
|
||||
|
||||
reader.MoveToContent();
|
||||
}
|
||||
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the value for the specified <paramref name="name"/> from the <paramref name="reader"/>.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <param name="name">The name of the node.</param>
|
||||
protected virtual void ReadValue(XmlReader reader, string name)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reader));
|
||||
}
|
||||
|
||||
var value = reader.ReadInnerXml();
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "Detail":
|
||||
ProblemDetails.Detail = value;
|
||||
break;
|
||||
|
||||
case "Instance":
|
||||
ProblemDetails.Instance = value;
|
||||
break;
|
||||
|
||||
case "Status":
|
||||
ProblemDetails.Status = string.IsNullOrEmpty(value) ?
|
||||
(int?)null :
|
||||
int.Parse(value, CultureInfo.InvariantCulture);
|
||||
break;
|
||||
|
||||
case "Title":
|
||||
ProblemDetails.Title = value;
|
||||
break;
|
||||
|
||||
case "Type":
|
||||
ProblemDetails.Type = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (string.Equals(name, EmptyKey, StringComparison.Ordinal))
|
||||
{
|
||||
name = string.Empty;
|
||||
}
|
||||
|
||||
ProblemDetails.Extensions.Add(name, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void WriteXml(XmlWriter writer)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ProblemDetails.Detail))
|
||||
{
|
||||
writer.WriteElementString(
|
||||
XmlConvert.EncodeLocalName("Detail"),
|
||||
ProblemDetails.Detail);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ProblemDetails.Instance))
|
||||
{
|
||||
writer.WriteElementString(
|
||||
XmlConvert.EncodeLocalName("Instance"),
|
||||
ProblemDetails.Instance);
|
||||
}
|
||||
|
||||
if (ProblemDetails.Status.HasValue)
|
||||
{
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName("Status"));
|
||||
writer.WriteValue(ProblemDetails.Status.Value);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ProblemDetails.Title))
|
||||
{
|
||||
writer.WriteElementString(
|
||||
XmlConvert.EncodeLocalName("Title"),
|
||||
ProblemDetails.Title);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(ProblemDetails.Type))
|
||||
{
|
||||
writer.WriteElementString(
|
||||
XmlConvert.EncodeLocalName("Type"),
|
||||
ProblemDetails.Type);
|
||||
}
|
||||
|
||||
foreach (var keyValuePair in ProblemDetails.Extensions)
|
||||
{
|
||||
var key = keyValuePair.Key;
|
||||
var value = keyValuePair.Value;
|
||||
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
key = EmptyKey;
|
||||
}
|
||||
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName(key));
|
||||
if (value != null)
|
||||
{
|
||||
writer.WriteValue(value);
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
object IUnwrappable.Unwrap(Type declaredType)
|
||||
{
|
||||
if (declaredType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(declaredType));
|
||||
}
|
||||
|
||||
return ProblemDetails;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
internal class ProblemDetailsWrapperProviderFactory : IWrapperProviderFactory
|
||||
{
|
||||
private readonly MvcXmlOptions _options;
|
||||
|
||||
public ProblemDetailsWrapperProviderFactory(MvcXmlOptions options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public IWrapperProvider GetProvider(WrapperProviderContext context)
|
||||
{
|
||||
if (context.DeclaredType == typeof(ProblemDetails))
|
||||
{
|
||||
if (_options.AllowRfc7807CompliantProblemDetailsFormat)
|
||||
{
|
||||
return new WrapperProvider(typeof(ProblemDetailsWrapper), p => new ProblemDetailsWrapper((ProblemDetails)p));
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
return new WrapperProvider(typeof(ProblemDetails21Wrapper), p => new ProblemDetails21Wrapper((ProblemDetails)p));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
}
|
||||
}
|
||||
|
||||
if (context.DeclaredType == typeof(ValidationProblemDetails))
|
||||
{
|
||||
if (_options.AllowRfc7807CompliantProblemDetailsFormat)
|
||||
{
|
||||
return new WrapperProvider(typeof(ValidationProblemDetailsWrapper), p => new ValidationProblemDetailsWrapper((ValidationProblemDetails)p));
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
return new WrapperProvider(typeof(ValidationProblemDetails21Wrapper), p => new ValidationProblemDetails21Wrapper((ValidationProblemDetails)p));
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class WrapperProvider : IWrapperProvider
|
||||
{
|
||||
public WrapperProvider(Type wrappingType, Func<object, object> wrapDelegate)
|
||||
{
|
||||
WrappingType = wrappingType;
|
||||
WrapDelegate = wrapDelegate;
|
||||
}
|
||||
|
||||
public Type WrappingType { get; }
|
||||
|
||||
public Func<object, object> WrapDelegate { get; }
|
||||
|
||||
public object Wrap(object original) => WrapDelegate(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// Wrapper class for <see cref="ValidationProblemDetails"/> to enable it to be serialized by the xml formatters.
|
||||
/// </summary>
|
||||
[XmlRoot(nameof(ValidationProblemDetails))]
|
||||
[Obsolete("This type is deprecated and will be removed in a future version")]
|
||||
public class ValidationProblemDetails21Wrapper : ProblemDetails21Wrapper, IUnwrappable
|
||||
{
|
||||
private static readonly string ErrorKey = "MVC-Errors";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="ValidationProblemDetailsWrapper"/>.
|
||||
/// </summary>
|
||||
public ValidationProblemDetails21Wrapper()
|
||||
: this(new ValidationProblemDetails())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="ValidationProblemDetailsWrapper"/> for the specified
|
||||
/// <paramref name="problemDetails"/>.
|
||||
/// </summary>
|
||||
/// <param name="problemDetails">The <see cref="ProblemDetails"/>.</param>
|
||||
public ValidationProblemDetails21Wrapper(ValidationProblemDetails problemDetails)
|
||||
: base(problemDetails)
|
||||
{
|
||||
ProblemDetails = problemDetails;
|
||||
}
|
||||
|
||||
internal new ValidationProblemDetails ProblemDetails { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void ReadValue(XmlReader reader, string name)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reader));
|
||||
}
|
||||
|
||||
if (string.Equals(name, ErrorKey, StringComparison.Ordinal))
|
||||
{
|
||||
reader.Read();
|
||||
ReadErrorProperty(reader);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.ReadValue(reader, name);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadErrorProperty(XmlReader reader)
|
||||
{
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (reader.NodeType != XmlNodeType.EndElement)
|
||||
{
|
||||
var key = XmlConvert.DecodeName(reader.LocalName);
|
||||
var value = reader.ReadInnerXml();
|
||||
if (string.Equals(EmptyKey, key, StringComparison.Ordinal))
|
||||
{
|
||||
key = string.Empty;
|
||||
}
|
||||
|
||||
ProblemDetails.Errors.Add(key, new[] { value });
|
||||
reader.MoveToContent();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void WriteXml(XmlWriter writer)
|
||||
{
|
||||
if (writer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(writer));
|
||||
}
|
||||
|
||||
base.WriteXml(writer);
|
||||
|
||||
if (ProblemDetails.Errors.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName(ErrorKey));
|
||||
|
||||
foreach (var keyValuePair in ProblemDetails.Errors)
|
||||
{
|
||||
var key = keyValuePair.Key;
|
||||
var value = keyValuePair.Value;
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
key = EmptyKey;
|
||||
}
|
||||
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName(key));
|
||||
if (value != null)
|
||||
{
|
||||
writer.WriteValue(value);
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
object IUnwrappable.Unwrap(Type declaredType)
|
||||
{
|
||||
if (declaredType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(declaredType));
|
||||
}
|
||||
|
||||
return ProblemDetails;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,24 +44,5 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static IList<IWrapperProviderFactory> GetDefaultProviderFactories()
|
||||
{
|
||||
var wrapperProviderFactories = new List<IWrapperProviderFactory>();
|
||||
|
||||
wrapperProviderFactories.Add(new SerializableErrorWrapperProviderFactory());
|
||||
|
||||
wrapperProviderFactories.Add(new WrapperProviderFactory(
|
||||
typeof(ProblemDetails),
|
||||
typeof(ProblemDetailsWrapper),
|
||||
value => new ProblemDetailsWrapper((ProblemDetails)value)));
|
||||
|
||||
wrapperProviderFactories.Add(new WrapperProviderFactory(
|
||||
typeof(ValidationProblemDetails),
|
||||
typeof(ValidationProblemDetailsWrapper),
|
||||
value => new ValidationProblemDetailsWrapper((ValidationProblemDetails)value)));
|
||||
|
||||
return wrapperProviderFactories;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
internal class WrapperProviderFactory : IWrapperProviderFactory
|
||||
{
|
||||
public WrapperProviderFactory(Type declaredType, Type wrappingType, Func<object, object> wrapper)
|
||||
{
|
||||
DeclaredType = declaredType;
|
||||
WrappingType = wrappingType;
|
||||
Wrapper = wrapper;
|
||||
}
|
||||
|
||||
public Type DeclaredType { get; }
|
||||
|
||||
public Type WrappingType { get; }
|
||||
|
||||
public Func<object, object> Wrapper { get; }
|
||||
|
||||
public IWrapperProvider GetProvider(WrapperProviderContext context)
|
||||
{
|
||||
if (context.DeclaredType == DeclaredType)
|
||||
{
|
||||
return new WrapperProvider(this);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class WrapperProvider : IWrapperProvider
|
||||
{
|
||||
private readonly WrapperProviderFactory _wrapperFactory;
|
||||
|
||||
public WrapperProvider(WrapperProviderFactory wrapperFactory)
|
||||
{
|
||||
_wrapperFactory = wrapperFactory;
|
||||
}
|
||||
|
||||
public Type WrappingType => _wrapperFactory.WrappingType;
|
||||
|
||||
public object Wrap(object original)
|
||||
{
|
||||
return _wrapperFactory.Wrapper(original);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
_serializerSettings = new DataContractSerializerSettings();
|
||||
|
||||
WrapperProviderFactories = WrapperProviderFactoriesExtensions.GetDefaultProviderFactories();
|
||||
WrapperProviderFactories = new List<IWrapperProviderFactory>
|
||||
{
|
||||
new SerializableErrorWrapperProviderFactory(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -2,34 +2,36 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IConfigureOptions{TOptions}"/> implementation which will add the
|
||||
/// data contract serializer formatters to <see cref="MvcOptions"/>.
|
||||
/// </summary>
|
||||
public class MvcXmlDataContractSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
||||
internal sealed class XmlDataContractSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
||||
{
|
||||
private readonly MvcXmlOptions _xmlOptions;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="MvcXmlDataContractSerializerMvcOptionsSetup"/>.
|
||||
/// Initializes a new instance of <see cref="XmlDataContractSerializerMvcOptionsSetup"/>.
|
||||
/// </summary>
|
||||
/// <param name="xmlOptions"><see cref="MvcXmlOptions"/>.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public MvcXmlDataContractSerializerMvcOptionsSetup(ILoggerFactory loggerFactory)
|
||||
public XmlDataContractSerializerMvcOptionsSetup(
|
||||
IOptions<MvcXmlOptions> xmlOptions,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_loggerFactory = loggerFactory;
|
||||
_xmlOptions = xmlOptions?.Value ?? throw new ArgumentNullException(nameof(xmlOptions));
|
||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -40,8 +42,13 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
{
|
||||
options.ModelMetadataDetailsProviders.Add(new DataMemberRequiredBindingMetadataProvider());
|
||||
|
||||
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter(_loggerFactory));
|
||||
options.InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options));
|
||||
var inputFormatter = new XmlDataContractSerializerInputFormatter(options);
|
||||
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
||||
options.InputFormatters.Add(inputFormatter);
|
||||
|
||||
var outputFormatter = new XmlDataContractSerializerOutputFormatter(_loggerFactory);
|
||||
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
||||
options.OutputFormatters.Add(outputFormatter);
|
||||
|
||||
// Do not override any user mapping
|
||||
var key = "xml";
|
||||
|
|
@ -76,7 +76,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
_serializerSettings = new DataContractSerializerSettings();
|
||||
|
||||
WrapperProviderFactories = WrapperProviderFactoriesExtensions.GetDefaultProviderFactories();
|
||||
WrapperProviderFactories = new List<IWrapperProviderFactory>()
|
||||
{
|
||||
new SerializableErrorWrapperProviderFactory(),
|
||||
};
|
||||
WrapperProviderFactories.Add(new EnumerableWrapperProviderFactory(WrapperProviderFactories));
|
||||
|
||||
_logger = loggerFactory?.CreateLogger(GetType());
|
||||
|
|
|
|||
|
|
@ -43,7 +43,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
SupportedMediaTypes.Add(MediaTypeHeaderValues.TextXml);
|
||||
SupportedMediaTypes.Add(MediaTypeHeaderValues.ApplicationAnyXmlSyntax);
|
||||
|
||||
WrapperProviderFactories = WrapperProviderFactoriesExtensions.GetDefaultProviderFactories();
|
||||
WrapperProviderFactories = new List<IWrapperProviderFactory>
|
||||
{
|
||||
new SerializableErrorWrapperProviderFactory(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -2,32 +2,32 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IConfigureOptions{TOptions}"/> implementation which will add the
|
||||
/// XML serializer formatters to <see cref="MvcOptions"/>.
|
||||
/// </summary>
|
||||
public class MvcXmlSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
||||
internal sealed class XmlSerializerMvcOptionsSetup : IConfigureOptions<MvcOptions>
|
||||
{
|
||||
private readonly MvcXmlOptions _xmlOptions;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="MvcXmlSerializerMvcOptionsSetup"/>.
|
||||
/// Initializes a new instance of <see cref="XmlSerializerMvcOptionsSetup"/>.
|
||||
/// </summary>
|
||||
/// <param name="xmlOptions"><see cref="MvcXmlOptions"/>.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public MvcXmlSerializerMvcOptionsSetup(ILoggerFactory loggerFactory)
|
||||
public XmlSerializerMvcOptionsSetup(
|
||||
IOptions<MvcXmlOptions> xmlOptions,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (loggerFactory == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_loggerFactory = loggerFactory;
|
||||
_xmlOptions = xmlOptions?.Value ?? throw new ArgumentNullException(nameof(xmlOptions));
|
||||
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -46,8 +46,14 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
|||
MediaTypeHeaderValues.ApplicationXml);
|
||||
}
|
||||
|
||||
options.OutputFormatters.Add(new XmlSerializerOutputFormatter(_loggerFactory));
|
||||
options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
|
||||
var inputFormatter = new XmlSerializerInputFormatter(options);
|
||||
inputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
||||
options.InputFormatters.Add(inputFormatter);
|
||||
|
||||
var outputFormatter = new XmlSerializerOutputFormatter(_loggerFactory);
|
||||
outputFormatter.WrapperProviderFactories.Add(new ProblemDetailsWrapperProviderFactory(_xmlOptions));
|
||||
options.OutputFormatters.Add(outputFormatter);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -73,7 +73,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
|
||||
WriterSettings = writerSettings;
|
||||
|
||||
WrapperProviderFactories = WrapperProviderFactoriesExtensions.GetDefaultProviderFactories();
|
||||
WrapperProviderFactories = new List<IWrapperProviderFactory>
|
||||
{
|
||||
new SerializableErrorWrapperProviderFactory(),
|
||||
};
|
||||
WrapperProviderFactories.Add(new EnumerableWrapperProviderFactory(WrapperProviderFactories));
|
||||
|
||||
_logger = loggerFactory?.CreateLogger(GetType());
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||
{
|
||||
public class MvcXmlDataContractSerializerMvcOptionsSetupTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddsFormatterMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new MvcXmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("application/xml", mappedContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotOverrideExistingMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new MvcXmlDataContractSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("text/xml", mappedContentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml.Internal
|
||||
{
|
||||
public class MvcXmlSerializerMvcOptionsSetupTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddsFormatterMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new MvcXmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("application/xml", mappedContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotOverrideExistingMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new MvcXmlSerializerMvcOptionsSetup(NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("text/xml", mappedContentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
public class ProblemDetails21WrapperTest
|
||||
{
|
||||
[Fact]
|
||||
public void ReadXml_ReadsProblemDetailsXml()
|
||||
{
|
||||
// Arrange
|
||||
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ProblemDetails>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<Status>403</Status>" +
|
||||
"<Instance>Some instance</Instance>" +
|
||||
"<key1>Test Value 1</key1>" +
|
||||
"<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" +
|
||||
"<MVC-Empty>Test Value 3</MVC-Empty>" +
|
||||
"</ProblemDetails>";
|
||||
var serializer = new DataContractSerializer(typeof(ProblemDetails21Wrapper));
|
||||
|
||||
// Act
|
||||
var value = serializer.ReadObject(
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(xml)));
|
||||
|
||||
// Assert
|
||||
var problemDetails = Assert.IsType<ProblemDetails21Wrapper>(value).ProblemDetails;
|
||||
Assert.Equal("Some title", problemDetails.Title);
|
||||
Assert.Equal("Some instance", problemDetails.Instance);
|
||||
Assert.Equal(403, problemDetails.Status);
|
||||
|
||||
Assert.Collection(
|
||||
problemDetails.Extensions.OrderBy(kvp => kvp.Key),
|
||||
kvp =>
|
||||
{
|
||||
Assert.Empty(kvp.Key);
|
||||
Assert.Equal("Test Value 3", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("[key2]", kvp.Key);
|
||||
Assert.Equal("Test Value 2", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("key1", kvp.Key);
|
||||
Assert.Equal("Test Value 1", kvp.Value);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteXml_WritesValidXml()
|
||||
{
|
||||
// Arrange
|
||||
var problemDetails = new ProblemDetails
|
||||
{
|
||||
Title = "Some title",
|
||||
Detail = "Some detail",
|
||||
Extensions =
|
||||
{
|
||||
["key1"] = "Test Value 1",
|
||||
["[Key2]"] = "Test Value 2",
|
||||
[""] = "Test Value 3",
|
||||
},
|
||||
};
|
||||
|
||||
var wrapper = new ProblemDetails21Wrapper(problemDetails);
|
||||
var outputStream = new MemoryStream();
|
||||
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ProblemDetails>" +
|
||||
"<Detail>Some detail</Detail>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<key1>Test Value 1</key1>" +
|
||||
"<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" +
|
||||
"<MVC-Empty>Test Value 3</MVC-Empty>" +
|
||||
"</ProblemDetails>";
|
||||
|
||||
// Act
|
||||
using (var xmlWriter = XmlWriter.Create(outputStream))
|
||||
{
|
||||
var dataContractSerializer = new DataContractSerializer(wrapper.GetType());
|
||||
dataContractSerializer.WriteObject(xmlWriter, wrapper);
|
||||
}
|
||||
outputStream.Position = 0;
|
||||
var res = new StreamReader(outputStream, Encoding.UTF8).ReadToEnd();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContent, res);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
public class ProblemDetailsWrapperProviderFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsNull_IfTypeDoesNotMatch()
|
||||
{
|
||||
// Arrange
|
||||
var xmlOptions = new MvcXmlOptions();
|
||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
||||
var context = new WrapperProviderContext(typeof(SerializableError), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(provider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsWrapper_ForProblemDetails()
|
||||
{
|
||||
// Arrange
|
||||
var xmlOptions = new MvcXmlOptions { AllowRfc7807CompliantProblemDetailsFormat = true };
|
||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
||||
var instance = new ProblemDetails();
|
||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
var result = provider.Wrap(instance);
|
||||
var wrapper = Assert.IsType<ProblemDetailsWrapper>(result);
|
||||
Assert.Same(instance, wrapper.ProblemDetails);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_Returns21CompatibleWrapper_ForProblemDetails()
|
||||
{
|
||||
// Arrange
|
||||
var xmlOptions = new MvcXmlOptions();
|
||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
||||
var instance = new ProblemDetails();
|
||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
var result = provider.Wrap(instance);
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
var wrapper = Assert.IsType<ProblemDetails21Wrapper>(result);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
Assert.Same(instance, wrapper.ProblemDetails);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsWrapper_ForValidationProblemDetails()
|
||||
{
|
||||
// Arrange
|
||||
var xmlOptions = new MvcXmlOptions { AllowRfc7807CompliantProblemDetailsFormat = true };
|
||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
||||
var instance = new ValidationProblemDetails();
|
||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
var result = provider.Wrap(instance);
|
||||
var wrapper = Assert.IsType<ValidationProblemDetailsWrapper>(result);
|
||||
Assert.Same(instance, wrapper.ProblemDetails);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_Returns21CompatibleWrapper_ForValidationProblemDetails()
|
||||
{
|
||||
// Arrange
|
||||
var xmlOptions = new MvcXmlOptions();
|
||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
||||
var instance = new ValidationProblemDetails();
|
||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
var result = provider.Wrap(instance);
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
var wrapper = Assert.IsType<ValidationProblemDetails21Wrapper>(result);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
Assert.Same(instance, wrapper.ProblemDetails);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsNull_ForCustomProblemDetails()
|
||||
{
|
||||
// Arrange
|
||||
var xmlOptions = new MvcXmlOptions();
|
||||
var providerFactory = new ProblemDetailsWrapperProviderFactory(xmlOptions);
|
||||
var instance = new CustomProblemDetails();
|
||||
var context = new WrapperProviderContext(instance.GetType(), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(provider);
|
||||
}
|
||||
|
||||
private class CustomProblemDetails : ProblemDetails { }
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +56,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void WriteXml_WritesValidXml()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
public class ValidationProblemDetails21WrapperTest
|
||||
{
|
||||
[Fact]
|
||||
public void ReadXml_ReadsValidationProblemDetailsXml()
|
||||
{
|
||||
// Arrange
|
||||
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ValidationProblemDetails>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<Status>400</Status>" +
|
||||
"<Instance>Some instance</Instance>" +
|
||||
"<key1>Test Value 1</key1>" +
|
||||
"<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" +
|
||||
"<MVC-Errors>" +
|
||||
"<error1>Test error 1 Test error 2</error1>" +
|
||||
"<_x005B_error2_x005D_>Test error 3</_x005B_error2_x005D_>" +
|
||||
"<MVC-Empty>Test error 4</MVC-Empty>" +
|
||||
"</MVC-Errors>" +
|
||||
"</ValidationProblemDetails>";
|
||||
var serializer = new DataContractSerializer(typeof(ValidationProblemDetails21Wrapper));
|
||||
|
||||
// Act
|
||||
var value = serializer.ReadObject(
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(xml)));
|
||||
|
||||
// Assert
|
||||
var problemDetails = Assert.IsType<ValidationProblemDetails21Wrapper>(value).ProblemDetails;
|
||||
Assert.Equal("Some title", problemDetails.Title);
|
||||
Assert.Equal("Some instance", problemDetails.Instance);
|
||||
Assert.Equal(400, problemDetails.Status);
|
||||
|
||||
Assert.Collection(
|
||||
problemDetails.Extensions.OrderBy(kvp => kvp.Key),
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("[key2]", kvp.Key);
|
||||
Assert.Equal("Test Value 2", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("key1", kvp.Key);
|
||||
Assert.Equal("Test Value 1", kvp.Value);
|
||||
});
|
||||
|
||||
Assert.Collection(
|
||||
problemDetails.Errors.OrderBy(kvp => kvp.Key),
|
||||
kvp =>
|
||||
{
|
||||
Assert.Empty(kvp.Key);
|
||||
Assert.Equal(new[] { "Test error 4" }, kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("[error2]", kvp.Key);
|
||||
Assert.Equal(new[] { "Test error 3" }, kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("error1", kvp.Key);
|
||||
Assert.Equal(new[] { "Test error 1 Test error 2" }, kvp.Value);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadXml_ReadsValidationProblemDetailsXml_WithNoErrors()
|
||||
{
|
||||
// Arrange
|
||||
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ValidationProblemDetails>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<Status>400</Status>" +
|
||||
"<Instance>Some instance</Instance>" +
|
||||
"<key1>Test Value 1</key1>" +
|
||||
"<_x005B_key2_x005D_>Test Value 2</_x005B_key2_x005D_>" +
|
||||
"</ValidationProblemDetails>";
|
||||
var serializer = new DataContractSerializer(typeof(ValidationProblemDetails21Wrapper));
|
||||
|
||||
// Act
|
||||
var value = serializer.ReadObject(
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(xml)));
|
||||
|
||||
// Assert
|
||||
var problemDetails = Assert.IsType<ValidationProblemDetails21Wrapper>(value).ProblemDetails;
|
||||
Assert.Equal("Some title", problemDetails.Title);
|
||||
Assert.Equal("Some instance", problemDetails.Instance);
|
||||
Assert.Equal(400, problemDetails.Status);
|
||||
|
||||
Assert.Collection(
|
||||
problemDetails.Extensions,
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("key1", kvp.Key);
|
||||
Assert.Equal("Test Value 1", kvp.Value);
|
||||
},
|
||||
kvp =>
|
||||
{
|
||||
Assert.Equal("[key2]", kvp.Key);
|
||||
Assert.Equal("Test Value 2", kvp.Value);
|
||||
});
|
||||
|
||||
Assert.Empty(problemDetails.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadXml_ReadsValidationProblemDetailsXml_WithEmptyErrorsElement()
|
||||
{
|
||||
// Arrange
|
||||
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ValidationProblemDetails>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<Status>400</Status>" +
|
||||
"<MVC-Errors />" +
|
||||
"</ValidationProblemDetails>";
|
||||
var serializer = new DataContractSerializer(typeof(ValidationProblemDetails21Wrapper));
|
||||
|
||||
// Act
|
||||
var value = serializer.ReadObject(
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(xml)));
|
||||
|
||||
// Assert
|
||||
var problemDetails = Assert.IsType<ValidationProblemDetails21Wrapper>(value).ProblemDetails;
|
||||
Assert.Equal("Some title", problemDetails.Title);
|
||||
Assert.Equal(400, problemDetails.Status);
|
||||
Assert.Empty(problemDetails.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteXml_WritesValidXml()
|
||||
{
|
||||
// Arrange
|
||||
var problemDetails = new ValidationProblemDetails
|
||||
{
|
||||
Title = "Some title",
|
||||
Detail = "Some detail",
|
||||
Extensions =
|
||||
{
|
||||
["key1"] = "Test Value 1",
|
||||
["[Key2]"] = "Test Value 2"
|
||||
},
|
||||
Errors =
|
||||
{
|
||||
{ "error1", new[] {"Test error 1", "Test error 2" } },
|
||||
{ "[error2]", new[] {"Test error 3" } },
|
||||
{ "", new[] { "Test error 4" } },
|
||||
}
|
||||
};
|
||||
|
||||
var wrapper = new ValidationProblemDetails21Wrapper(problemDetails);
|
||||
var outputStream = new MemoryStream();
|
||||
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ValidationProblemDetails>" +
|
||||
"<Detail>Some detail</Detail>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<key1>Test Value 1</key1>" +
|
||||
"<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" +
|
||||
"<MVC-Errors>" +
|
||||
"<error1>Test error 1 Test error 2</error1>" +
|
||||
"<_x005B_error2_x005D_>Test error 3</_x005B_error2_x005D_>" +
|
||||
"<MVC-Empty>Test error 4</MVC-Empty>" +
|
||||
"</MVC-Errors>" +
|
||||
"</ValidationProblemDetails>";
|
||||
|
||||
// Act
|
||||
using (var xmlWriter = XmlWriter.Create(outputStream))
|
||||
{
|
||||
var dataContractSerializer = new DataContractSerializer(wrapper.GetType());
|
||||
dataContractSerializer.WriteObject(xmlWriter, wrapper);
|
||||
}
|
||||
outputStream.Position = 0;
|
||||
var res = new StreamReader(outputStream, Encoding.UTF8).ReadToEnd();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContent, res);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteXml_WithNoValidationErrors()
|
||||
{
|
||||
// Arrange
|
||||
var problemDetails = new ValidationProblemDetails
|
||||
{
|
||||
Title = "Some title",
|
||||
Detail = "Some detail",
|
||||
Extensions =
|
||||
{
|
||||
["key1"] = "Test Value 1",
|
||||
["[Key2]"] = "Test Value 2"
|
||||
},
|
||||
};
|
||||
|
||||
var wrapper = new ValidationProblemDetails21Wrapper(problemDetails);
|
||||
var outputStream = new MemoryStream();
|
||||
var expectedContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<ValidationProblemDetails>" +
|
||||
"<Detail>Some detail</Detail>" +
|
||||
"<Title>Some title</Title>" +
|
||||
"<key1>Test Value 1</key1>" +
|
||||
"<_x005B_Key2_x005D_>Test Value 2</_x005B_Key2_x005D_>" +
|
||||
"</ValidationProblemDetails>";
|
||||
|
||||
// Act
|
||||
using (var xmlWriter = XmlWriter.Create(outputStream))
|
||||
{
|
||||
var dataContractSerializer = new DataContractSerializer(wrapper.GetType());
|
||||
dataContractSerializer.WriteObject(xmlWriter, wrapper);
|
||||
}
|
||||
outputStream.Position = 0;
|
||||
var res = new StreamReader(outputStream, Encoding.UTF8).ReadToEnd();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedContent, res);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
public class WrapperProviderFactoryExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetDefaultProviderFactories_GetsFactoriesUsedByInputAndOutputFormatters()
|
||||
{
|
||||
// Act
|
||||
var factoryProviders = WrapperProviderFactoriesExtensions.GetDefaultProviderFactories();
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
factoryProviders,
|
||||
factory => Assert.IsType<SerializableErrorWrapperProviderFactory>(factory),
|
||||
factory =>
|
||||
{
|
||||
var wrapperProviderFactory = Assert.IsType<WrapperProviderFactory>(factory);
|
||||
Assert.Equal(typeof(ProblemDetails), wrapperProviderFactory.DeclaredType);
|
||||
Assert.Equal(typeof(ProblemDetailsWrapper), wrapperProviderFactory.WrappingType);
|
||||
},
|
||||
factory =>
|
||||
{
|
||||
var wrapperProviderFactory = Assert.IsType<WrapperProviderFactory>(factory);
|
||||
Assert.Equal(typeof(ValidationProblemDetails), wrapperProviderFactory.DeclaredType);
|
||||
Assert.Equal(typeof(ValidationProblemDetailsWrapper), wrapperProviderFactory.WrappingType);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
public class WrapperProviderFactoryTest
|
||||
{
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsNull_IfTypeDoesNotMatch()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new WrapperProviderFactory(
|
||||
typeof(ProblemDetails),
|
||||
typeof(ProblemDetailsWrapper),
|
||||
_ => null);
|
||||
var context = new WrapperProviderContext(typeof(SerializableError), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var result = provider.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsNull_IfTypeIsSubtype()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new WrapperProviderFactory(
|
||||
typeof(ProblemDetails),
|
||||
typeof(ProblemDetailsWrapper),
|
||||
_ => null);
|
||||
var context = new WrapperProviderContext(typeof(ValidationProblemDetails), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var result = provider.GetProvider(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetProvider_ReturnsValue_IfTypeMatches()
|
||||
{
|
||||
// Arrange
|
||||
var expected = new object();
|
||||
var providerFactory = new WrapperProviderFactory(
|
||||
typeof(ProblemDetails),
|
||||
typeof(ProblemDetailsWrapper),
|
||||
_ => expected);
|
||||
var context = new WrapperProviderContext(typeof(ProblemDetails), isSerialization: true);
|
||||
|
||||
// Act
|
||||
var provider = providerFactory.GetProvider(context);
|
||||
var result = provider.Wrap(new ProblemDetails());
|
||||
|
||||
// Assert
|
||||
Assert.Same(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
public class XmlDataContractSerializerMvcOptionsSetupTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddsFormatterMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("application/xml", mappedContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotOverrideExistingMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("text/xml", mappedContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddsInputFormatter()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<XmlDataContractSerializerInputFormatter>(Assert.Single(options.InputFormatters));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddsOutputFormatter()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlDataContractSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<XmlDataContractSerializerOutputFormatter>(Assert.Single(options.OutputFormatters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters.Xml
|
||||
{
|
||||
public class XmlSerializerMvcOptionsSetupTest
|
||||
{
|
||||
[Fact]
|
||||
public void AddsFormatterMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("application/xml", mappedContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotOverrideExistingMapping()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
options.FormatterMappings.SetMediaTypeMappingForFormat("xml", "text/xml");
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
var mappedContentType = options.FormatterMappings.GetMediaTypeMappingForFormat("xml");
|
||||
Assert.Equal("text/xml", mappedContentType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddsInputFormatter()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<XmlSerializerInputFormatter>(Assert.Single(options.InputFormatters));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddsOutputFormatter()
|
||||
{
|
||||
// Arrange
|
||||
var optionsSetup = new XmlSerializerMvcOptionsSetup(Options.Create(new MvcXmlOptions()), NullLoggerFactory.Instance);
|
||||
var options = new MvcOptions();
|
||||
|
||||
// Act
|
||||
optionsSetup.Configure(options);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<XmlSerializerOutputFormatter>(Assert.Single(options.OutputFormatters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,16 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using XmlFormattersWebSite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
|
|
@ -16,10 +20,12 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
{
|
||||
public XmlDataContractSerializerFormattersWrappingTest(MvcTestFixture<XmlFormattersWebSite.Startup> fixture)
|
||||
{
|
||||
Client = fixture.CreateDefaultClient();
|
||||
Factory = fixture.Factories.FirstOrDefault() ?? fixture.WithWebHostBuilder(builder => builder.UseStartup<Startup>());
|
||||
Client = Factory.CreateDefaultClient();
|
||||
}
|
||||
|
||||
public HttpClient Client { get; }
|
||||
public WebApplicationFactory<Startup> Factory { get; }
|
||||
|
||||
[ConditionalTheory]
|
||||
// Mono issue - https://github.com/aspnet/External/issues/18
|
||||
|
|
@ -254,6 +260,31 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProblemDetails_With21Behavior()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "<ProblemDetails>" +
|
||||
"<Instance>instance</Instance>" +
|
||||
"<Status>404</Status>" +
|
||||
"<Title>title</Title>" +
|
||||
"<Correlation>correlation</Correlation>" +
|
||||
"<Accounts>Account1 Account2</Accounts>" +
|
||||
"</ProblemDetails>";
|
||||
|
||||
var client = Factory
|
||||
.WithWebHostBuilder(builder => builder.UseStartup<StartupWith21Compat>())
|
||||
.CreateDefaultClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("/api/XmlDataContractApi/ActionReturningProblemDetails");
|
||||
|
||||
// Assert
|
||||
await response.AssertStatusCodeAsync(HttpStatusCode.NotFound);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidationProblemDetails_IsSerialized()
|
||||
{
|
||||
|
|
@ -302,5 +333,33 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
var content = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidationProblemDetails_With21Behavior()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "<ValidationProblemDetails>" +
|
||||
"<Detail>some detail</Detail>" +
|
||||
"<Status>400</Status>" +
|
||||
"<Title>One or more validation errors occurred.</Title>" +
|
||||
"<Type>some type</Type>" +
|
||||
"<CorrelationId>correlation</CorrelationId>" +
|
||||
"<MVC-Errors>" +
|
||||
"<Error1>ErrorValue</Error1>" +
|
||||
"</MVC-Errors>" +
|
||||
"</ValidationProblemDetails>";
|
||||
|
||||
var client = Factory
|
||||
.WithWebHostBuilder(builder => builder.UseStartup<StartupWith21Compat>())
|
||||
.CreateDefaultClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("/api/XmlDataContractApi/ActionReturningValidationDetailsWithMetadata");
|
||||
|
||||
// Assert
|
||||
await response.AssertStatusCodeAsync(HttpStatusCode.BadRequest);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,15 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using XmlFormattersWebSite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
|
|
@ -15,9 +19,11 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
{
|
||||
public XmlSerializerFormattersWrappingTest(MvcTestFixture<XmlFormattersWebSite.Startup> fixture)
|
||||
{
|
||||
Client = fixture.CreateDefaultClient();
|
||||
Factory = fixture.Factories.FirstOrDefault() ?? fixture.WithWebHostBuilder(builder => builder.UseStartup<Startup>());
|
||||
Client = Factory.CreateDefaultClient();
|
||||
}
|
||||
|
||||
public WebApplicationFactory<Startup> Factory { get; }
|
||||
public HttpClient Client { get; }
|
||||
|
||||
[Theory]
|
||||
|
|
@ -208,6 +214,31 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProblemDetails_With21Behavior()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "<ProblemDetails>" +
|
||||
"<Instance>instance</Instance>" +
|
||||
"<Status>404</Status>" +
|
||||
"<Title>title</Title>" +
|
||||
"<Correlation>correlation</Correlation>" +
|
||||
"<Accounts>Account1 Account2</Accounts>" +
|
||||
"</ProblemDetails>";
|
||||
|
||||
var client = Factory
|
||||
.WithWebHostBuilder(builder => builder.UseStartup<StartupWith21Compat>())
|
||||
.CreateDefaultClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("/api/XmlSerializerApi/ActionReturningProblemDetails");
|
||||
|
||||
// Assert
|
||||
await response.AssertStatusCodeAsync(HttpStatusCode.NotFound);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProblemDetails_WithExtensionMembers_IsSerialized()
|
||||
{
|
||||
|
|
@ -277,5 +308,33 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
var content = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidationProblemDetails_With21Behavior()
|
||||
{
|
||||
// Arrange
|
||||
var expected = "<ValidationProblemDetails>" +
|
||||
"<Detail>some detail</Detail>" +
|
||||
"<Status>400</Status>" +
|
||||
"<Title>One or more validation errors occurred.</Title>" +
|
||||
"<Type>some type</Type>" +
|
||||
"<CorrelationId>correlation</CorrelationId>" +
|
||||
"<MVC-Errors>" +
|
||||
"<Error1>ErrorValue</Error1>" +
|
||||
"</MVC-Errors>" +
|
||||
"</ValidationProblemDetails>";
|
||||
|
||||
var client = Factory
|
||||
.WithWebHostBuilder(builder => builder.UseStartup<StartupWith21Compat>())
|
||||
.CreateDefaultClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("/api/XmlSerializerApi/ActionReturningValidationDetailsWithMetadata");
|
||||
|
||||
// Assert
|
||||
await response.AssertStatusCodeAsync(HttpStatusCode.BadRequest);
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
XmlAssert.Equal(expected, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,12 +5,8 @@ using System;
|
|||
using System.Buffers;
|
||||
using Microsoft.AspNetCore.Mvc.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Json.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters.Xml;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -26,7 +27,10 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
AddHostingServices(serviceCollection);
|
||||
serviceCollection.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_0);
|
||||
serviceCollection
|
||||
.AddMvc()
|
||||
.AddXmlDataContractSerializerFormatters()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_0);
|
||||
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
|
||||
|
|
@ -36,6 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
var apiBehaviorOptions = services.GetRequiredService<IOptions<ApiBehaviorOptions>>().Value;
|
||||
var razorViewEngineOptions = services.GetRequiredService<IOptions<RazorViewEngineOptions>>().Value;
|
||||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.False(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
|
|
@ -50,6 +55,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.True(apiBehaviorOptions.SuppressMapClientErrors);
|
||||
Assert.True(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
|
||||
Assert.False(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
||||
Assert.False(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -58,7 +64,10 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
AddHostingServices(serviceCollection);
|
||||
serviceCollection.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
|
||||
serviceCollection
|
||||
.AddMvc()
|
||||
.AddXmlDataContractSerializerFormatters()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
|
||||
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
|
||||
|
|
@ -68,6 +77,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
var apiBehaviorOptions = services.GetRequiredService<IOptions<ApiBehaviorOptions>>().Value;
|
||||
var razorViewEngineOptions = services.GetRequiredService<IOptions<RazorViewEngineOptions>>().Value;
|
||||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
|
|
@ -82,6 +92,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.True(apiBehaviorOptions.SuppressMapClientErrors);
|
||||
Assert.True(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
|
||||
Assert.False(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
||||
Assert.False(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -90,7 +101,10 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
AddHostingServices(serviceCollection);
|
||||
serviceCollection.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
serviceCollection
|
||||
.AddMvc()
|
||||
.AddXmlDataContractSerializerFormatters()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
|
||||
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
|
||||
|
|
@ -100,6 +114,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
var apiBehaviorOptions = services.GetRequiredService<IOptions<ApiBehaviorOptions>>().Value;
|
||||
var razorViewEngineOptions = services.GetRequiredService<IOptions<RazorViewEngineOptions>>().Value;
|
||||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
|
|
@ -114,6 +129,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.False(apiBehaviorOptions.SuppressMapClientErrors);
|
||||
Assert.False(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
|
||||
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
||||
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -122,7 +138,10 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
// Arrange
|
||||
var serviceCollection = new ServiceCollection();
|
||||
AddHostingServices(serviceCollection);
|
||||
serviceCollection.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
serviceCollection
|
||||
.AddMvc()
|
||||
.AddXmlDataContractSerializerFormatters()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
|
||||
var services = serviceCollection.BuildServiceProvider();
|
||||
|
||||
|
|
@ -132,6 +151,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
var apiBehaviorOptions = services.GetRequiredService<IOptions<ApiBehaviorOptions>>().Value;
|
||||
var razorViewEngineOptions = services.GetRequiredService<IOptions<RazorViewEngineOptions>>().Value;
|
||||
var xmlOptions = services.GetRequiredService<IOptions<MvcXmlOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
|
|
@ -146,6 +166,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
Assert.False(apiBehaviorOptions.SuppressMapClientErrors);
|
||||
Assert.False(razorViewEngineOptions.AllowRecompilingViewsOnFileChange);
|
||||
Assert.True(razorPagesOptions.AllowDefaultHandlingForOptionsRequests);
|
||||
Assert.True(xmlOptions.AllowRfc7807CompliantProblemDetailsFormat);
|
||||
}
|
||||
|
||||
// This just does the minimum needed to be able to resolve these options.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace XmlFormattersWebSite
|
||||
{
|
||||
|
|
@ -22,7 +25,10 @@ namespace XmlFormattersWebSite
|
|||
// Both kinds of Xml serializers are configured for this application and use custom content-types to do formatter
|
||||
// selection. The globally configured formatters rely on custom content-type to perform conneg which does not play
|
||||
// well the ProblemDetails returning filters that defaults to using application/xml. We'll explicitly select the formatter for this controller.
|
||||
objectResult.Formatters.Add(new XmlDataContractSerializerOutputFormatter());
|
||||
var mvcOptions = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>();
|
||||
var xmlFormatter = mvcOptions.Value.OutputFormatters.OfType<XmlDataContractSerializerOutputFormatter>().First();
|
||||
|
||||
objectResult.Formatters.Add(xmlFormatter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace XmlFormattersWebSite
|
||||
{
|
||||
|
|
@ -22,7 +25,10 @@ namespace XmlFormattersWebSite
|
|||
// Both kinds of Xml serializers are configured for this application and use custom content-types to do formatter
|
||||
// selection. The globally configured formatters rely on custom content-type to perform conneg which does not play
|
||||
// well the ProblemDetails returning filters that defaults to using application/xml. We'll explicitly select the formatter for this controller.
|
||||
objectResult.Formatters.Add(new XmlSerializerOutputFormatter());
|
||||
var mvcOptions = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>();
|
||||
var xmlFormatter = mvcOptions.Value.OutputFormatters.OfType<XmlSerializerOutputFormatter>().First();
|
||||
|
||||
objectResult.Formatters.Add(xmlFormatter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,47 +13,85 @@ namespace XmlFormattersWebSite
|
|||
{
|
||||
public class Startup
|
||||
{
|
||||
public virtual CompatibilityVersion CompatibilityVersion => CompatibilityVersion.Latest;
|
||||
|
||||
// Set up application services
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add MVC services to the services container
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Latest);
|
||||
.AddXmlDataContractSerializerFormatters()
|
||||
.AddXmlSerializerFormatters()
|
||||
.SetCompatibilityVersion(CompatibilityVersion);
|
||||
|
||||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.InputFormatters.Clear();
|
||||
options.OutputFormatters.Clear();
|
||||
|
||||
// Since both XmlSerializer and DataContractSerializer based formatters
|
||||
// have supported media types of 'application/xml' and 'text/xml', it
|
||||
// would be difficult for a test to choose a particular formatter based on
|
||||
// request information (Ex: Accept header).
|
||||
// So here we instead clear out the default supported media types and create new
|
||||
// ones which are distinguishable between formatters.
|
||||
var xmlSerializerInputFormatter = new XmlSerializerInputFormatter(new MvcOptions());
|
||||
// request information (Ex: Accept header).
|
||||
// We'll configure the ones on MvcOptions to use a distinct set of content types.
|
||||
|
||||
XmlSerializerInputFormatter xmlSerializerInputFormatter = null;
|
||||
XmlSerializerOutputFormatter xmlSerializerOutputFormatter = null;
|
||||
XmlDataContractSerializerInputFormatter dcsInputFormatter = null;
|
||||
XmlDataContractSerializerOutputFormatter dcsOutputFormatter = null;
|
||||
|
||||
for (var i = options.InputFormatters.Count - 1; i >= 0; i--)
|
||||
{
|
||||
switch (options.InputFormatters[i])
|
||||
{
|
||||
case XmlSerializerInputFormatter formatter:
|
||||
xmlSerializerInputFormatter = formatter;
|
||||
break;
|
||||
|
||||
case XmlDataContractSerializerInputFormatter formatter:
|
||||
dcsInputFormatter = formatter;
|
||||
break;
|
||||
|
||||
default:
|
||||
options.InputFormatters.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = options.OutputFormatters.Count - 1; i >= 0; i--)
|
||||
{
|
||||
switch (options.OutputFormatters[i])
|
||||
{
|
||||
case XmlSerializerOutputFormatter formatter:
|
||||
xmlSerializerOutputFormatter = formatter;
|
||||
break;
|
||||
|
||||
case XmlDataContractSerializerOutputFormatter formatter:
|
||||
dcsOutputFormatter = formatter;
|
||||
break;
|
||||
|
||||
default:
|
||||
options.OutputFormatters.RemoveAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xmlSerializerInputFormatter.SupportedMediaTypes.Clear();
|
||||
xmlSerializerInputFormatter.SupportedMediaTypes.Add(
|
||||
new MediaTypeHeaderValue("application/xml-xmlser"));
|
||||
xmlSerializerInputFormatter.SupportedMediaTypes.Add(
|
||||
new MediaTypeHeaderValue("text/xml-xmlser"));
|
||||
xmlSerializerInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-xmlser"));
|
||||
xmlSerializerInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-xmlser"));
|
||||
xmlSerializerInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml"));
|
||||
|
||||
var xmlSerializerOutputFormatter = new XmlSerializerOutputFormatter();
|
||||
xmlSerializerOutputFormatter.SupportedMediaTypes.Clear();
|
||||
xmlSerializerOutputFormatter.SupportedMediaTypes.Add(
|
||||
new MediaTypeHeaderValue("application/xml-xmlser"));
|
||||
xmlSerializerOutputFormatter.SupportedMediaTypes.Add(
|
||||
new MediaTypeHeaderValue("text/xml-xmlser"));
|
||||
xmlSerializerOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-xmlser"));
|
||||
xmlSerializerOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-xmlser"));
|
||||
xmlSerializerOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml"));
|
||||
|
||||
var dcsInputFormatter = new XmlDataContractSerializerInputFormatter(new MvcOptions());
|
||||
dcsInputFormatter.SupportedMediaTypes.Clear();
|
||||
dcsInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-dcs"));
|
||||
dcsInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-dcs"));
|
||||
dcsInputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml"));
|
||||
|
||||
var dcsOutputFormatter = new XmlDataContractSerializerOutputFormatter();
|
||||
dcsOutputFormatter.SupportedMediaTypes.Clear();
|
||||
dcsOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xml-dcs"));
|
||||
dcsOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml-dcs"));
|
||||
dcsOutputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/problem+xml"));
|
||||
|
||||
options.InputFormatters.Add(dcsInputFormatter);
|
||||
options.InputFormatters.Add(xmlSerializerInputFormatter);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace XmlFormattersWebSite
|
||||
{
|
||||
public class StartupWith21Compat : Startup
|
||||
{
|
||||
public override CompatibilityVersion CompatibilityVersion => CompatibilityVersion.Version_2_1;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue