Note that there are some explanatory texts on larger screens.

plurals
  1. POMVC3 - passing null item when model requires TimeSpan
    primarykey
    data
    text
    <p>Well I've recently come up against an interesting problem that I can't seem to figure out.</p> <p>The error message I get is:</p> <pre><code>{"The model item passed into the dictionary is null, but this dictionary requires a non-null model item of type 'System.TimeSpan'."} </code></pre> <p>This occurs when I try to submit a new entry to the database. So, the details of what is being submitted.</p> <p>The model class:</p> <pre><code>public class EventModel { [Key] public int EventID { get; set; } [DisplayName("Booking title")] [Required(ErrorMessage="Please provide a title for the booking")] public string Title { get; set; } [DataType(DataType.Date)] [DisplayName("Start date")] [DisplayFormat(DataFormatString="{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateTime StartDateTime { get; set; } [DisplayName("End date")] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] [IsDateAfter("StartDateTime", true, ErrorMessage="End date must be on or after the start date")] public DateTime EndDateTime { get; set; } public long StartTicks { get; set; } public long EndTicks { get; set; } [NotMapped] [DisplayName("Start Time")] public TimeSpan StartTime { get { return TimeSpan.FromTicks(StartTicks); } set { StartTicks = value.Ticks; } } [NotMapped] [DisplayName("End Time")] public TimeSpan EndTime { get { return TimeSpan.FromTicks(EndTicks); } set { EndTicks = value.Ticks; } } [DefaultValue(2)] [DisplayName("Booking is")] public int BookingStatus { get; set; } [DisplayName("Set recurrence")] [DefaultValue(false)] public bool DoesRecur { get; set; } [DisplayName("Set recurrence type")] public string Pattern { get; set; } [DisplayName("Set the day this happens on ")] public int DayIndex { get; set; } [DisplayName("Choose the day instance this recurs on")] public int DayCount { get; set; } [DisplayName("Day ")] [NotMapped] public string Day { get; set; } [DisplayName("Instance")] [NotMapped] public string Instance { get; set; } // links resource to a user/member [DisplayName("Booked by")] [NotMapped] public string BookerName { get; set; } public Guid MemberID { get; set; } // links resource to a resource type [DisplayName("Resource required:")] public int ResourceID { get; set; } } </code></pre> <p>The action methods in the controller class:</p> <pre><code>[HttpGet] public ActionResult Create(DateTime eventDate) { var days = from DayOfWeek d in Enum.GetValues(typeof(DayOfWeek)) select new { ID = (int) d, Name = (DayOfWeek)d }; var instance = from DayInstance i in Enum.GetValues(typeof(DayInstance)) select new { ID = (int) i, Name = (DayInstance)i }; MembershipUser mu = Membership.GetUser(HttpContext.Profile.UserName); CreateEventViewModel model = new CreateEventViewModel() { Event = new EventModel() { StartDateTime = eventDate, EndDateTime = eventDate, MemberID = (Guid)mu.ProviderUserKey }, Resources = DBContext.Resources.ToList(), Patterns = DBContext.Patterns.ToList(), ResourceTypes = DBContext.ResourceTypes.ToList() }; ViewData["dayOfWeek"] = new SelectList(days, "ID", "Name", DayOfWeek.Monday); ViewData["dayInstance"] = new SelectList(instance, "ID", "Name", DayInstance.First); return View(model); } [HttpPost] public ActionResult Create(CreateEventViewModel em) { if (ModelState.IsValid) { // get the resource turn aournd time double turnAround = rc.GetResourceTurnAround(em.Event.ResourceID); MembershipUser mu = Membership.GetUser(HttpContext.Profile.UserName); em.Event.MemberID = (Guid) mu.ProviderUserKey; em.Event.BookingStatus = 2; // need to get the time added to the date. DateTime actualStartPoint = new DateTime(em.Event.StartDateTime.Ticks + em.Event.StartTicks); DateTime actualEndPoint = new DateTime(em.Event.EndDateTime.Ticks + em.Event.EndTicks); em.Event.StartDateTime = actualStartPoint; em.Event.EndDateTime = actualEndPoint; // add turn around time to the end of the event em.Event.EndDateTime = em.Event.EndDateTime.AddMinutes(turnAround); // needed becase these are handled slighty differently to the rest of the model em.Event.DayIndex = int.Parse(Request.Form.GetValues("dayOfWeek").GetValue(0).ToString()); em.Event.DayCount = int.Parse(Request.Form.GetValues("dayInstance").GetValue(0).ToString()); DBContext.Events.Add(em.Event); DBContext.SaveChanges(); // get the resource owner MembershipUser resourceOwner = Membership.GetUser(rc.GetResourceOwnerByID(em.Event.ResourceID)); // email the admin team and the user the details of this booking // get the email address of the user making the booking StringBuilder message = new StringBuilder(); message.AppendFormat("Thank you for your booking, this is now being reviewed by the team.\nThe details of your booking are included for confirmation.\n"); message.AppendFormat("Booking Title: {0}\nResource: {1}\n Date: {2} {3} (this includes our turn around time added on)\n", em.Event.Title, rc.GetResourceNameByID(em.Event.ResourceID), actualStartPoint, actualEndPoint); message.AppendFormat("You can log in at any time to review your bookings.\nYou will receive an email when the team have reviewed this request\nMany thanks\n"); EmailHandler eh = new EmailHandler(); eh.SetRecipient(Membership.GetUser().Email); eh.AddAdminEmail(); eh.AddBcc(resourceOwner.Email); eh.SetSubject("Booking Requested"); eh.SetBody(message.ToString()); eh.sendMessage(); return RedirectToAction("Index"); } else { return View(); } } </code></pre> <p>Now for the view items - the main view:</p> <pre><code>@model AssetManager.Models.CreateEventViewModel @{ ViewBag.Title = "Create"; Layout = "~/Views/Shared/_Layout.cshtml"; } @using (Html.BeginForm()) { @Html.ValidationSummary(true) &lt;fieldset&gt; &lt;legend id="bookingLegend"&gt;Place Booking&lt;/legend&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.Title) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.EditorFor(model =&gt; model.Event.Title) @Html.ValidationMessageFor(model =&gt; model.Event.Title) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.StartDateTime) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.EditorFor(model =&gt; model.Event.StartDateTime, new { @class = "date" }) @Html.ValidationMessageFor(model =&gt; model.Event.StartDateTime) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label timeSelector"&gt; @Html.LabelFor(model =&gt; model.Event.StartTime) &lt;/div&gt; &lt;div class="editor-field timeSelector"&gt; @Html.EditorFor(model =&gt; model.Event.StartTime) @Html.ValidationMessageFor(model =&gt; model.Event.StartTime) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.EndDateTime) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.EditorFor(model =&gt; model.Event.EndDateTime, new { @class = "date" }) @Html.ValidationMessageFor(model =&gt; model.Event.EndDateTime) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label timeSelector"&gt; @Html.LabelFor(model =&gt; model.Event.EndTime) &lt;/div&gt; &lt;div class="editor-field timeSelector"&gt; @Html.EditorFor(model =&gt; model.Event.EndTime) @Html.ValidationMessageFor(model =&gt; model.Event.EndTime) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.Label("Select Resource Type") &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.DropDownList("ResourceTypes", new SelectList(Model.ResourceTypes, "ResourceTypeID", "Title"), "-- Select Resource Type --", new { @id = "ddlResourceTypes" }) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.ResourceID) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.DropDownListFor(model =&gt; model.Event.ResourceID, new SelectList(Enumerable.Empty&lt;SelectListItem&gt;(), "ResourceType", "Name"), "-- Select Resource --", new { @id = "ddlResources" }) @Html.ValidationMessageFor(model =&gt; model.Event.ResourceID) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.DoesRecur) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.EditorFor(model =&gt; model.Event.DoesRecur) @Html.ValidationMessageFor(model =&gt; model.Event.DoesRecur) &lt;/div&gt; &lt;/div&gt; &lt;div id="recurType" class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.Pattern) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.DropDownListFor(model =&gt; model.Event.Pattern, new SelectList(Model.Patterns, "PatternCode", "Pattern"), "-- Select Recurrence Pattern --") @Html.ValidationMessageFor(model =&gt; model.Event.Pattern) &lt;/div&gt; &lt;/div&gt; &lt;div id="recurDayHappens" class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.DayIndex) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.DropDownList("dayOfWeek") @Html.ValidationMessageFor(model =&gt; model.Event.DayIndex) &lt;/div&gt; &lt;/div&gt; &lt;div id="recurInstance" class="controlcontainer"&gt; &lt;div class="editor-label"&gt; @Html.LabelFor(model =&gt; model.Event.DayCount) &lt;/div&gt; &lt;div class="editor-field"&gt; @Html.DropDownList("dayInstance") @Html.ValidationMessageFor(model =&gt; model.Event.DayCount) &lt;/div&gt; &lt;/div&gt; &lt;div class="controlcontainer"&gt; &lt;p&gt; &lt;input class="subButton" type="submit" value="Create" /&gt; &lt;input id="cancelBtn" class="cancelButton" type="button" value="Cancel" onclick="location.href='@Url.Action("Index", "Calendar")'" /&gt; &lt;/p&gt; &lt;/div&gt; &lt;/fieldset&gt; } </code></pre> <p>Then there is an editor template for the TimeSpan items:</p> <pre><code>@model TimeSpan @Html.DropDownList("Hours", Enumerable.Range(0, 24) .Select(i =&gt; new SelectListItem { Value = i.ToString(), Text = i.ToString(), Selected = Model.Hours == i }))&amp;nbsp;: @Html.DropDownList("Minutes", Enumerable.Range(0, 60) .Select(i =&gt; new SelectListItem { Value = i.ToString(), Text = i.ToString(), Selected = Model.Minutes == i })) </code></pre> <p>And finally a TimeBinder class:</p> <pre><code>public class TimeBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { // Ensure there's incomming data var key_hours = bindingContext.ModelName + ".Hours"; var valueProviderResult_hours = bindingContext.ValueProvider .GetValue(key_hours); var key_minutes = bindingContext.ModelName + ".Minutes"; var valueProviderResult_minutes = bindingContext.ValueProvider .GetValue(key_minutes); if (valueProviderResult_hours == null || string.IsNullOrEmpty(valueProviderResult_hours.AttemptedValue) || valueProviderResult_minutes == null || string.IsNullOrEmpty(valueProviderResult_minutes.AttemptedValue)) { return null; } // Preserve it in case we need to redisplay the form bindingContext.ModelState.SetModelValue(key_hours, valueProviderResult_hours); bindingContext.ModelState.SetModelValue(key_minutes, valueProviderResult_minutes); // Parse var hours = ((string[])valueProviderResult_hours.RawValue)[0]; var minutes = ((string[])valueProviderResult_minutes.RawValue)[0]; // A TimeSpan represents the time elapsed since midnight var time = new TimeSpan(Convert.ToInt32(hours), Convert.ToInt32(minutes), 0); return time; } } </code></pre> <p>That's it, that is all the code that is involved. I am completely baffled as to why this error occurs. Any ideas or suggestions as to the cause and the solution are greatly appreciated.</p> <p>Many thanks nathj07</p> <p><strong>EDIT</strong> Pk, so I tried something differnt with th TimeSpan editor template:</p> <pre><code>@model TimeSpan? @Html.DropDownList("Hours", Enumerable.Range(0, 24) .Select(i =&gt; new SelectListItem { Value = i.ToString(), Text = i.ToString(), Selected = Model.HasValue ? Model.Value.Hours == i : false }))&amp;nbsp;: @Html.DropDownList("Minutes", Enumerable.Range(0, 60) .Select(i =&gt; new SelectListItem { Value = i.ToString(), Text = i.ToString(), Selected = Model.HasValue ? Model.Value.Minutes == i : false })) </code></pre> <p>This seems to have overcome this error but now I get an issue a little further down. In the view there is a DropDownList("ResourceTypes"....) This is essentially a dropdownlist that is used to control what appears in the DropDownListFor(model=>model.Event.ResourceID.....) There is a simple piece of JavaScript:</p> <pre><code>$(document).ready(function () { $("#ddlResourceTypes").change(function () { var idResourceType = $('#ddlResourceTypes').val(); $.getJSON("/Resource/LoadResourcesByType", { id: idResourceType }, function (resourceData) { var select = $("#ddlResources"); select.empty(); select.append($('&lt;option/&gt;', { value: 0, text: "-- Select Resource --" })); $.each(resourceData, function (index, itemData) { select.append($('&lt;option/&gt;', { value: itemData.Value, text: itemData.Text })); }); }); }); }); </code></pre> <p>Now the issue I get is:</p> <p>Object reference not set to an instance of an object</p> <p>On the DropDownList("ResourceTypes".....)</p> <p>Any ideas on this one?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload