Fix for #1694 issue : Removed prefix for ModelState keys for FromBody parameters

This commit is contained in:
Kirthi Krishnamraju 2015-02-19 10:53:40 -08:00
parent 27bdec40a6
commit 2b246e7acc
9 changed files with 63 additions and 35 deletions

View File

@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
var unsupportedContentType = Resources.FormatUnsupportedContentType( var unsupportedContentType = Resources.FormatUnsupportedContentType(
bindingContext.OperationBindingContext.HttpContext.Request.ContentType); bindingContext.OperationBindingContext.HttpContext.Request.ContentType);
bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType); bindingContext.ModelState.AddModelError(bindingContext.ModelName, unsupportedContentType);
return new ModelBindingResult(null, bindingContext.ModelName, isModelSet: false); return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
} }
object model = null; object model = null;
@ -72,7 +72,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false); return new ModelBindingResult(model: null, key: bindingContext.ModelName, isModelSet: false);
} }
return new ModelBindingResult(model, bindingContext.ModelName, isModelSet: true); // key is empty to ensure that the model name is not used as a prefix for validation.
return new ModelBindingResult(model, key: string.Empty, isModelSet: true);
} }
private object GetDefaultValueForType(Type modelType) private object GetDefaultValueForType(Type modelType)

View File

@ -158,6 +158,38 @@ namespace Microsoft.AspNet.Mvc
Assert.Equal("Your input is bad!", errorMessage); Assert.Equal("Your input is bad!", errorMessage);
} }
[Fact]
public async Task NullFormatterError_AddedToModelState()
{
// Arrange
var httpContext = new DefaultHttpContext();
httpContext.Request.ContentType = "text/xyz";
var provider = new TestModelMetadataProvider();
provider.ForType<Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);
var bindingContext = GetBindingContext(
typeof(Person),
inputFormatter: null,
httpContext: httpContext,
metadataProvider: provider);
var binder = bindingContext.OperationBindingContext.ModelBinder;
// Act
var binderResult = await binder.BindModelAsync(bindingContext);
// Assert
// Returns true because it understands the metadata type.
Assert.NotNull(binderResult);
Assert.False(binderResult.IsModelSet);
Assert.Null(binderResult.Model);
Assert.True(bindingContext.ModelState.ContainsKey("someName"));
var errorMessage = bindingContext.ModelState["someName"].Errors[0].ErrorMessage;
Assert.Equal("Unsupported content type 'text/xyz'.", errorMessage);
}
private static ModelBindingContext GetBindingContext( private static ModelBindingContext GetBindingContext(
Type modelType, Type modelType,
IInputFormatter inputFormatter = null, IInputFormatter inputFormatter = null,

View File

@ -60,8 +60,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
"<Employee xmlns=\"http://schemas.datacontract.org/2004/07/FormatterWebSite\">" + "<Employee xmlns=\"http://schemas.datacontract.org/2004/07/FormatterWebSite\">" +
"<Id>2</Id><Name>foo</Name></Employee>"; "<Id>2</Id><Name>foo</Name></Employee>";
var expectedOutput = "{\"employee.Id\":[\"The field Id must be between 10 and 100." + var expectedOutput = "{\"Id\":[\"The field Id must be between 10 and 100." +
"\"],\"employee.Name\":[\"The field Name must be a string or array type with" + "\"],\"Name\":[\"The field Name must be a string or array type with" +
" a minimum length of '15'.\"]}"; " a minimum length of '15'.\"]}";
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));

View File

