使用AJAX提交部分页面时出错

时间:2014-05-19 10:01:54

标签: c# ajax asp.net-mvc asp.net-mvc-4

最近,我经常会遇到在dev中工作但在生产中没有的错误,这就是其中之一。使用AJAX提交部分页面时,我遇到了错误" 500内部服务器错误" 。 Firebug捕获的细节:

异常详情

    控制器:TimeKeeper
    行动:编辑
    消息:没有类型' IEnumerable< SelectListItem>'有关键' StateID'。
    StackTrace:

Exception:    at System.Web.Mvc.Html.SelectExtensions.GetSelectData(HtmlHelper htmlHelper, String name)
   at System.Web.Mvc.Html.SelectExtensions.SelectInternal(HtmlHelper htmlHelper, ModelMetadata metadata, String optionLabel, String name, IEnumerable`1 selectList, Boolean allowMultiple, IDictionary`2 htmlAttributes)
   at System.Web.Mvc.Html.SelectExtensions.DropDownList(HtmlHelper htmlHelper, String name, IEnumerable`1 selectList, String optionLabel, Object htmlAttributes)
   at ASP._Page_Views_TimeKeeper__Edit_cshtml.Execute() in c:\inetpub\wwwroot\[appname]\Views\TimeKeeper\_Edit.cshtml:line 64
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy()
   at System.Web.Mvc.WebViewPage.ExecutePageHierarchy()
   at System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage)
   at System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance)
   at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
   at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilterRecursive(IList`1 filters, Int32 filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<>c__DisplayClass2b.<BeginInvokeAction>b__1c()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass21.<BeginInvokeAction>b__1e(IAsyncResult asyncResult)

_Edit.cshtml(部分):

@model appname.ViewModels.TimeKeeperEditViewModel

<link href="@Url.Content("~/Content/datepicker.css")" rel="stylesheet" type="text/css" />
<link href="@Url.Content("~/Content/datepicker3.css")" rel="stylesheet" type="text/css" />

<div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
    <h4 class="modal-title" id="myModalLabel">Edit Time Keeper</h4>
</div>

@using (Ajax.BeginForm("Edit", "TimeKeeper",
    new AjaxOptions
    {
        InsertionMode = InsertionMode.Replace,
        HttpMethod = "POST",
        OnComplete = "editTimeKeeperComplete",
        UpdateTargetId = "timeKeeperList"
    }))
{
    @Html.ValidationSummary(true)
    @Html.HiddenFor(model => model.TimeKeeperID)
    @Html.HiddenFor(model => model.BillingID)

    <div class="modal-body">
        <div class="form-horizontal">
            <div class="form-group">
                <div class="col-md-4">
                    <label for="billingRate" class="control-label">Billing Rate</label>
                </div>
                <div class="col-md-8">
                    @Html.EditorFor(model => model.BillingRate, new { htmlAttributes = new { @class = "form-control" } })
                </div>
            </div>
            <div class="form-group">
                <div class="col-md-4">
                    <label for="billingStartDate" class="control-label">Billing Start Date</label>
                </div>
                <div class="col-md-8">
                    @Html.EditorFor(model => model.BillingStartDate, new { htmlAttributes = new { @class = "form-control", @readonly = "readonly" } })
                </div>
            </div>
            <div class="form-group">
                <div class="col-md-4">
                    <label for="status" class="control-label">Status</label>
                </div>
                <div class="col-md-8">
                    @Html.DropDownList("StateID", null, String.Empty, new { @class = "form-control" })
                </div>
            </div>
        </div>
    </div>

    <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal" id="btnClose">Close</button>
        <button type="submit" class="btn btn-primary" id="btnSave">Save changes</button>
    </div>
}

<script type="text/javascript">
    $(document).ready(function () {
        $("#BillingStartDate").datepicker({
            format: "dd/mm/yyyy",
            todayBtn: "linked",
            autoclose: true,
            todayHighlight: true
        });
    });
</script>

此代码用于填充StateID:

private void PopulateStateDropDownList(object selectedState = null)
        {
            var statesQuery = from s in db.States
                              where s.RowStatus == true && s.StateGroupID == 1
                              orderby s.Name
                              select new
                              {
                                  StateID = s.StateID,
                                  Name = s.Name
                              };

            ViewBag.StateID = new SelectList(statesQuery, "StateID", "Name", selectedState);
        }

邮政编码:

[HttpPost]
        public ActionResult Edit(TimeKeeperEditViewModel timeKeeperEditVM)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    LogHelper.logger.Info("Model Valid");
                    TimeKeeper timeKeeper = db.TimeKeepers.Find(timeKeeperEditVM.TimeKeeperID);
                    timeKeeper.BillingRate = timeKeeperEditVM.BillingRate;
                    timeKeeper.BillingStartDate = timeKeeperEditVM.BillingStartDate;
                    timeKeeper.BillingEndDate = timeKeeperEditVM.BillingEndDate;
                    timeKeeper.StateID = timeKeeperEditVM.StateID;

                    LogHelper.logger.Info("Save");
                    db.Entry(timeKeeper).State = EntityState.Modified;
                    db.SaveChanges();

                    LogHelper.logger.Info("Get Timekeepers");
                    Billing billing = db.Billings.Find(timeKeeperEditVM.BillingID);
                    BillingTimeKeeperViewModel billingVM = new BillingTimeKeeperViewModel()
                    {
                        BillingID = billing.BillingID,
                        TimeKeepers = billing.TimeKeepers
                    };

                    LogHelper.logger.Info("Return");
                    return PartialView("_List", billingVM.TimeKeepers);
                }
                else
                {
                    LogHelper.logger.Info("Model is not Valid");
                    return PartialView("_Edit");
                }
            }
            catch (Exception ex)
            {
                LogHelper.logger.Error(ex);
                return RedirectToAction("Index", "Error", ex);
            }
        }

我正在使用NLog来查看问题。没有错误,但ModelState.IsValid为假

更新

我在if (ModelState.IsValid)之前放置了日志以打印出BillingRate,BillingStartDate,BillingEndDate和StateID。如果我在2014年1月13日填写超过12天的日期,那么由BillingEndDate引起的是空的,但如果我填写12/1/2014,则ModelState.IsValid为真。

所以我的结论,它是由日期格式引起的。问题是我禁止更改服务器日期格式。有什么建议吗?

1 个答案:

答案 0 :(得分:0)

通过viewbag传递下拉列表通常很糟糕。我建议把它放到模型中

public List<SelectListItem> StateList { get; set; }

然后用数据库调用填充此列表

foreach(var temp in statesQuery){
    model.StateList.Add(new SelectListItem() { Text = temp.Name, Value = temp.StateID });
}

然后在您的视图中将您的下拉列表更改为

@Html.DropDownListFor(x => x.StateID, Model.StateList)

您可以通过设置model.StateID来设置控制器上的下拉菜单,下拉列表中的选定值将与回发后的该字段相关联