From ce8d840cc6a6bb57d2fbaa751edc1c16df7e23f3 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 11 Dec 2014 10:09:42 -0800 Subject: [PATCH] Adding additional functional tests for ModelBinding --- .../ModelBindingTests.cs | 242 ++++++++++++++++++ ...Vehicle_PopulatesPropertyErrorsInViews.txt | 16 ++ ...alerVehicle_PopulatesValidationSummary.txt | 16 ++ .../UpdateDealerVehicle_UpdateSuccessful.txt | 24 ++ .../Controllers/VehicleController.cs | 54 ++++ .../Services/ILocationService.cs | 14 + .../Services/IVehicleService.cs | 12 + .../Services/LocationService.cs | 28 ++ .../Services/VehicleService.cs | 21 ++ test/WebSites/ModelBindingWebSite/Startup.cs | 13 +- .../ViewModels/DealerViewModel.cs | 22 ++ .../ViewModels/VehicleViewModel.cs | 50 ++++ .../ViewModels/VehicleWithDealerViewModel.cs | 39 +++ .../Views/Vehicle/UpdateSuccessful.cshtml | 26 ++ .../Views/Vehicle/UpdateVehicle.cshtml | 20 ++ 15 files changed, 589 insertions(+), 8 deletions(-) create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt create mode 100644 test/WebSites/ModelBindingWebSite/Controllers/VehicleController.cs create mode 100644 test/WebSites/ModelBindingWebSite/Services/ILocationService.cs create mode 100644 test/WebSites/ModelBindingWebSite/Services/IVehicleService.cs create mode 100644 test/WebSites/ModelBindingWebSite/Services/LocationService.cs create mode 100644 test/WebSites/ModelBindingWebSite/Services/VehicleService.cs create mode 100644 test/WebSites/ModelBindingWebSite/ViewModels/DealerViewModel.cs create mode 100644 test/WebSites/ModelBindingWebSite/ViewModels/VehicleViewModel.cs create mode 100644 test/WebSites/ModelBindingWebSite/ViewModels/VehicleWithDealerViewModel.cs create mode 100644 test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateSuccessful.cshtml create mode 100644 test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateVehicle.cshtml diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTests.cs index 952d278ad1..08db805e1e 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ModelBindingTests.cs @@ -7,11 +7,14 @@ using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Http; +using System.Net.Http.Headers; +using System.Reflection; using System.Text; using System.Threading.Tasks; using Microsoft.AspNet.Builder; using Microsoft.AspNet.TestHost; using ModelBindingWebSite; +using ModelBindingWebSite.ViewModels; using Newtonsoft.Json; using Xunit; @@ -1083,5 +1086,244 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests // Should Update all included properties. Assert.Equal("March", user.RegisterationMonth); } + + [Fact] + public async Task UpdateVehicle_WithJson_ProducesModelStateErrors() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var content = new + { + Year = 3012, + InspectedDates = new[] + { + new DateTime(4065, 10, 10) + }, + Make = "Volttrax", + Model = "Epsum" + }; + + // Act + var response = await client.PutAsJsonAsync("http://localhost/api/vehicles/520", content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + var modelStateErrors = JsonConvert.DeserializeObject>>(body); + + Assert.Equal(3, modelStateErrors.Count); + Assert.Equal(new[] { + "The field Year must be between 1980 and 2034.", + "Year is invalid" + }, modelStateErrors["model.Year"]); + + var vinError = Assert.Single(modelStateErrors["model.Vin"]); + Assert.Equal("The Vin field is required.", vinError); + + var trackingIdError = Assert.Single(modelStateErrors["X-TrackingId"]); + Assert.Equal("A value is required but was not present in the request.", trackingIdError); + } + + [Fact] + public async Task UpdateVehicle_WithJson_DoesPropertyValidationPriorToValidationAtType() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var content = new + { + Year = 2007, + InspectedDates = new[] + { + new DateTime(4065, 10, 10) + }, + Make = "Volttrax", + Model = "Epsum", + Vin = "Pqrs" + }; + client.DefaultRequestHeaders.TryAddWithoutValidation("X-TrackingId", "trackingid"); + + // Act + var response = await client.PutAsJsonAsync("http://localhost/api/vehicles/520", content); + + // Assert + Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + var modelStateErrors = JsonConvert.DeserializeObject>>(body); + + var item = Assert.Single(modelStateErrors); + Assert.Equal("model.InspectedDates", item.Key); + var error = Assert.Single(item.Value); + Assert.Equal("Inspection date cannot be later than year of manufacture.", error); + } + + [Fact] + public async Task UpdateVehicle_WithJson_BindsBodyAndServices() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var trackingId = Guid.NewGuid().ToString(); + var postedContent = new + { + Year = 2010, + InspectedDates = new List + { + new DateTime(2008, 10, 01), + new DateTime(2009, 03, 01), + }, + Make = "Volttrax", + Model = "Epsum", + Vin = "PQRS" + }; + client.DefaultRequestHeaders.TryAddWithoutValidation("X-TrackingId", trackingId); + + // Act + var response = await client.PutAsJsonAsync("http://localhost/api/vehicles/520", postedContent); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + var actual = JsonConvert.DeserializeObject(body); + + Assert.Equal(postedContent.Vin, actual.Vin); + Assert.Equal(postedContent.Make, actual.Make); + Assert.Equal(postedContent.InspectedDates, actual.InspectedDates.Select(d => d.DateTime)); + Assert.Equal(trackingId, actual.LastUpdatedTrackingId); + } + + [Fact] + public async Task UpdateVehicle_WithXml_BindsBodyServicesAndHeaders() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var trackingId = Guid.NewGuid().ToString(); + var postedContent = new VehicleViewModel + { + Year = 2010, + InspectedDates = new DateTimeOffset[] + { + new DateTimeOffset(2008, 10, 01, 8, 3, 1, TimeSpan.Zero), + new DateTime(2009, 03, 01), + }, + Make = "Volttrax", + Model = "Epsum", + Vin = "PQRS" + }; + client.DefaultRequestHeaders.TryAddWithoutValidation("X-TrackingId", trackingId); + + // Act + var response = await client.PutAsXmlAsync("http://localhost/api/vehicles/520", postedContent); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var body = await response.Content.ReadAsStringAsync(); + var actual = JsonConvert.DeserializeObject(body); + + Assert.Equal(postedContent.Vin, actual.Vin); + Assert.Equal(postedContent.Make, actual.Make); + Assert.Equal(postedContent.InspectedDates, actual.InspectedDates); + Assert.Equal(trackingId, actual.LastUpdatedTrackingId); + } + + // Simulates a browser based client that does a Ajax post for partial page updates. + [Fact] + public async Task UpdateDealerVehicle_PopulatesPropertyErrorsInViews() + { + // Arrange + var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync( + "compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt"); + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var postedContent = new + { + Year = 9001, + InspectedDates = new List + { + new DateTime(2008, 01, 01) + }, + Make = "Acme", + Model = "Epsum", + Vin = "LongerThan8Chars", + + }; + var url = "http://localhost/dealers/32/update-vehicle?dealer.name=TestCarDealer&dealer.location=SE"; + + // Act + var response = await client.PostAsJsonAsync(url, postedContent); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal(expectedContent, body); + } + + [Fact] + public async Task UpdateDealerVehicle_PopulatesValidationSummary() + { + // Arrange + var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync( + "compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt"); + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var postedContent = new + { + Year = 2013, + InspectedDates = new List + { + new DateTime(2008, 01, 01) + }, + Make = "Acme", + Model = "Epsum", + Vin = "8chars", + + }; + var url = "http://localhost/dealers/43/update-vehicle?dealer.name=TestCarDealer&dealer.location=SE"; + + // Act + var response = await client.PostAsJsonAsync(url, postedContent); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal(expectedContent, body); + } + + [Fact] + public async Task UpdateDealerVehicle_UsesDefaultValuesForOptionalProperties() + { + // Arrange + var expectedContent = await GetType().GetTypeInfo().Assembly.ReadResourceAsStringAsync( + "compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt"); + var server = TestServer.Create(_services, _app); + var client = server.CreateClient(); + var postedContent = new + { + Year = 2013, + InspectedDates = new DateTimeOffset[] + { + new DateTime(2008, 11, 01) + }, + Make = "RealSlowCars", + Model = "Epsum", + Vin = "8chars", + + }; + var url = "http://localhost/dealers/43/update-vehicle?dealer.name=TestCarDealer&dealer.location=NE"; + + // Act + var response = await client.PostAsJsonAsync(url, postedContent); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal(expectedContent, body); + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt new file mode 100644 index 0000000000..8802bb6ddb --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesPropertyErrorsInViews.txt @@ -0,0 +1,16 @@ +
+ TestCarDealer + SE + +
+
  • +
