Adding ApiController.Validate : Fixes #1286

This commit is contained in:
Harsh Gupta 2014-10-09 16:42:52 -07:00 committed by Ryan Nowak
parent 22869b41c0
commit 5a83383179
3 changed files with 131 additions and 0 deletions

View File

@ -7,6 +7,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.WebApiCompatShim;
using Microsoft.Framework.DependencyInjection;
namespace System.Web.Http
{
@ -83,6 +84,40 @@ namespace System.Web.Http
GC.SuppressFinalize(this);
}
/// <summary>
/// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>
/// under an empty prefix.
/// </summary>
/// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
/// <param name="entity">The entity being validated.</param>
public void Validate<TEntity>(TEntity entity)
{
Validate(entity, keyPrefix: string.Empty);
}
/// <summary>
/// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>.
/// </summary>
/// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
/// <param name="entity">The entity being validated.</param>
/// <param name="keyPrefix">
/// The key prefix under which the model state errors would be added in the
/// <see cref="ApiController.ModelState"/>.
/// </param>
public void Validate<TEntity>(TEntity entity, string keyPrefix)
{
var validator = Context.RequestServices.GetService<IBodyModelValidator>();
var metadataProvider = Context.RequestServices.GetService<IModelMetadataProvider>();
var modelMetadata = metadataProvider.GetMetadataForType(() => entity, typeof(TEntity));
var validatorProvider = Context.RequestServices.GetService<ICompositeModelValidatorProvider>();
var modelValidationContext = new ModelValidationContext(metadataProvider,
validatorProvider,
ModelState,
modelMetadata,
containerMetadata: null);
validator.Validate(modelValidationContext, keyPrefix);
}
protected virtual void Dispose(bool disposing)
{
}

View File

@ -81,6 +81,53 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(expected, formatters);
}
[Fact]
public async Task ApiController_CanValidateCustomObjectWithPrefix_Fails()
{
// Arrange
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
// Act
var response = await client.GetStringAsync(
"http://localhost/api/Blog/BasicApi/ValidateObjectWithPrefixFails?prefix=prefix");
// Assert
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
Assert.Equal(1, json.Count);
Assert.Equal("The field ID must be between 0 and 100.", json["prefix.ID"]);
}
[Fact]
public async Task ApiController_CanValidateCustomObject_IsSuccessFul()
{
// Arrange
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
// Act
var response = await client.GetStringAsync("http://localhost/api/Blog/BasicApi/ValidateObject_Passes");
// Assert
Assert.Equal("true", response);
}
[Fact]
public async Task ApiController_CanValidateCustomObject_Fails()
{
// Arrange
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
// Act
var response = await client.GetStringAsync("http://localhost/api/Blog/BasicApi/ValidateObjectFails");
// Assert
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
Assert.Equal(1, json.Count);
Assert.Equal("The field ID must be between 0 and 100.", json["ID"]);
}
[Fact]
public async Task ApiController_RequestProperty()
{

View File

@ -1,6 +1,8 @@
// 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 System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
@ -45,5 +47,52 @@ namespace WebApiCompatShimWebSite
{
return OptionsAccessor.Options.Formatters.Select(f => f.GetType().FullName).ToArray();
}
[HttpGet]
public bool ValidateObject_Passes()
{
var entity = new TestEntity { ID = 42 };
Validate(entity);
return ModelState.IsValid;
}
[HttpGet]
public object ValidateObjectFails()
{
var entity = new TestEntity { ID = -1 };
Validate(entity);
return CreateValidationDictionary();
}
[HttpGet]
public object ValidateObjectWithPrefixFails(string prefix)
{
var entity = new TestEntity { ID = -1 };
Validate(entity, prefix);
return CreateValidationDictionary();
}
private class TestEntity
{
[Range(0, 100)]
public int ID { get; set; }
}
private Dictionary<string, string> CreateValidationDictionary()
{
var result = new Dictionary<string, string>();
foreach (var item in ModelState)
{
var error = item.Value.Errors.SingleOrDefault();
if (error != null)
{
var value = error.Exception != null ? error.Exception.Message :
error.ErrorMessage;
result.Add(item.Key, value);
}
}
return result;
}
}
}