Adding SerializableError - a serializable container for the purpose of output conneg.
This commit is contained in:
parent
51567194dc
commit
5262dfd577
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="ObjectResult"/> that when executed will produce a Bad Request (400) response.
|
||||
/// </summary>
|
||||
public class BadRequestObjectResult : ObjectResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BadRequestObjectResult"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="error">Contains the errors to be returned to the client.</param>
|
||||
public BadRequestObjectResult(object error)
|
||||
: base(error)
|
||||
{
|
||||
StatusCode = 400;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="BadRequestObjectResult"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="modelState"><see cref="ModelStateDictionary"/> containing the validation errors.</param>
|
||||
public BadRequestObjectResult([NotNull] ModelStateDictionary modelState)
|
||||
: base(new SerializableError(modelState))
|
||||
{
|
||||
StatusCode = 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a serializable container for storing ModelState information.
|
||||
/// This information is stored as key/value pairs.
|
||||
/// </summary>
|
||||
[XmlRoot("Error")]
|
||||
public sealed class SerializableError : Dictionary<string, object>, IXmlSerializable
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SerializableError"/> class.
|
||||
/// </summary>
|
||||
public SerializableError()
|
||||
: base(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="SerializableError"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelState"><see cref="ModelState"/> containing the validation errors.</param>
|
||||
public SerializableError([NotNull] ModelStateDictionary modelState)
|
||||
: this()
|
||||
{
|
||||
if (modelState.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var keyModelStatePair in modelState)
|
||||
{
|
||||
var key = keyModelStatePair.Key;
|
||||
var errors = keyModelStatePair.Value.Errors;
|
||||
if (errors != null && errors.Count > 0)
|
||||
{
|
||||
var errorMessages = errors.Select(error =>
|
||||
{
|
||||
return string.IsNullOrEmpty(error.ErrorMessage) ?
|
||||
Resources.SerializableError_DefaultError : error.ErrorMessage;
|
||||
}).ToArray();
|
||||
|
||||
Add(key, errorMessages);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <inheritdoc />
|
||||
public XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// <inheritdoc />
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return;
|
||||
}
|
||||
|
||||
reader.ReadStartElement();
|
||||
while (reader.NodeType != XmlNodeType.EndElement)
|
||||
{
|
||||
var key = XmlConvert.DecodeName(reader.LocalName);
|
||||
var value = reader.ReadInnerXml();
|
||||
|
||||
Add(key, value);
|
||||
reader.MoveToContent();
|
||||
}
|
||||
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
|
||||
// <inheritdoc />
|
||||
public void WriteXml(XmlWriter writer)
|
||||
{
|
||||
foreach (var keyValuePair in this)
|
||||
{
|
||||
var key = keyValuePair.Key;
|
||||
var value = keyValuePair.Value;
|
||||
writer.WriteStartElement(XmlConvert.EncodeLocalName(key));
|
||||
if (value != null)
|
||||
{
|
||||
writer.WriteValue(value);
|
||||
}
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -627,6 +627,26 @@ namespace Microsoft.AspNet.Mvc
|
|||
return new BadRequestResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="BadRequestObjectResult"/> that produces a Bad Request (400) response.
|
||||
/// </summary>
|
||||
/// <returns>The created <see cref="BadRequestObjectResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual BadRequestObjectResult HttpBadRequest(object error)
|
||||
{
|
||||
return new BadRequestObjectResult(error);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="BadRequestObjectResult"/> that produces a Bad Request (400) response.
|
||||
/// </summary>
|
||||
/// <returns>The created <see cref="BadRequestObjectResult"/> for the response.</returns>
|
||||
[NonAction]
|
||||
public virtual BadRequestObjectResult HttpBadRequest([NotNull] ModelStateDictionary modelState)
|
||||
{
|
||||
return new BadRequestObjectResult(modelState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CreatedResult"/> object that produces a Created (201) response.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1514,6 +1514,22 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("ViewComponent_AmbiguousTypeMatch_Item"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The input was not valid.
|
||||
/// </summary>
|
||||
internal static string SerializableError_DefaultError
|
||||
{
|
||||
get { return GetString("SerializableError_DefaultError"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The input was not valid.
|
||||
/// </summary>
|
||||
internal static string FormatSerializableError_DefaultError()
|
||||
{
|
||||
return GetString("SerializableError_DefaultError");
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
|
@ -409,4 +409,7 @@
|
|||
<data name="ViewComponent_AmbiguousTypeMatch_Item" xml:space="preserve">
|
||||
<value>Type: '{0}' - Name: '{1}'</value>
|
||||
</data>
|
||||
<data name="SerializableError_DefaultError" xml:space="preserve">
|
||||
<value>The input was not valid.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Xunit;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class BadRequestObjectResultTests
|
||||
{
|
||||
[Fact]
|
||||
public void BadRequestObjectResult_SetsStatusCodeAndValue()
|
||||
{
|
||||
// Arrange & Act
|
||||
var obj = new object();
|
||||
var badRequestObjecResult = new BadRequestObjectResult(obj);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(400, badRequestObjecResult.StatusCode);
|
||||
Assert.Equal(obj, badRequestObjecResult.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BadRequestObjectResult_ModelState_SetsStatusCodeAndValue()
|
||||
{
|
||||
// Arrange & Act
|
||||
var badRequestObjecResult = new BadRequestObjectResult(new ModelStateDictionary());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(400, badRequestObjecResult.StatusCode);
|
||||
var errors = Assert.IsType<SerializableError>(badRequestObjecResult.Value);
|
||||
Assert.Equal(0, errors.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class SerializableErrorTests
|
||||
{
|
||||
[Fact]
|
||||
public void ConvertsModelState_To_Dictionary()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.AddModelError("key1", "Test Error 1");
|
||||
modelState.AddModelError("key1", "Test Error 2");
|
||||
modelState.AddModelError("key2", "Test Error 3");
|
||||
|
||||
// Act
|
||||
var serializableError = new SerializableError(modelState);
|
||||
|
||||
// Assert
|
||||
var arr = Assert.IsType<string[]>(serializableError["key1"]);
|
||||
Assert.Equal("Test Error 1", arr[0]);
|
||||
Assert.Equal("Test Error 2", arr[1]);
|
||||
Assert.Equal("Test Error 3", (serializableError["key2"] as string[])[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LookupIsCaseInsensitive()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.AddModelError("key1", "x");
|
||||
|
||||
// Act
|
||||
var serializableError = new SerializableError(modelState);
|
||||
|
||||
// Assert
|
||||
var arr = Assert.IsType<string[]>(serializableError["KEY1"]);
|
||||
Assert.Equal("x", arr[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConvertsModelState_To_Dictionary_AddsDefaultValuesWhenErrorsAreAbsent()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.AddModelError("key1", "");
|
||||
|
||||
// Act
|
||||
var serializableError = new SerializableError(modelState);
|
||||
|
||||
// Assert
|
||||
var arr = Assert.IsType<string[]>(serializableError["key1"]);
|
||||
Assert.Equal("The input was not valid.", arr[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotThrowOnValidModelState()
|
||||
{
|
||||
// Arrange, Act & Assert (does not throw)
|
||||
new SerializableError(new ModelStateDictionary());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotAddEntries_IfNoErrorsArePresent()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.Add(
|
||||
"key1",
|
||||
new ModelState() { Value = new ValueProviderResult("foo", "foo", CultureInfo.InvariantCulture) });
|
||||
modelState.Add(
|
||||
"key2",
|
||||
new ModelState() { Value = new ValueProviderResult("bar", "bar", CultureInfo.InvariantCulture) });
|
||||
|
||||
// Act
|
||||
var serializableError = new SerializableError(modelState);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, serializableError.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSchema_Returns_Null()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
// To make modelState invalid.
|
||||
modelState.AddModelError("key1", "Test Error 1");
|
||||
var serializableError = new SerializableError(modelState);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Null(serializableError.GetSchema());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteXml_WritesValidXml()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.AddModelError("key1", "Test Error 1");
|
||||
modelState.AddModelError("key1", "Test Error 2");
|
||||
modelState.AddModelError("key2", "Test Error 3");
|
||||
var serializableError = new SerializableError(modelState);
|
||||
var outputStream = new MemoryStream();
|
||||
|
||||
// Act
|
||||
using (var xmlWriter = XmlWriter.Create(outputStream))
|
||||
{
|
||||
var dataContractSerializer = new DataContractSerializer(typeof(SerializableError));
|
||||
dataContractSerializer.WriteObject(xmlWriter, serializableError);
|
||||
}
|
||||
outputStream.Position = 0;
|
||||
var res = new StreamReader(outputStream, Encoding.UTF8).ReadToEnd();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<Error><key1>Test Error 1 Test Error 2</key1><key2>Test Error 3</key2></Error>", res);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadXml_ReadsSerializableErrorXml()
|
||||
{
|
||||
// Arrange
|
||||
var serializableErrorXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
|
||||
"<Error><key1>Test Error 1 Test Error 2</key1><key2>Test Error 3</key2></Error>";
|
||||
var serializer = new DataContractSerializer(typeof(SerializableError));
|
||||
|
||||
// Act
|
||||
var errors = (SerializableError)serializer.ReadObject(
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(serializableErrorXml)));
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Test Error 1 Test Error 2", errors["key1"]);
|
||||
Assert.Equal("Test Error 3", errors["key2"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -669,6 +669,38 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
Assert.Equal(400, result.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BadRequest_SetsStatusCodeAndValue_Object()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new Controller();
|
||||
var obj = new object();
|
||||
|
||||
// Act
|
||||
var result = controller.HttpBadRequest(obj);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BadRequestObjectResult>(result);
|
||||
Assert.Equal(400, result.StatusCode);
|
||||
Assert.Equal(obj, result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BadRequest_SetsStatusCodeAndValue_ModelState()
|
||||
{
|
||||
// Arrange
|
||||
var controller = new Controller();
|
||||
|
||||
// Act
|
||||
var result = controller.HttpBadRequest(new ModelStateDictionary());
|
||||
|
||||
// Assert
|
||||
Assert.IsType<BadRequestObjectResult>(result);
|
||||
Assert.Equal(400, result.StatusCode);
|
||||
var errors = Assert.IsType<SerializableError>(result.Value);
|
||||
Assert.Equal(0, errors.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(PublicNormalMethodsFromController))]
|
||||
public void NonActionAttribute_IsOnEveryPublicNormalMethodFromController(MethodInfo method)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using ActionResultsWebSite;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
|
|
@ -17,7 +20,10 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
{
|
||||
private readonly IServiceProvider _provider = TestHelper.CreateServices("ActionResultsWebSite");
|
||||
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||
|
||||
private const string sampleIntError = "The field SampleInt must be between 10 and 100.";
|
||||
private const string sampleStringError =
|
||||
"The field SampleString must be a string or array type with a minimum length of '15'.";
|
||||
|
||||
[Fact]
|
||||
public async Task BadRequestResult_CanBeReturned()
|
||||
{
|
||||
|
|
@ -181,5 +187,97 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
Assert.Equal("http://localhost/foo/ActionResultsVerification/GetDummy/1", response.Headers.Location.OriginalString);
|
||||
Assert.Equal("{\"SampleInt\":10,\"SampleString\":\"Foo\"}", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://localhost/Home/Index",
|
||||
"application/json;charset=utf-8",
|
||||
"{\"test.SampleInt\":[\"" + sampleIntError + "\"]," +
|
||||
"\"test.SampleString\":" +
|
||||
"[\"" + sampleStringError + "\"]}")]
|
||||
[InlineData("http://localhost/Home/Index",
|
||||
"application/xml;charset=utf-8",
|
||||
"<Error><test.SampleInt>" + sampleIntError + "</test.SampleInt>" +
|
||||
"<test.SampleString>" + sampleStringError +
|
||||
"</test.SampleString></Error>")]
|
||||
[InlineData("http://localhost/XmlSerializer/GetSerializableError",
|
||||
"application/xml;charset=utf-8",
|
||||
"<Error><test.SampleInt>" + sampleIntError + "</test.SampleInt>" +
|
||||
"<test.SampleString>" + sampleStringError +
|
||||
"</test.SampleString></Error>")]
|
||||
public async Task SerializableErrorIsReturnedInExpectedFormat(string url, string outputFormat, string output)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<DummyClass xmlns=\"http://schemas.datacontract.org/2004/07/ActionResultsWebSite\">" +
|
||||
"<SampleInt>2</SampleInt><SampleString>foo</SampleString></DummyClass>";
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, url);
|
||||
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(outputFormat));
|
||||
request.Content = new StringContent(input, Encoding.UTF8, "application/xml");
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.Equal(output, await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SerializableError_CanSerializeNormalObjects()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<DummyClass xmlns=\"http://schemas.datacontract.org/2004/07/ActionResultsWebSite\">" +
|
||||
"<SampleInt>2</SampleInt><SampleString>foo</SampleString></DummyClass>";
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Home/GetCustomErrorObject");
|
||||
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json;charset=utf-8"));
|
||||
request.Content = new StringContent(input, Encoding.UTF8, "application/xml");
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.Equal("[\"Something went wrong with the model.\"]",
|
||||
await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SerializableError_ReadTheReturnedXml()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<DummyClass xmlns=\"http://schemas.datacontract.org/2004/07/ActionResultsWebSite\">" +
|
||||
"<SampleInt>20</SampleInt><SampleString>foo</SampleString></DummyClass>";
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Home/Index");
|
||||
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/xml;charset=utf-8"));
|
||||
request.Content = new StringContent(input, Encoding.UTF8, "application/xml");
|
||||
|
||||
// Act
|
||||
var response = await client.SendAsync(request);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Deserializing Xml content
|
||||
var serializer = new XmlSerializer(typeof(SerializableError));
|
||||
var errors = (SerializableError)serializer.Deserialize(
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(responseContent)));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
Assert.Equal(
|
||||
"<Error><test.SampleString>" + sampleStringError + "</test.SampleString></Error>",
|
||||
responseContent);
|
||||
Assert.Equal(sampleStringError, errors["test.SampleString"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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.AspNet.Mvc;
|
||||
|
||||
namespace ActionResultsWebSite
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index([FromBody] DummyClass test)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return Content("Hello World!");
|
||||
}
|
||||
|
||||
public IActionResult GetCustomErrorObject([FromBody] DummyClass test)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
errors.Add("Something went wrong with the model.");
|
||||
return new BadRequestObjectResult(errors);
|
||||
}
|
||||
|
||||
return Content("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ActionResultsWebSite
|
||||
{
|
||||
public class XmlSerializerController : Controller
|
||||
{
|
||||
public IActionResult GetSerializableError([FromBody] DummyClass test)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return HttpBadRequest(ModelState);
|
||||
}
|
||||
|
||||
return Content("Success!");
|
||||
}
|
||||
|
||||
public override void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
var result = context.Result as ObjectResult;
|
||||
if (result != null)
|
||||
{
|
||||
result.Formatters.Add(new XmlSerializerOutputFormatter());
|
||||
}
|
||||
|
||||
base.OnActionExecuted(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
|
@ -7,8 +7,10 @@ namespace ActionResultsWebSite
|
|||
{
|
||||
public class DummyClass
|
||||
{
|
||||
[Range(10, 100)]
|
||||
public int SampleInt { get; set; }
|
||||
|
||||
[MinLength(15)]
|
||||
public string SampleString { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue