[Codeplex #2162]: Nullable Enum support in Web API

This fix is to allow nullable enums as function paramters.
This commit is contained in:
Sam Xu 2014-10-28 19:16:38 +08:00
Родитель 8aee6c29e6
Коммит 9d9c57193b
3 изменённых файлов: 120 добавлений и 2 удалений

Просмотреть файл

@ -120,8 +120,13 @@ namespace System.Web.OData.Formatter
valueString = values[1];
}
if (type.IsNullable() && String.Equals(valueString, "null", StringComparison.Ordinal))
{
return null;
}
Type enumType = TypeHelper.GetUnderlyingTypeOrSelf(type);
object[] parameters = new[] { valueString, Enum.ToObject(type, 0) };
object[] parameters = new[] { valueString, Enum.ToObject(enumType, 0) };
bool isSuccessful = (bool)enumTryParseMethod.MakeGenericMethod(enumType).Invoke(null, parameters);
if (!isSuccessful)

Просмотреть файл

@ -8,6 +8,7 @@ using System.Web.OData.Extensions;
using System.Web.OData.Formatter;
using System.Web.OData.Formatter.Deserialization;
using System.Web.OData.Formatter.Serialization;
using System.Web.OData.Routing;
using Microsoft.OData.Core;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Library;
@ -114,6 +115,52 @@ namespace System.Web.OData
JsonAssert.Equal(Resources.EnumComplexType, content.ReadAsStringAsync().Result);
}
[Fact]
public void NullableEnumParameter_Works_WithNotNullEnumValue()
{
// Arrange
const string expect =
"{\r\n" +
" \"@odata.context\":\"http://localhost/odata/$metadata#Edm.Boolean\",\"value\":true\r\n" +
"}";
HttpConfiguration config = new[] { typeof(NullableEnumValueController) }.GetHttpConfiguration();
config.MapODataServiceRoute("odata", "odata", GetSampleModel());
HttpClient client = new HttpClient(new HttpServer(config));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get,
"http://localhost/odata/NullableEnumFunction(ColorParameter=System.Web.OData.Builder.TestModels.Color'Red')");
// Act
HttpResponseMessage respone = client.SendAsync(request).Result;
// Assert
Assert.Equal(expect, respone.Content.ReadAsStringAsync().Result);
}
[Fact]
public void NullableEnumParameter_Works_WithNullEnumValue()
{
// Arrange
const string expect =
"{\r\n" +
" \"@odata.context\":\"http://localhost/odata/$metadata#Edm.Boolean\",\"value\":false\r\n" +
"}";
HttpConfiguration config = new[] { typeof(NullableEnumValueController) }.GetHttpConfiguration();
config.MapODataServiceRoute("odata", "odata", GetSampleModel());
HttpClient client = new HttpClient(new HttpServer(config));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get,
"http://localhost/odata/NullableEnumFunction(ColorParameter=null)");
// Act
HttpResponseMessage respone = client.SendAsync(request).Result;
// Assert
Assert.Equal(expect, respone.Content.ReadAsStringAsync().Result);
}
private static ODataMediaTypeFormatter GetFormatter()
{
var formatter = new ODataMediaTypeFormatter(new ODataPayloadKind[] { ODataPayloadKind.Property })
@ -140,6 +187,10 @@ namespace System.Web.OData
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.ComplexType<EnumComplex>();
FunctionConfiguration function = builder.Function("NullableEnumFunction").Returns<bool>();
function.Parameter<Color?>("ColorParameter");
return builder.GetEdmModel();
}
@ -150,4 +201,21 @@ namespace System.Web.OData
public Color UndefinedColor { get; set; }
}
}
}
public class NullableEnumValueController : ODataController
{
[HttpGet]
[ODataRoute("NullableEnumFunction(ColorParameter={colorParameter})")]
[EnableQuery]
public bool NullableEnumFunction([FromODataUri]Color? colorParameter)
{
if (colorParameter != null)
{
return true;
}
Assert.True(ModelState.IsValid);
return false;
}
}
}

Просмотреть файл

@ -242,6 +242,36 @@ namespace System.Web.OData.Formatter
response.Content.ReadAsAsync(value.GetType(), configuration.Formatters).Result);
}
[Theory]
[InlineData(null, false)]
[InlineData(FlagsEnum.One, true)]
public void ODataModelBinderProvider_Works_ForNullableEnum(object value, bool expect)
{
// Arrange
HttpConfiguration configuration = new HttpConfiguration();
configuration.Services.Replace(typeof(ModelBinderProvider), new ODataModelBinderProvider());
configuration.MapODataServiceRoute("odata", "", GetEdmModel());
var controllers = new[] { typeof(ODataModelBinderProviderTestODataController) };
TestAssemblyResolver resolver = new TestAssemblyResolver(new MockAssembly(controllers));
configuration.Services.Replace(typeof(IAssembliesResolver), resolver);
HttpServer server = new HttpServer(configuration);
HttpClient client = new HttpClient(server);
// Act
string url = String.Format(
"http://localhost/GetNullableFlagsEnum(flagsEnum={0})",
value == null ? "null" : Uri.EscapeDataString(ConventionsHelpers.GetUriRepresentationForValue(value)));
HttpResponseMessage response = client.GetAsync(url).Result;
// Assert
response.EnsureSuccessStatusCode();
Assert.Equal(
expect,
response.Content.ReadAsAsync(typeof(bool), configuration.Formatters).Result);
}
[Theory]
[InlineData("abc", "GetEnum", "simpleEnum")]
public void ResourceIsNotFound_IfContainsInvalidEnum(object value, string action, string parameterName)
@ -282,6 +312,9 @@ namespace System.Web.OData.Formatter
getFlagsEnum.Parameter<FlagsEnum>("flagsEnum");
getFlagsEnum.Returns<FlagsEnum>();
FunctionConfiguration function = builder.Function("GetNullableFlagsEnum").Returns<bool>();
function.Parameter<FlagsEnum?>("flagsEnum");
return builder.GetEdmModel();
}
}
@ -488,5 +521,17 @@ namespace System.Web.OData.Formatter
return flagsEnum;
}
[HttpGet]
[ODataRoute("GetNullableFlagsEnum(flagsEnum={flagsEnum})")]
public bool GetNullableFlagsEnum(FlagsEnum? flagsEnum)
{
if (flagsEnum != null)
{
return true;
}
Assert.True(ModelState.IsValid);
return false;
}
}
}