Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit 5a83383

Browse files
harshgMSFTrynowak
authored andcommitted
Adding ApiController.Validate : Fixes #1286
1 parent 22869b4 commit 5a83383

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.AspNet.Mvc;
88
using Microsoft.AspNet.Mvc.ModelBinding;
99
using Microsoft.AspNet.Mvc.WebApiCompatShim;
10+
using Microsoft.Framework.DependencyInjection;
1011

1112
namespace System.Web.Http
1213
{
@@ -83,6 +84,40 @@ public void Dispose()
8384
GC.SuppressFinalize(this);
8485
}
8586

87+
/// <summary>
88+
/// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>
89+
/// under an empty prefix.
90+
/// </summary>
91+
/// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
92+
/// <param name="entity">The entity being validated.</param>
93+
public void Validate<TEntity>(TEntity entity)
94+
{
95+
Validate(entity, keyPrefix: string.Empty);
96+
}
97+
98+
/// <summary>
99+
/// Validates the given entity and adds the validation errors to the <see cref="ApiController.ModelState"/>.
100+
/// </summary>
101+
/// <typeparam name="TEntity">The type of the entity to be validated.</typeparam>
102+
/// <param name="entity">The entity being validated.</param>
103+
/// <param name="keyPrefix">
104+
/// The key prefix under which the model state errors would be added in the
105+
/// <see cref="ApiController.ModelState"/>.
106+
/// </param>
107+
public void Validate<TEntity>(TEntity entity, string keyPrefix)
108+
{
109+
var validator = Context.RequestServices.GetService<IBodyModelValidator>();
110+
var metadataProvider = Context.RequestServices.GetService<IModelMetadataProvider>();
111+
var modelMetadata = metadataProvider.GetMetadataForType(() => entity, typeof(TEntity));
112+
var validatorProvider = Context.RequestServices.GetService<ICompositeModelValidatorProvider>();
113+
var modelValidationContext = new ModelValidationContext(metadataProvider,
114+
validatorProvider,
115+
ModelState,
116+
modelMetadata,
117+
containerMetadata: null);
118+
validator.Validate(modelValidationContext, keyPrefix);
119+
}
120+
86121
protected virtual void Dispose(bool disposing)
87122
{
88123
}

test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,53 @@ public async Task Options_SetsDefaultFormatters()
8181
Assert.Equal(expected, formatters);
8282
}
8383

84+
[Fact]
85+
public async Task ApiController_CanValidateCustomObjectWithPrefix_Fails()
86+
{
87+
// Arrange
88+
var server = TestServer.Create(_provider, _app);
89+
var client = server.CreateClient();
90+
91+
// Act
92+
var response = await client.GetStringAsync(
93+
"http://localhost/api/Blog/BasicApi/ValidateObjectWithPrefixFails?prefix=prefix");
94+
95+
// Assert
96+
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
97+
Assert.Equal(1, json.Count);
98+
Assert.Equal("The field ID must be between 0 and 100.", json["prefix.ID"]);
99+
}
100+
101+
[Fact]
102+
public async Task ApiController_CanValidateCustomObject_IsSuccessFul()
103+
{
104+
// Arrange
105+
var server = TestServer.Create(_provider, _app);
106+
var client = server.CreateClient();
107+
108+
// Act
109+
var response = await client.GetStringAsync("http://localhost/api/Blog/BasicApi/ValidateObject_Passes");
110+
111+
// Assert
112+
Assert.Equal("true", response);
113+
}
114+
115+
[Fact]
116+
public async Task ApiController_CanValidateCustomObject_Fails()
117+
{
118+
// Arrange
119+
var server = TestServer.Create(_provider, _app);
120+
var client = server.CreateClient();
121+
122+
// Act
123+
var response = await client.GetStringAsync("http://localhost/api/Blog/BasicApi/ValidateObjectFails");
124+
125+
// Assert
126+
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
127+
Assert.Equal(1, json.Count);
128+
Assert.Equal("The field ID must be between 0 and 100.", json["ID"]);
129+
}
130+
84131
[Fact]
85132
public async Task ApiController_RequestProperty()
86133
{

test/WebSites/WebApiCompatShimWebSite/Controllers/BasicApiController.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Collections.Generic;
5+
using System.ComponentModel.DataAnnotations;
46
using System.Linq;
57
using System.Threading.Tasks;
68
using System.Web.Http;
@@ -45,5 +47,52 @@ public string[] GetFormatters()
4547
{
4648
return OptionsAccessor.Options.Formatters.Select(f => f.GetType().FullName).ToArray();
4749
}
50+
51+
[HttpGet]
52+
public bool ValidateObject_Passes()
53+
{
54+
var entity = new TestEntity { ID = 42 };
55+
Validate(entity);
56+
return ModelState.IsValid;
57+
}
58+
59+
[HttpGet]
60+
public object ValidateObjectFails()
61+
{
62+
var entity = new TestEntity { ID = -1 };
63+
Validate(entity);
64+
return CreateValidationDictionary();
65+
}
66+
67+
[HttpGet]
68+
public object ValidateObjectWithPrefixFails(string prefix)
69+
{
70+
var entity = new TestEntity { ID = -1 };
71+
Validate(entity, prefix);
72+
return CreateValidationDictionary();
73+
}
74+
75+
private class TestEntity
76+
{
77+
[Range(0, 100)]
78+
public int ID { get; set; }
79+
}
80+
81+
private Dictionary<string, string> CreateValidationDictionary()
82+
{
83+
var result = new Dictionary<string, string>();
84+
foreach (var item in ModelState)
85+
{
86+
var error = item.Value.Errors.SingleOrDefault();
87+
if (error != null)
88+
{
89+
var value = error.Exception != null ? error.Exception.Message :
90+
error.ErrorMessage;
91+
result.Add(item.Key, value);
92+
}
93+
}
94+
95+
return result;
96+
}
4897
}
4998
}

0 commit comments

Comments
 (0)