diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinders/BodyModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinders/BodyModelBinder.cs index a8a9352744..161d2a2675 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinders/BodyModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinders/BodyModelBinder.cs @@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding var unsupportedContentType = Resources.FormatUnsupportedContentType( bindingContext.OperationBindingContext.HttpContext.Request.ContentType); 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; @@ -72,7 +72,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding 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) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/BodyModelBinderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/BodyModelBinderTests.cs index cc7482add9..7b6f477e8e 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/BodyModelBinderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/BodyModelBinderTests.cs @@ -158,6 +158,38 @@ namespace Microsoft.AspNet.Mvc 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().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( Type modelType, IInputFormatter inputFormatter = null, diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonOutputFormatterTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonOutputFormatterTests.cs index 39e6fe1a82..44227b80f5 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonOutputFormatterTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/JsonOutputFormatterTests.cs @@ -60,8 +60,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests "" + "2foo"; - var expectedOutput = "{\"employee.Id\":[\"The field Id must be between 10 and 100." + - "\"],\"employee.Name\":[\"The field Name must be a string or array type with" + + var expectedOutput = "{\"Id\":[\"The field Id must be between 10 and 100." + + "\"],\"Name\":[\"The field Name must be a string or array type with" + " a minimum length of '15'.\"]}"; var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee"); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs index eac307abe7..06821e8825 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTest.cs @@ -1139,9 +1139,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests Assert.Equal(new[] { "The field Year must be between 1980 and 2034.", "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); } @@ -1174,7 +1174,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var modelStateErrors = JsonConvert.DeserializeObject>>(body); var item = Assert.Single(modelStateErrors); - Assert.Equal("model.InspectedDates", item.Key); + Assert.Equal("InspectedDates", item.Key); var error = Assert.Single(item.Value); Assert.Equal("Inspection date cannot be later than year of manufacture.", error); } @@ -1772,14 +1772,14 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests new[] { ":Required property 'Id' not found in JSON", - "rectangle.Lines:The Lines field is required." + "Lines:The Lines field is required." } }, { "{\"Id\":10}", new[] { - "rectangle.Lines:The Lines field is required." + "Lines:The Lines field is required." } }, { diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelMetadataAttributeTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelMetadataAttributeTest.cs index 5630bfe2cc..c75993584c 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelMetadataAttributeTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelMetadataAttributeTest.cs @@ -58,12 +58,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var body = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject>(body); Assert.Equal(6, 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 Contact Us field is required.", json["product.Contact"]); - Assert.Equal("The Detail2 field is required.", json["product.ProductDetails.Detail2"]); - Assert.Equal("The Detail3 field is required.", json["product.ProductDetails.Detail3"]); + 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 Category field is required.", json["Category"]); + Assert.Equal("The Contact Us field is required.", json["Contact"]); + Assert.Equal("The Detail2 field is required.", json["ProductDetails.Detail2"]); + Assert.Equal("The Detail3 field is required.", json["ProductDetails.Detail3"]); } [Fact] @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var body = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject>(body); 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] @@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var body = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject>(body); 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] @@ -152,8 +152,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var body = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject>(body); Assert.Equal(2, json.Count); - Assert.Equal("The field Price must be between 100 and 200.", json["software.Price"]); - Assert.Equal("The field Contact must be a string with a maximum length of 10.", json["software.Contact"]); + 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["Contact"]); } [Fact] @@ -176,7 +176,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var body = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject>(body); 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[""]); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/SerializableErrorTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/SerializableErrorTests.cs index 63a423e5bf..83a2d9d17d 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/SerializableErrorTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/SerializableErrorTests.cs @@ -82,9 +82,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests var input = "" + "" + "2foo"; - var expected = "The field Id must be between 10 and 100." + - "The field Name must be a string or array type with a minimum " + - "length of '15'."; + var expected = "The field Id must be between 10 and 100." + + "The field Name must be a string or array type with a minimum " + + "length of '15'."; var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/SerializableError/CreateEmployee"); request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse(acceptHeader)); request.Content = new StringContent(input, Encoding.UTF8, "application/xml-dcs"); diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/TryValidateModelTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/TryValidateModelTest.cs index bada3c6be5..831f119985 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/TryValidateModelTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/TryValidateModelTest.cs @@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Arrange var server = TestHelper.CreateServer(_app, SiteName, _configureServices); var client = server.CreateClient(); - var input = "{ \"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", "+ + var input = "{ \"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", " + "\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}"; var content = new StringContent(input, Encoding.UTF8, "application/json"); var url = @@ -39,12 +39,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Assert var body = await response.Content.ReadAsStringAsync(); var json = JsonConvert.DeserializeObject>(body); - Assert.Equal(8, 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(4, json.Count); 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 Category field is required.", json["Category"]); diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs index 31a8e8ca92..749620ffc1 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/XmlDataContractSerializerInputFormatterTest.cs @@ -118,7 +118,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests { return string.Format(errorMessageFormat, kvp.Key, kvp.Value); }).ToList(); - expectedErrorMessages.Add("store.Address:The Address field is required."); + expectedErrorMessages.Add("Address:The Address field is required."); // Act var response = await client.PostAsync("http://localhost/Validation/CreateStore", content); diff --git a/test/WebSites/FormatterWebSite/Controllers/ValidationController.cs b/test/WebSites/FormatterWebSite/Controllers/ValidationController.cs index 29778035e9..e5a2a5dc84 100644 --- a/test/WebSites/FormatterWebSite/Controllers/ValidationController.cs +++ b/test/WebSites/FormatterWebSite/Controllers/ValidationController.cs @@ -15,10 +15,10 @@ namespace FormatterWebSite { if (!ModelState.IsValid) { - return Content(ModelState["user.Id"].Errors[0].ErrorMessage + "," + - ModelState["user.Name"].Errors[0].ErrorMessage + "," + - ModelState["user.Alias"].Errors[0].ErrorMessage + "," + - ModelState["user.Designation"].Errors[0].ErrorMessage); + return Content(ModelState["Id"].Errors[0].ErrorMessage + "," + + ModelState["Name"].Errors[0].ErrorMessage + "," + + ModelState["Alias"].Errors[0].ErrorMessage + "," + + ModelState["Designation"].Errors[0].ErrorMessage); } return Content("User has been registerd : " + user.Name);