Unable To populate view or view model Updaed - asp.net-web-api

Hi I am following up on this question here and working through a proof of concept for a SPA using our Company database data from a series of examples / articles Using Web API 2 with Entity Framework 6
Unfortunately, when I run the project I get this return
This feels like a failure to retrieve the data from the SQL Database (SQL Server 2008R2). However I am getting no error message, which I though I would, I know the data view is there as I have checked in SQL Management studio and in Server Explorer of Visual Studio 2017.
I am guessing though it could also be an error mapping my Data transfer Objects to my Knockout View Model or my Data bindings to my View.
When I try to look in Visual Studio 2017 I can not find(?) any problems, build errors nor the values of the objects (In the past I have been able to see the local values of objects in vs 2012 build WPF apps).
I could do with someone telling me the best debug steps and where I should be looking in visual studio 2017 to start tracking down these errors, I thought it was the Local tab but this is empty, see screen shot
In summary
1. What is the best way to trap this error
2. Can I find out what has been loaded into my Model and View Modal during run time?
3 If the answer to number 2 is yes, where should I be looking?
Here is my view code
#section scripts {
#Scripts.Render("~/bundles/app")
}
<div class="page-header">
<h1>Requistions Approval</h1>
</div>
<div class="row">
<div class="col-md-4">
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Requistions</h2>
</div>
<div class="panel-body">
<ul class="list-unstyled" data-bind="foreach: Requistions">
<li>
<strong><span data-bind="text: Requistion"></span></strong>
: <span data-bind="text: Line"></span>
: <span data-bind="text: ReqnValue"></span>
: <span data-bind="text: OrigName"></span>
: <span data-bind="text: LineReqnRaised"></span>
: <span data-bind="text: ReasonForReqn"></span>
: <span data-bind="text: GLDescription"></span>
<small>Details</small>
</li>
</ul>
</div>
</div>
<div class="alert alert-danger" data-bind="visible: error"><p data-bind="text: error"></p></div>
</div>
</div>
Here is my Controller code
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Description;
using Requestions_Api_POC.Models;
namespace Requestions_Api_POC.Controllers
{
public class RequistionsForApprovalsController : ApiController
{
private Requestions_Api_POCContext db = new Requestions_Api_POCContext();
// GET api/RequistionsForApprovals
public IQueryable<RequistionHeaderDTO> GetRequistionsForApprovals()
{
var Requistions = from b in db.RequistionsForApprovals
select new RequistionHeaderDTO()
{
ID = b.ID,
Requisition = b.Requisition,
ReqnValue = b.ReqnValue,
ApprovedValue = b.ApprovedValue,
OrigName = b.OrigName,
Line = b.Line,
LineReqnRaised = b.LineReqnRaised,
DueDate = b.DueDate,
ReasonForReqn = b.ReasonForReqn,
Supplier = b.Supplier,
GLDesc = b.GLDesc,
CurrentHolder = b.CurrentHolder,
CurName = b.CurName,
CurEmail = b.CurName,
HoldersRouteNum = b.HoldersRouteNum,
DateActioned = b.DateActioned,
DatabaseName = b.DatabaseName,
AdUser = b.AdUser,
ServerName = b.ServerName
};
return Requistions;
}
Here is my Data Transfer object
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Requestions_Api_POC.Models
{
public class RequistionHeaderDTO
{
public string ID { get; set; }
public string Requisition { get; set; }
public decimal? ReqnValue { get; set; }
public decimal? ApprovedValue { get; set; }
public string OrigName { get; set; }
public decimal Line { get; set; }
public System.DateTime? LineReqnRaised { get; set; }
public DateTime? DueDate { get; set; }
public string ReasonForReqn { get; set; }
public string Supplier { get; set; }
public string GLDesc { get; set; }
public string CurrentHolder { get; set; }
public string CurName { get; set; }
public string CurEmail { get; set; }
public decimal? HoldersRouteNum { get; set; }
public DateTime? DateActioned { get; set; }
public string DatabaseName { get; set; }
public string AdUser { get; set; }
public string ServerName { get; set; }
}
}
Many thanks

To help others.
The problem was as I was adapting the work through to Database first approach and I had not correctly created my model file
To help with debug on the running web app I posted a request to my Get API
api/RequistionsForApprovals
This returned a blank return, proving the problem was with my data reading not my knock out models and bindings. After reading up a bit more I thought I had not defined correctly the primary key of the EF model of my SQL view, therefore I needed to edit the edmx file as in the case here.
However I could not find my edmx file in my solution. Therefore I went through the process of adding a new item, Data, then choosing ADO.net Entity Data model. This created the mappings to my model class and a context which I was able to use with my controller
A bit of a simple mistake, but that is often the case when learning a new process!
Hope it helps anyone else

Related

returning null value from populated selectlist with DB data

I'm implementing asp.net core MVC project. In my controller class called ApiApplicant, Create method, I have 3 selectlists that its items should be populated from a table called APIApplicantHistory. My models and create method and view are implemented like following:
using System.Collections.Generic;
namespace CSDDashboard.Models
{
public partial class Apiapplicant
{
public Apiapplicant()
{
ApiApplicantHistory = new HashSet<ApiApplicantHistory>();
}
public int Id { get; set; }
public string ApiRequestDate { get; set; }
public int? ApiRequestNo { get; set; }
public int? Apiid { get; set; }
public int? ApplicantId { get; set; }
public int? GateId { get; set; }
public string NocRequestDate { get; set; }
public string NocRequestNo { get; set; }
public string Url { get; set; }
public string Description { get; set; }
public bool? IsDeleted { get; set; }
public virtual Api Api { get; set; }
public virtual Applicant Applicant { get; set; }
public virtual Gate Gate { get; set; }
public virtual ICollection<ApiApplicantHistory> ApiApplicantHistory { get; set; }
}
}
using System;
using System.Collections.Generic;
namespace CSDDashboard.Models
{
public partial class ApiApplicantHistory
{
public int Id { get; set; }
public int? ApiApplicantId { get; set; }
public string Date { get; set; }
public int? SentResponseType { get; set; }
public int? UnconfirmedReason { get; set; }
public int LastReqStatus { get; set; }
public string Description { get; set; }
public virtual Apiapplicant ApiApplicant { get; set; }
public virtual EntityType LastReqStatusNavigation { get; set; }
public virtual EntityType SentResponseTypeNavigation { get; set; }
public virtual EntityType UnconfirmedReasonNavigation { get; set; }
}
}
using System;
using System.Collections.Generic;
namespace CSDDashboard.Models
{
public partial class EntityType
{
public EntityType()
{
ApiApplicantHistoryLastReqStatusNavigation = new HashSet<ApiApplicantHistory>();
ApiApplicantHistorySentResponseTypeNavigation = new HashSet<ApiApplicantHistory>();
ApiApplicantHistoryUnconfirmedReasonNavigation = new HashSet<ApiApplicantHistory>();
}
public int Id { get; set; }
public string Name { get; set; }
public string EntityKey { get; set; }
public virtual ICollection<ApiApplicantHistory> ApiApplicantHistoryLastReqStatusNavigation { get; set; }
public virtual ICollection<ApiApplicantHistory> ApiApplicantHistorySentResponseTypeNavigation { get; set; }
public virtual ICollection<ApiApplicantHistory> ApiApplicantHistoryUnconfirmedReasonNavigation { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CSDDashboard.Models
{
public class APIApplicantViewModel
{
public Apiapplicant apiApplicantvm { get; set; }
public ApiApplicantHistory apiApplicantHistoryvm { get; set; }
}
}
public class ApiapplicantsController : Controller
{
private readonly CSSDDashboardContext _context;
public ApiapplicantsController(CSSDDashboardContext context)
{
_context = context;
}
public IActionResult Create()
{
ViewData["sentResponseType"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "sentResponseType").ToList(), "ID", "name");
ViewData["unconfirmedReason"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "unconfirmedReason").ToList(), "ID", "name");
ViewData["lastReqStatus"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "lastRequestStatus").ToList(), "ID", "name");
return View();
}
}
And a part of create view implementation:
#model CSDDashboard.Models.APIApplicantViewModel
#{
ViewData["Title"] = "create";
}
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="apiApplicantvm.GateId" class="control-label"></label>
<select asp-for="apiApplicantvm.GateId" class="form-control" asp-items="ViewBag.GateId"></select>
</div>
<div class="form-group">
<label asp-for="apiApplicantHistoryvm.SentResponseType" class="control-label"></label>
<select asp-for="apiApplicantHistoryvm.SentResponseType" class="form-control" asp-items="ViewBag.sentResponseType"></select>
</div>
<div class="form-group">
<label asp-for="apiApplicantHistoryvm.UnconfirmedReason" class="control-label"></label>
<select asp-for="apiApplicantHistoryvm.UnconfirmedReason" class="form-control" asp-items="ViewBag.unconfirmedReason"></select>
</div>
<div class="form-group">
<label asp-for="apiApplicantHistoryvm.LastReqStatus" class="control-label"></label>
<select asp-for="apiApplicantHistoryvm.LastReqStatus" class="form-control" asp-items="ViewBag.lastReqStatus"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
In create method, all the viewData are filled with the correct related data but the problem is existing in Create view, after running the project an error like below is shown in Create page:
An unhandled exception occurred while processing the request.
NullReferenceException: Object reference not set to an instance of an object.
After debugging the code I understand that In create view, apiApplicantvm is not null but apiApplicantHistoryvm returns null and the above error is because of that. I appreciate if anyone could tells me how to fix the problem.
I hope you would be using EF core as ORM because you are using Asp.net core.
To load related data in EF core.
It can be done in 2 ways or Lazy loading
Eager loading
_context.EntityType.Where(g=>g.EntityKey=="sentResponseType")
.Include(x=>x.ApiApplicantHistoryLastReqStatusNavigation).ToList()
OR
Lazy loading
on your modal creating
protected override void
OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder .UseLazyLoadingProxies() .UseSqlServer(myConnectionString);
OR
on startup.cs of your core MVC project
Lazy loading example.
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
for more info learn.microsoft.com/en-us/ef/core/querying/related-data
https://learn.microsoft.com/en-us/ef/core/querying/related-data
Thank you very much for the answers. I'm using EF core and I changed my code as what you suggested. I added ViewData["sentResponseType"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "sentResponseType")
.Include(x => x.ApiApplicantHistoryLastReqStatusNavigation).ToList(), "ID", "name");
in my create method.
And my problem is here in Create view, in the below line there exists a null value in apiApplicantHistoryvm:
Thank you for the help. The problem was here in my code
ViewData["sentResponseType"] = new SelectList(_context.EntityType.Where(g => g.EntityKey == "sentResponseType").ToList(), "ID", "name");
I should use Id instead of ID according to my EntityType model.

