I have an ASP .Net Core 1.1 MVC web app. The app will be used by real estate agents to manage properties. The web app gets all it's data from a Web API. The web app has a page where a user can edit an existing property. The page has some simple textbox type
inputs, and a dropdown list to select the type of property (house, flat, simplex, duplex, office, shop, etc). So, it has:
These two models:
namespace InspectionsData.Models { [Table("property")] public class Property { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int? Id { get; set; } public string Street1 { get; set; } public string City { get; set; } public string Region { get; set; } public string Country { get; set; } public PropertyType PropertyType { get; set; } and namespace InspectionsData.Models { public partial class PropertyType { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string PropertyTypeName { get; set; } } }
A ModelView:
namespace InspectionsTestClient.ViewModels { public class PropertyIndexViewModel { public Property Property { get; set; } public List<PropertyType> PropertyTypes { get; set; } } }
a controller:
// GET: Property/Edit/5 public async Task<ActionResult> Edit(int id) { if (!ModelState.IsValid) { return BadRequest(ModelState); } string url = propertiesUrl + "/" + id.ToString(); HttpResponseMessage responseMessage = await client.GetAsync(url); if (responseMessage.IsSuccessStatusCode) { var responseData = responseMessage.Content.ReadAsStringAsync().Result; var @property = Newtonsoft.Json.JsonConvert.DeserializeObject<Property>(responseData); if (@property == null) { return NotFound(); } List<PropertyType> propertyTypes = null; url = apiUrl + "PropertyTypes"; responseMessage = await client.GetAsync(url); if (responseMessage.IsSuccessStatusCode) { responseData = responseMessage.Content.ReadAsStringAsync().Result; propertyTypes = Newtonsoft.Json.JsonConvert.DeserializeObject<List<PropertyType>>(responseData); } PropertyIndexViewModel vm = new PropertyIndexViewModel() { Property = @property, PropertyTypes = propertyTypes }; return View(vm); } return View("Error"); }
And a view:
@model InspectionsTestClient.ViewModels.PropertyIndexViewModel @{ ViewData["Title"] = "Edit"; } @{ Layout = "_Layout"; } <h2>Edit</h2> @Html.ValidationSummary(); <form asp-action="Edit"> <div class="form-horizontal"> <h4>Property</h4> <hr /> <div class="form-group"> <label asp-for="Property.Street" class="col-md-2 control-label"></label> <div class="col-md-10"> <input asp-for="Property.Street" class="form-control" /> <span asp-validation-for="Street" class="text-danger"></span> </div> </div> <div class="form-group"> <label asp-for="Property.City" class="col-md-2 control-label"></label> <div class="col-md-10"> <input asp-for="Property.City" class="form-control" /> <span asp-validation-for="City" class="text-danger"></span> </div> </div> <div class="form-group"> <label asp-for="Property.Region" class="col-md-2 control-label"></label> <div class="col-md-10"> <input asp-for="Property.Region" class="form-control" /> <span asp-validation-for="Region" class="text-danger"></span> </div> </div> <div class="form-group"> <label asp-for="Property.Country" class="col-md-2 control-label"></label> <div class="col-md-10"> <input asp-for="Property.Country" class="form-control" /> <span asp-validation-for="Country" class="text-danger"></span> </div> </div> <div class="form-group"> <label asp-for="Property.PropertyType" class="col-md-2 control-label"></label> <div class="col-md-10"> <input asp-for="Property.PropertyType" class="form-control" /> <span asp-validation-for="PropertyType" class="text-danger"></span> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Save" class="btn btn-default" /> </div> </div> </div> </form> <div> <a asp-action="Index">Back to List</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
Now, in my view, the PropertyType is still a text type input - not a dropdown. But that's ok, I will sort that out shortly (I'm taking one step at a time - I'm very new to web development).
Now, I don't know if I'm following the correct approach, but I have created a ViewModel so that I can feed the View both the Property object, as well as the List of PropertyTypes for the dropdown list, since the view needs both of these to work properly. I don't know if perhaps I should rather have a DTO that the Web Api returns that already has the property and list of property types in it (instead of making two separate calls to the web API to fetch each)? Or if perhaps the web app should request all the property types from the web API at startup and keep them cached as these won't be changing?
But be that as it may - for now, I'd like to try and figure out what I am doing wrong with my current (probably flawed) approach.
When I run the app, the controller works 100% and fetches all the data, but when the view fires up, I get this error:
Type expected + #pragma warning restore 1998 Type expected + #pragma warning restore 1998 Type expected + #pragma warning restore 1998 Type expected + #pragma warning restore 1998 Type expected + #pragma warning restore 1998 Type expected + #pragma warning restore 1998 'PropertyIndexViewModel' does not contain a definition for 'Street' and no extension method 'Street' accepting a first argument of type 'PropertyIndexViewModel' could be found (are you missing a using directive or an assembly reference?) + #pragma warning restore 1998 'PropertyIndexViewModel' does not contain a definition for 'City' and no extension method 'City' accepting a first argument of type 'PropertyIndexViewModel' could be found (are you missing a using directive or an assembly reference?) + #pragma warning restore 1998 'PropertyIndexViewModel' does not contain a definition for 'Region' and no extension method 'Region' accepting a first argument of type 'PropertyIndexViewModel' could be found (are you missing a using directive or an assembly reference?) + #pragma warning restore 1998 'PropertyIndexViewModel' does not contain a definition for 'Country' and no extension method 'Country' accepting a first argument of type 'PropertyIndexViewModel' could be found (are you missing a using directive or an assembly reference?) + #pragma warning restore 1998 'PropertyIndexViewModel' does not contain a definition for 'PropertyType' and no extension method 'PropertyType' accepting a first argument of type 'PropertyIndexViewModel' could be found (are you missing a using directive or an assembly reference?)
In my view, I am suspecting that I cannot do this:
<input type="hidden" asp-for="Property.Id" />
But I'm not sure how to reference the specific object in the ModelView... Any ideas?