@ -1139,9 +1139,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(new[] { Assert.Equal(new[] {
"The field Year must be between 1980 and 2034.", "The field Year must be between 1980 and 2034.",
"Year is invalid" "Year is invalid"
}, modelStateErrors["model.Year"]); }, modelStateErrors["Year"]);
var vinError = Assert.Single(modelStateErrors["model.Vin"]); var vinError = Assert.Single(modelStateErrors["Vin"]);
Assert.Equal("The Vin field is required.", vinError); Assert.Equal("The Vin field is required.", vinError);
} }
@ -1174,7 +1174,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var modelStateErrors = JsonConvert.DeserializeObject<IDictionary<string, IEnumerable<string>>>(body); var modelStateErrors = JsonConvert.DeserializeObject<IDictionary<string, IEnumerable<string>>>(body);
var item = Assert.Single(modelStateErrors); var item = Assert.Single(modelStateErrors);
Assert.Equal("model.InspectedDates", item.Key); Assert.Equal("InspectedDates", item.Key);
var error = Assert.Single(item.Value); var error = Assert.Single(item.Value);
Assert.Equal("Inspection date cannot be later than year of manufacture.", error); Assert.Equal("Inspection date cannot be later than year of manufacture.", error);
} }
@ -1772,14 +1772,14 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
new[] new[]
{ {
":Required property 'Id' not found in JSON", ":Required property 'Id' not found in JSON",
"rectangle.Lines:The Lines field is required." "Lines:The Lines field is required."
} }
}, },
{ {
"{\"Id\":10}", "{\"Id\":10}",
new[] new[]
{ {
"rectangle.Lines:The Lines field is required." "Lines:The Lines field is required."
} }
}, },
{ {

View File

@ -58,12 +58,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body); var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(6, json.Count); Assert.Equal(6, json.Count);
Assert.Equal("CompanyName cannot be null or empty.", json["product.CompanyName"]); Assert.Equal("CompanyName cannot be null or empty.", json["CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["product.Price"]); Assert.Equal("The field Price must be between 20 and 100.", json["Price"]);
Assert.Equal("The Category field is required.", json["product.Category"]); Assert.Equal("The Category field is required.", json["Category"]);
Assert.Equal("The Contact Us field is required.", json["product.Contact"]); Assert.Equal("The Contact Us field is required.", json["Contact"]);
Assert.Equal("The Detail2 field is required.", json["product.ProductDetails.Detail2"]); Assert.Equal("The Detail2 field is required.", json["ProductDetails.Detail2"]);
Assert.Equal("The Detail3 field is required.", json["product.ProductDetails.Detail3"]); Assert.Equal("The Detail3 field is required.", json["ProductDetails.Detail3"]);
} }
[Fact] [Fact]
@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body); var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count); Assert.Equal(1, json.Count);
Assert.Equal("The ProductDetails field is required.", json["product.ProductDetails"]); Assert.Equal("The ProductDetails field is required.", json["ProductDetails"]);
} }
[Fact] [Fact]
@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body); var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count); Assert.Equal(1, json.Count);
Assert.Equal("Product must be made in the USA if it is not named.", json["product"]); Assert.Equal("Product must be made in the USA if it is not named.", json[""]);
} }
[Fact] [Fact]
@ -152,8 +152,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body); var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(2, json.Count); Assert.Equal(2, json.Count);
Assert.Equal("The field Price must be between 100 and 200.", json["software.Price"]); Assert.Equal("The field Price must be between 100 and 200.", json["Price"]);
Assert.Equal("The field Contact must be a string with a maximum length of 10.", json["software.Contact"]); Assert.Equal("The field Contact must be a string with a maximum length of 10.", json["Contact"]);
} }
[Fact] [Fact]
@ -176,7 +176,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body); var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count); Assert.Equal(1, json.Count);
Assert.Equal("Product must be made in the USA if it is not named.", json["software"]); Assert.Equal("Product must be made in the USA if it is not named.", json[""]);
} }
} }
} }

View File

@ -82,9 +82,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + var input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<Employee xmlns=\"http://schemas.datacontract.org/2004/07/XmlFormattersWebSite.Models\">" + "<Employee xmlns=\"http://schemas.datacontract.org/2004/07/XmlFormattersWebSite.Models\">" +
"<Id>2</Id><Name>foo</Name></Employee>"; "<Id>2</Id><Name>foo</Name></Employee>";
var expected = "<Error><employee.Id>The field Id must be between 10 and 100.</employee.Id>" + var expected = "<Error><Id>The field Id must be between 10 and 100.</Id>" +
"<employee.Name>The field Name must be a string or array type with a minimum " + "<Name>The field Name must be a string or array type with a minimum " +
"length of '15'.</employee.Name></Error>"; "length of '15'.</Name></Error>";
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee"); var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee");
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(acceptHeader)); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(acceptHeader));
request.Content = new StringContent(input, Encoding.UTF8, "application/xml-dcs"); request.Content = new StringContent(input, Encoding.UTF8, "application/xml-dcs");

View File

@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Arrange // Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient(); var client = server.CreateClient();
var input = "{ \"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", "+ var input = "{ \"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", " +
"\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}"; "\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}";
var content = new StringContent(input, Encoding.UTF8, "application/json"); var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = var url =
@ -39,12 +39,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
// Assert // Assert
var body = await response.Content.ReadAsStringAsync(); var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body); var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(8, json.Count); Assert.Equal(4, json.Count);
Assert.Equal("CompanyName cannot be null or empty.", json["product.CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["product.Price"]);
Assert.Equal("The Category field is required.", json["product.Category"]);
Assert.Equal("The field Contact Us must be a string with a maximum length of 20." +
"The field Contact Us must match the regular expression '^[0-9]*$'.", json["product.Contact"]);
Assert.Equal("CompanyName cannot be null or empty.", json["CompanyName"]); Assert.Equal("CompanyName cannot be null or empty.", json["CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["Price"]); Assert.Equal("The field Price must be between 20 and 100.", json["Price"]);
Assert.Equal("The Category field is required.", json["Category"]); Assert.Equal("The Category field is required.", json["Category"]);

View File

@ -118,7 +118,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
{ {
return string.Format(errorMessageFormat, kvp.Key, kvp.Value); return string.Format(errorMessageFormat, kvp.Key, kvp.Value);
}).ToList(); }).ToList();
expectedErrorMessages.Add("store.Address:The Address field is required."); expectedErrorMessages.Add("Address:The Address field is required.");
// Act // Act
var response = await client.PostAsync("http://localhost/Validation/CreateStore", content); var response = await client.PostAsync("http://localhost/Validation/CreateStore", content);

View File

@ -15,10 +15,10 @@ namespace FormatterWebSite
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)
{ {
return Content(ModelState["user.Id"].Errors[0].ErrorMessage + "," + return Content(ModelState["Id"].Errors[0].ErrorMessage + "," +
ModelState["user.Name"].Errors[0].ErrorMessage + "," + ModelState["Name"].Errors[0].ErrorMessage + "," +
ModelState["user.Alias"].Errors[0].ErrorMessage + "," + ModelState["Alias"].Errors[0].ErrorMessage + "," +
ModelState["user.Designation"].Errors[0].ErrorMessage); ModelState["Designation"].Errors[0].ErrorMessage);
} }
return Content("User has been registerd : " + user.Name); return Content("User has been registerd : " + user.Name);