posting ASP.net MVC form having Kendoui widgets for ASP.net MVC

I am developing my ASp.net MVC application using Kendoui MVC extensions.
So In my form I have all the kendoui grid, dropdown, datepicker etc...
I have accumulated them all in my #using(Html.BeginForm ())
But I am not sure How do i post my form data to the controller. If anybody has done that could you please shre your experience.
For example:
I have two entities: Faculty and FacultyType in My DAL
public class Faculties
{
public int FacultyId { get; set; }
public string StaffNumber { get; set; }
public int FacultyTypeId { get; set; }
public virtual FacultyTypes FacultyTypes { get; set; }
}
public class FacultyTypes
{
public FacultyTypes()
{
this.Faculties = new List<Faculties>();
}
public int FacultyTypeId { get; set; }
public string FacultyTypeCode { get; set; }
public string FacultyType { get; set; }
public bool IsDefunct { get; set; }
public virtual ICollection<Faculties> Faculties { get; set; }
}
I have my ViewModels in my application:
public class ViewModelFaculty
{
public int FacultyId { get; set; }
public string StaffNumber { get; set; }
public ViewModelFacultyTypes FacultyType { get; set; }
}
public class ViewModelFacultyTypes
{
[ScaffoldColumn(false)]
public int FacultyTypeId { get; set; }
[Required(ErrorMessage ="Faculty Type Code is Required")]
public string FacultyTypeCode { get; set; }
[Required]
public string FacultyType { get; set; }
public bool IsDefunct { get; set; }
}
My View page having kendoui extensions for ASp.net MVC.
#model FMSApps.Models.ViewModelFaculty
#using(Html.BeginForm())
{
<fieldset>
<legend class="main">Personal Particulars</legend>
<div class="view-table">
<div class="view-row">
<div class="view-name"><label for="staffId">Staff ID</label></div>
<div class="view-name"><input id ="txtStaffId" name="StaffId" class="k-textbox" data-bind="value: StaffId" type="text" required /></div>
<div class="view-name"><label for="facultyType">Faculty Type</label></div>
<div class="view-name">
#(Html.Kendo().DropDownList()
.Name("ddFacultyType")
.DataTextField("FacultyType")
.DataValueField("FacultyTypeId")
.OptionLabel("Select Faculty Type")
.Enable(true)
.AutoBind(true)
.DataSource(ds =>
{
ds.Read(read =>
{
read.Action("GetFacultyTypes", "NewFaculty");
})
.ServerFiltering(true);
})
)
</div>
</div>
I am showing a part of my view as if I could post two fields then rest all will be of same logic.
So now when I submit my form I need to post the data in the form to controller.
I know it can be dne in ASp.net mvc html helpers but not sure how to do with kendoui, even kendoUi website as also not given any ened to end exaple of how to use the extensions in a form and how to post the data.
If anyone has been working in same enviorment or any direction on how to do please suggest me.
Let's say if you use
<input id ="txtStaffId" name="StaffId" class="k-textbox" data-bind="value: StaffId" type="text" required /></div>
#(Html.Kendo().DropDownList()
.Name("ddFacultyType")
.DataTextField("FacultyType")
.DataValueField("FacultyTypeId")
.OptionLabel("Select Faculty Type")
.Enable(true)
.AutoBind(true)
.DataSource(ds =>
{
ds.Read(read =>
{
read.Action("GetFacultyTypes", "NewFaculty");
})
.ServerFiltering(true);
})
)`
When a button with attribute is pressed on the page, the field on the form will then be post to the controller. Which means in this case, a field name 'txtStaffId' paired with input value & 'ddFacultyType' with the paired value(whichever you select on the list) will be send to the controller.

How to get data from two table or two class in single view in mvc3

How to get data from two table or two class in single view in mvc3.
I want to show data from both the table.
I have one parent class and two child class.
i.e
public class GetDocumentParent
{enter code here
public List getDocument { get; set; }
public List getDocumentRevision { get; set; }
}
View:
" %>
<% foreach (var item in Model.getDocument)
{ %>
<tr>
<td>
<%:Html.DisplayFor(ModelState => item.DOCUMENT_NAME)%>
</td>
<td>
<%:Html.DisplayFor(ModelState => item.ActiveDate)%>
</td>
<td>
<%:Html.DisplayFor(ModelState => item.Revision)%>
</td>
<td>
</tr>
<% } %>
==>item.DOCUMENT_NAME and item.ActiveDate from Document Class.
item.Revision from Document_Revision class.
how to show both class's value at the same time in view.
Controller:
var model = new GetDocumentParent
{
getDocument = db.Document.ToList(),
getDocumentRevision = db.DocumentRevisions.ToList()
};
return View(model);
Model:
1.
public class DOCUMENTS
{
public string DOCUMENT_NAME
{
get;
set;
}
public Nullable<System.DateTime> ActiveDate
{
get;
set;
}
}
2.
public class DOCUMENT_REVISIONS
{
public string REVISION
{
get;
set;
}
}
Thanks in advance
Always remember that it is best to have a view model that represents your data that is sent to the view. The view will do what is needed with you view model. The code below can guide you, you must just change it to fit into your scenario.
Lets say that I have a customer and each customer has only 1 address. I would create a view model called CustomerDetailsViewModel to represent this data:
public class CustomerDetailsViewModel
{
public string FirstName { get; set; }
public string Lastname { get; set; }
public int Age { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string City { get; set; }
}
Your action method to display the customer and customer address details:
public class CustomerController : Controller
{
private readonly ICustomerRepository customerRepository;
public CustomerController(ICustomerRepository customerRepository)
{
// Check customerRepository for nulls
this.customerRepository = customerRepository;
}
public ActionResult Details(int id)
{
// Check that id is not zero or negative
Customer customer = customerRepository.GetById(id);
// Get the customer's address
Address address = customerRepository.GetCustomerAddress(id);
CustomerDetailsViewModel viewModel = new CustomerDetailsViewModel()
{
FirstName = customer.Firstname,
LastName = customer.LastName,
Age = customer.Age,
AddressLine1 = address.AddressLine1,
AddressLine2 = address.AddressLine2,
City = address.City
}
return View(viewModel);
}
}
id above represents your customer's unique identifier. It is used to return a cusotmer:
Customer customer = customerRepository.GetById(id);
and also used to returned a specific customer's address:
Address address = customerRepository.GetCustomerAddress(id);
An ICustomerRepository instance is injected by an IoC container for example Autofac.
In your view you pass this view model as such and can display the data as you please:
#model MyProject.DomainModel.ViewModels.Customers.CustomerDetailsViewModel
<div class="content">
<div class="display-label">First Name: </div>
<div class="display-content">#Model.FirstName</div>
<div class="display-label">Last Name: </div>
<div class="display-content">#Model.LastName</div>
<div class="display-label">Age: </div>
<div class="display-content">#Model.Age</div>
<div class="display-label">Address Line 1: </div>
<div class="display-content">#Model.AddressLine1</div>
<div class="display-label">Address Line 2: </div>
<div class="display-content">#Model.AddressLine2</div>
<div class="display-label">City: </div>
<div class="display-content">#Model.City</div>
</div>
I hope this helps.
What is the problem?
use in controller:
var model = new GetDocumentParent();
model.getDocument = ...//Code that initialize getDocument
model.getDocumentRevision =...//Code that initialize getDocumentRevision
in View:
#Html.EditorFor(m=>m.getDocument);
#Html.EditorFor(m=>m.getDocumentRevision);

Model binding showing errors with adequate data being provided

I'm having an issue with a field being validated that seemingly is failing validation, but which has no requirements for being completed. I'll try to include all information, so apologies for such a lengthy question post!
The ViewModel that has been created is a DTO object which contains just enough information to action whatever data the user enters. Due to the unknown quantity of items, my view model is slightly more complex than would be ideal ...
public class UpdateViewModel
{
public UpdateViewModel()
{
WorkingPeriods = new List<WorkingPeriod>();
LeavePeriods = new List<LeavePeriod>();
}
public Guid UserID { get; set; }
public DateTime From { get; set; }
public DateTime Until { get; set; }
public DateTime Selected { get; set; }
public IEnumerable<WorkingPeriod> WorkingPeriods { get; set; }
public IEnumerable<LeavePeriod> LeavePeriods { get; set; }
public class WorkingPeriod
{
public int ID { get; set; }
public DateTime Date { get; set; }
public TimeSpan? StartTime { get; set; }
public TimeSpan? EndTime { get; set; }
}
public class LeavePeriod
{
public int ID { get; set; }
public DateTime Date { get; set; }
public int LeaveTypeID { get; set; }
public Guid? Reference { get; set; }
public string Period { get; set; }
public TimeSpan? UserDefinedPeriod { get; set; }
}
}
I've got a view that with the helper of a few static helpers is able to produce the HTML that represents the information being. The output HTML looks similar to:
<li class="editorRow">
<input type="hidden" name="LeavePeriods.index" autocomplete="off" value="8a5522c6-57fe-40a2-95bc-b9792fbe04d3" />
<input id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__ID" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].ID" type="hidden" value="4" />
<input id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__Date" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].Date" type="hidden" value="23/04/2012 00:00:00" />
<select class="leaveTypeDropdown" id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__LeaveTypeID" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].LeaveTypeID">
<option value="">- please select -</option>
<option selected="selected" value="2">Annual Leave</option>
<option value="34">Public Holiday</option>
<option value="1">Sickness</option>
</select>
<div class="leavePeriodRadio">
<input checked="checked" id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__ALL" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].Period" type="radio" value="ALL" /><label for="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__ALL">Full Day</label>
<input id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__AM" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].Period" type="radio" value="AM" /> <label for="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__AM">AM</label>
<input id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__PM" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].Period" type="radio" value="PM" /> <label for="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__PM">PM</label>
<input class="other-user-period" id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__Other" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].Period" type="radio" value="Other" /> <label for="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__Other">Other</label>
<span class="user-defined" style="display:none">
Duration: <input class="timepicker" id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__UserDefinedPeriod" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].UserDefinedPeriod" type="text" value="" />
</span>
</div>
</li>
The issue appears when a user submits the form using Ajax (set up via the Ajax.BeginForm construct) (MVC3 & JQuery are involved).
#using (Ajax.BeginForm("Index", "Timesheet", new AjaxOptions()
{
HttpMethod = "POST",
LoadingElementId = "loading",
UpdateTargetId = "contentPane",
OnComplete = "SaveCompleted",
}))
If the user omits the field (which they are perfectly entitled to do), they receive the message: The UserDefinedPeriod field is required..
Alternatively, if they enter a valid TimeSpan value (e.g. "12:00"), they get: The value '12:00' is not valid for UserDefinedPeriod..
If they enter an invalid string (e.g. "Boris"), the value is cleared and they are presented with the field required message above as if they had entered nothing. (Assumption: The value is cleared I believe because 'Boris' cannot be stored in a TimeSpan? and therefore cannot be transported back to the view)
Using breakpoints and inspecting the values of various things, I've concluded the following:
The value is present in Request.Form and can be seen with the others that are grouped with it.
The value is present within the Model and can be seen by inspecting it using the breakpoints in VS.
ModelState.IsValid is returning false because Model.LeavePeriods.UserDefinedPeriod has 1 error, which is the same as is displayed to the user in the end.
For reference, the Controller is:
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public class TimesheetController : Controller
{
[HttpPost]
public ActionResult Index(UpdateViewModel updates, User currentUser)
{
if (!ModelState.IsValid)
{
// error with model, so lets deal with it and return View();
}
// continue with parsing and saving.
}
}
The thing that confuses me the most about this issue is that I have other boxes that are built in similar ways that cause no issue - such as both of the TimeSpan?s within the WorkingPeriod enumerable. I'm running out of ideas as to where I can look to see what could be the issue. I've tried changing the ViewModel's expected value from a TimeSpan? to a normal string with no perceivable differences (even the error messages were identical).
I'm guessing that the issue lies either outside of the scope I've detailed below (though, the controller and model are relatively vanilla so I'm lost as to where else to look) or that there is something further I don't understand about model binding (and there is plenty I don't understand about model binding already!).
I've managed to solve this issue, but I'm not overly sure why what I've fixed, fixed it.
Basically, within the UpdateViewModel I changed the "UserDefinedPeriod" to be named "OtherPeriod".
public class LeavePeriod
{
public int ID { get; set; }
public DateTime Date { get; set; }
public int LeaveTypeID { get; set; }
public Guid? Reference { get; set; }
public string Period { get; set; }
public TimeSpan? OtherPeriod { get; set; }
}
Then obviously changed all code references to it elsewhere within my code, including the view:
<span class="user-defined" style="display:none">
Duration: <input class="timepicker" id="LeavePeriods_8a5522c6-57fe-40a2-95bc-b9792fbe04d3__OtherPeriod" name="LeavePeriods[8a5522c6-57fe-40a2-95bc-b9792fbe04d3].OtherPeriod" type="text" value="" />
</span>
This then seemed to fix the issue. I'm not sure what the specific reason for the change working was - so I'm open to any comments as to what may have caused it still. However, this tweak was the fix for me and may work for anyone else having this issue in the future.

asp.mvc3 #Html.DropDownListFor<> not working correctly

I have a strange issue with dropdown list in ASP.MVC3.
I have a view model that looks like this:
public class dto{
[Key]
public Int32 ClientID { get; set; }
[Required, MaxLength(50)]
public Name{get;set;}
public int ClientTypeID { get; set; }
public SelectList ClientTypes { get; set; }
}
Razor use:
<div class="editor-label">
#Html.LabelFor(model => model.ClientTypeID)
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.ClientTypeID,Model.ClientTypes)
</div>
In the controller i fill the ClientTypes with data.
When i use it to create a new dto object it works fine, and the selection is transfered back to controler and saved.
It also works fine when i use it to Edit an existing object, the proper value is selected when the page opens.
Problem is, when i change the selection, it does not get posted back to controler, while other edited values are returned correctly.
Can anyone point me in the direction of the problem?
thank You.
So, in my code I do something like this - in the ViewModel I've got an IEnumerable:
public IEnumerable<Choice> Choices { get; set; }
which gets populated back in the controller action.
and Choice looks something like
public class Choice
{
public int Id { get; set; }
public string Text { get; set; }
}
and in my ViewModel I've also got a member that looks like this:
public int TheChoice { get; set; }
and then in my View I've got something that looks like this:
#Html.DropDownListFor(model => model.TheChoice, new SelectList(Model.Choices, "Id", "Text", #Model.TheChoice))
and that seems to work pretty well.
Are you doing something differently that that?

Resources