+
+ + The field Vin must be a string with a maximum length of 8. +
+
+ + The field Year must be between 1980 and 2034. +
+
\ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt new file mode 100644 index 0000000000..21edd0399d --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_PopulatesValidationSummary.txt @@ -0,0 +1,16 @@ +
+ TestCarDealer + SE + +
+
  • Make is invalid for region.
  • +
+
+ + +
+
+ + +
+
\ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt new file mode 100644 index 0000000000..afe01b1f2e --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/compiler/resources/UpdateDealerVehicle_UpdateSuccessful.txt @@ -0,0 +1,24 @@ +
+
    +
  • + Vin: 8chars +
  • +
  • + Inspected Dates: 11/1/2008 12:00:00 AM -07:00 +
  • +
+
+
+
    +
  • + Dealer: 43 +
  • +
  • + Phone: 999-99-0000 +
  • +
+
+ +
+Tracked by +
diff --git a/test/WebSites/ModelBindingWebSite/Controllers/VehicleController.cs b/test/WebSites/ModelBindingWebSite/Controllers/VehicleController.cs new file mode 100644 index 0000000000..b3b2575e55 --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Controllers/VehicleController.cs @@ -0,0 +1,54 @@ +// 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.Net; +using Microsoft.AspNet.Mvc; +using ModelBindingWebSite.Services; +using ModelBindingWebSite.ViewModels; + +namespace ModelBindingWebSite +{ + public class VehicleController : Controller + { + [HttpPut("/api/vehicles/{id}")] + [Produces("application/json")] + public object UpdateVehicleApi( + [Range(1, 500)] int id, + [FromBody] VehicleViewModel model, + [FromServices] IVehicleService service, + [FromHeader(Name = "X-TrackingId")] string trackingId) + { + if (!ModelState.IsValid) + { + return SerializeModelState(); + } + + service.Update(id, model, trackingId); + + return model; + } + + [HttpPost("/dealers/{dealer.id:int}/update-vehicle")] + public IActionResult UpdateDealerVehicle(VehicleWithDealerViewModel model) + { + if (!ModelState.IsValid) + { + return PartialView("UpdateVehicle", model); + } + + model.Update(); + return PartialView("UpdateSuccessful", model); + } + + public IDictionary> SerializeModelState() + { + Response.StatusCode = (int)HttpStatusCode.BadRequest; + + return ModelState.Where(item => item.Value.Errors.Count > 0) + .ToDictionary(item => item.Key, item => item.Value.Errors.Select(e => e.ErrorMessage)); + } + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/Services/ILocationService.cs b/test/WebSites/ModelBindingWebSite/Services/ILocationService.cs new file mode 100644 index 0000000000..b637ac72dd --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Services/ILocationService.cs @@ -0,0 +1,14 @@ +// 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 ModelBindingWebSite.ViewModels; + +namespace ModelBindingWebSite.Services +{ + public interface ILocationService + { + bool IsValidMakeForRegion(string make, string region); + + bool Update(VehicleWithDealerViewModel model); + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/Services/IVehicleService.cs b/test/WebSites/ModelBindingWebSite/Services/IVehicleService.cs new file mode 100644 index 0000000000..73f1b83772 --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Services/IVehicleService.cs @@ -0,0 +1,12 @@ +// 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 ModelBindingWebSite.ViewModels; + +namespace ModelBindingWebSite.Services +{ + public interface IVehicleService + { + void Update(int id, VehicleViewModel vehicle, string trackingId); + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/Services/LocationService.cs b/test/WebSites/ModelBindingWebSite/Services/LocationService.cs new file mode 100644 index 0000000000..46c8521bbc --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Services/LocationService.cs @@ -0,0 +1,28 @@ +// 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 ModelBindingWebSite.ViewModels; + +namespace ModelBindingWebSite.Services +{ + public class LocationService : ILocationService + { + public bool Update(VehicleWithDealerViewModel viewModel) + { + return true; + } + + public bool IsValidMakeForRegion(string make, string region) + { + switch (make) + { + case "Acme": + return region == "NW" || "region" == "South Central"; + case "FastCars": + return region != "Central"; + } + + return true; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/Services/VehicleService.cs b/test/WebSites/ModelBindingWebSite/Services/VehicleService.cs new file mode 100644 index 0000000000..b01f1ccb31 --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Services/VehicleService.cs @@ -0,0 +1,21 @@ +// 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; +using ModelBindingWebSite.ViewModels; + +namespace ModelBindingWebSite.Services +{ + public class VehicleService : IVehicleService + { + public void Update(int id, VehicleViewModel vehicle, string trackingId) + { + if (trackingId == null) + { + throw new ArgumentException(nameof(trackingId)); + } + + vehicle.LastUpdatedTrackingId = trackingId; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/Startup.cs b/test/WebSites/ModelBindingWebSite/Startup.cs index b3c8067032..6a4e37e113 100644 --- a/test/WebSites/ModelBindingWebSite/Startup.cs +++ b/test/WebSites/ModelBindingWebSite/Startup.cs @@ -3,9 +3,8 @@ using Microsoft.AspNet.Builder; using Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Routing; using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Logging; +using ModelBindingWebSite.Services; namespace ModelBindingWebSite { @@ -28,17 +27,15 @@ namespace ModelBindingWebSite services.AddSingleton(); services.AddSingleton(); + + services.AddTransient(); + services.AddTransient(); }); app.UseErrorReporter(); // Add MVC to the request pipeline - app.UseMvc(routes => - { - routes.MapRoute("ActionAsMethod", "{controller}/{action}", - defaults: new { controller = "Home", action = "Index" }); - - }); + app.UseMvc(); } } } diff --git a/test/WebSites/ModelBindingWebSite/ViewModels/DealerViewModel.cs b/test/WebSites/ModelBindingWebSite/ViewModels/DealerViewModel.cs new file mode 100644 index 0000000000..2936243c81 --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/ViewModels/DealerViewModel.cs @@ -0,0 +1,22 @@ +// 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.ComponentModel.DataAnnotations; + +namespace ModelBindingWebSite.ViewModels +{ + public class DealerViewModel + { + private const string DefaultCustomerServiceNumber = "999-99-0000"; + + public int Id { get; set; } + + public string Name { get; set; } + + [Required] + public string Location { get; set; } + + [DataType(DataType.PhoneNumber)] + public string Phone { get; set; } = DefaultCustomerServiceNumber; + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/ViewModels/VehicleViewModel.cs b/test/WebSites/ModelBindingWebSite/ViewModels/VehicleViewModel.cs new file mode 100644 index 0000000000..907ccbe7fb --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/ViewModels/VehicleViewModel.cs @@ -0,0 +1,50 @@ +// 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; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +namespace ModelBindingWebSite.ViewModels +{ + public class VehicleViewModel : IValidatableObject + { + [Required] + [StringLength(8)] + public string Vin { get; set; } + + public string Make { get; set; } + + public string Model { get; set; } + + [Range(1980, 2034)] + [CustomValidation(typeof(VehicleViewModel), nameof(ValidateYear))] + public int Year { get; set; } + + [Required] + [MaxLength(10)] + public DateTimeOffset[] InspectedDates { get; set; } + + public string LastUpdatedTrackingId { get; set; } + + public IEnumerable Validate(ValidationContext validationContext) + { + if (InspectedDates.Any(d => d.Year > Year)) + { + yield return new ValidationResult("Inspection date cannot be later than year of manufacture.", + new[] { nameof(InspectedDates) }); + } + } + + public static ValidationResult ValidateYear(int year) + { + if (year > DateTime.UtcNow.Year) + { + return new ValidationResult("Year is invalid"); + } + + return ValidationResult.Success; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/ViewModels/VehicleWithDealerViewModel.cs b/test/WebSites/ModelBindingWebSite/ViewModels/VehicleWithDealerViewModel.cs new file mode 100644 index 0000000000..951464ba0b --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/ViewModels/VehicleWithDealerViewModel.cs @@ -0,0 +1,39 @@ +// 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 Microsoft.AspNet.Mvc; +using ModelBindingWebSite.Services; + +namespace ModelBindingWebSite.ViewModels +{ + public class VehicleWithDealerViewModel : IValidatableObject + { + [Required] + public DealerViewModel Dealer { get; set; } + + [Required] + [FromBody] + public VehicleViewModel Vehicle { get; set; } + + [FromServices] + public ILocationService LocationService { get; set; } + + [FromHeader(Name = "X-TrackingId")] + public string TrackingId { get; set; } = "default-tracking-id"; + + public IEnumerable Validate(ValidationContext validationContext) + { + if (!LocationService.IsValidMakeForRegion(Vehicle.Make, Dealer.Location)) + { + yield return new ValidationResult("Make is invalid for region."); + } + } + + public void Update() + { + LocationService.Update(this); + } + } +} \ No newline at end of file diff --git a/test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateSuccessful.cshtml b/test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateSuccessful.cshtml new file mode 100644 index 0000000000..402b269619 --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateSuccessful.cshtml @@ -0,0 +1,26 @@ +@model ModelBindingWebSite.ViewModels.VehicleWithDealerViewModel + +
+
    +
  • + Vin: @Html.DisplayFor(m => m.Vehicle.Vin) +
  • +
  • + Inspected Dates: @Html.DisplayFor(m => m.Vehicle.InspectedDates) +
  • +
+
+
+
    +
  • + Dealer: @Html.DisplayFor(m => m.Dealer.Id) +
  • +
  • + Phone: @Html.DisplayFor(m => m.Dealer.Phone) +
  • +
+
+ +
+Tracked by @Model.TrackingId +
diff --git a/test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateVehicle.cshtml b/test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateVehicle.cshtml new file mode 100644 index 0000000000..d4bb27c707 --- /dev/null +++ b/test/WebSites/ModelBindingWebSite/Views/Vehicle/UpdateVehicle.cshtml @@ -0,0 +1,20 @@ +@model ModelBindingWebSite.ViewModels.VehicleWithDealerViewModel + +
+ @Model.Dealer.Name + @Model.Dealer.Location + @Html.HiddenFor(m => m.Dealer.Id) +
+@Html.ValidationSummary(excludePropertyErrors: true) +@using (Html.BeginForm()) +{ +
+ @Html.TextBoxFor(m => m.Vehicle.Vin) + @Html.ValidationMessageFor(m => m.Vehicle.Vin) +
+ +
+ @Html.EditorFor(m => m.Vehicle.Year) + @Html.ValidationMessageFor(m => m.Vehicle.Year) +
+} \ No newline at end of file