问题
Am I the only one having this problem or I am doing it in totally wrong direction.
I have a View passing DateTime value:
<div class="control-group">
@Html.Label("Appointment date", null, new { @class = "control-label" })
<div class="controls">
<div class="input-append">
@Html.TextBoxFor(model => model.Appointment.Client_PreferredDate, new { @readonly = "readonly" })
<span class="add-on margin-fix"><i class="icon-th"></i></span>
</div>
<p class="help-block">
@Html.ValidationMessageFor(model => model.Appointment.Client_PreferredDate)
</p>
</div>
The values are passed into the Controller action ( I can see the value, and I know it is giving the format that is not DateTime, i.e. it is going to be in dd-MM-yyyy). Then in the Controller I will reformat it.
[HttpPost]
public ActionResult RequestAppointment(General_Enquiry model, FormCollection fc)
{
model.Appointment.Client_PreferredDate = Utilities.formatDate(fc["Appointment.Client_PreferredDate"]);
ModelState.Remove("Appointment.Client_PreferredDate");
try
{
if (ModelState.IsValid)
{
model.Branch_Id = Convert.ToInt32(fc["selectedBranch"]);
model.Appointment.Branch_Id = Convert.ToInt32(fc["selectedBranch"]);
db.General_Enquiry.AddObject(model);
db.SaveChanges();
return RedirectToAction("AppointmentSuccess", "Client");
}
}
catch (Exception e)
{
Debug.WriteLine("{0} First exception caught.", e);
Debug.WriteLine(e.InnerException);
ModelState.AddModelError("", e);
}
return View(model);
}
The best I can do is to use ModelState.Remove(), which I feel really uncomfortable with. I suspect that when my Model is passed from the View to Controller, the ModelState is already set to Invalid before I can do anything in the Controller. Any ideas?
If I call the ModelState.Remove() everything went smoothly, the DateTime is accepted by SQL server database.
If at least I can update or 'refresh' ModelState at any point it'll fix my problem.
Cheers.
回答1:
I'd recommend you using a view model and a custom model binder for the DateTime formats.
We start by defining this view model:
public class MyViewModel
{
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime PreferredDate { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
PreferredDate = DateTime.Now.AddDays(2)
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model.PreferredDate will be correctly bound here so
// that you don't need to twiddle with any FormCollection and
// removing stuff from ModelState, etc...
return View(model);
}
}
a View:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.LabelFor(x => x.PreferredDate)
@Html.EditorFor(x => x.PreferredDate)
@Html.ValidationMessageFor(x => x.PreferredDate)
<button type="submit">OK</button>
}
and finally a custom model binder to use the specified format:
public class MyDateTimeModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var displayFormat = bindingContext.ModelMetadata.DisplayFormatString;
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (!string.IsNullOrEmpty(displayFormat) && value != null)
{
DateTime date;
displayFormat = displayFormat.Replace("{0:", string.Empty).Replace("}", string.Empty);
// use the format specified in the DisplayFormat attribute to parse the date
if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
{
return date;
}
else
{
bindingContext.ModelState.AddModelError(
bindingContext.ModelName,
string.Format("{0} is an invalid date format", value.AttemptedValue)
);
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
that will be registered in Application_Start
:
ModelBinders.Binders.Add(typeof(DateTime), new MyDateTimeModelBinder());
来源:https://stackoverflow.com/questions/12023970/mvc3-passing-incorrectly-formatted-datetime-to-controller-but-correcting-it-in-t