asp.net-mvc
Привязка к модели
Поиск…
Вступление
Связывание модели - это процесс приема параметров HTTP, как правило, в строке запроса запроса GET или внутри тела POST и применения его к объекту, который затем может быть проверен и потреблен объектно-ориентированным образом без необходимости в действиях контроллера имея интимные знания о том, как получить параметры HTTP.
Другими словами, привязка к модели - это то, что позволяет действиям в MVC иметь любой параметр (ы), будь то тип значения или объект.
замечания
Чтобы попытаться создать экземпляр в действии, процесс модели привязки будет искать данные в разных местах:
- Данные формы
- Данные маршрута
- Строка запроса
- Файлы Custom (файлы cookie, например)
Перенос значения маршрута
Учитывая некоторую маршрутизацию по умолчанию, такую как {controller=Home}/{action=Index}/{id?}
Если у вас есть URL https://stackoverflow.com/questions/1558902
Это перейдет в Контроллер вопросов и значение 1558902 будет сопоставлено с идентификационным параметром действия индекса, т. Е.
public ActionResult Index(int? id){
//id would be bound to id of the route
}
Связывание строки запроса
Чтобы расширить привязку маршрута, скажите, что у вас есть URL-адрес, например https://stackoverflow.com/questions/1558902?sort=desc
и маршрутизация, подобная {controller=Home}/{action=Index}/{id?}
public ActionResult Index(int? id, string sort){
//sort would bind to the value in the query string, i.e. "desc"
}
Связывание с объектами
Часто вы будете работать с классами viewmodel в asp.net-mvc и захотите привязываться к свойствам на них. Это похоже на сопоставление с отдельными параметрами.
Предположим, что у вас была простая модель вида PostViewModel.
public class PostViewModel{
public int Id {get;set;}
public int SnappyTitle {get;set;}
}
Затем вы отправили значения Id и SnappyTitle из формы в HTTP-запросе, тогда они будут отображаться прямо на эту модель, если сама модель была параметром действия, например
public ActionResult UpdatePost(PostViewModel viewModel){
//viewModel.Id would have our posted value
}
Стоит отметить, что привязка нечувствительна к регистру для имен параметров и свойств. Он также будет отличать значения, где это возможно. Я оставляю больше случаев для конкретных примеров
Связывание Ajax
Это значения формы, которые входят в HTTP-запрос с использованием метода POST. (включая запросы POST JQuery).
Скажем, вы сделали ajax-сообщение вроде
$.ajax({
type: 'POST',
url: window.updatePost,
data: { id: 21, title: 'snappy title' },
//kept short for clarity
});
Здесь два значения в json, id и title будут привязаны к соответствующему действию, например
public JsonResult UpdatePost(int id, string title) {
...
}
Обобщенная привязка модели на основе сеанса
Иногда нам нужно сохранить целую модель и передать ее через действия или даже контроллеры. Хранение модели на сессии хорошее решение для этого типа требований. Если мы объединим это с мощными функциями привязки модели MVC, мы получим элегантный способ сделать это. Мы можем создать общую привязку модели на основе сеанса в три простых шага:
Шаг первый: создать модельное связующее
Создайте само устройство. Лично я создал SessionDataModelBinder класс в папке / Инфраструктура / ModelBinders.
using System;
using System.Web.Mvc;
public class SessionDataModelBinder<TModel>
: IModelBinder
where TModel : class
{
private string SessionKey { get; set; }
public SessionDataModelBinder(string sessionKey)
{
if (string.IsNullOrEmpty(sessionKey))
throw new ArgumentNullException(nameof(sessionKey));
SessionKey = sessionKey;
}
public object BindModel(
ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
// Get model from session
TModel model = controllerContext
.HttpContext
.Session[SessionKey] as TModel;
// Create model if it wasn't found from session and store it
if (model == null)
{
model = Activator.CreateInstance<TModel>();
controllerContext.HttpContext.Session[SessionKey] = model;
}
// Return the model
return model;
}
}
Шаг второй: зарегистрируйте связующее
Если у нас есть модель, как показано ниже:
public class ReportInfo
{
public int ReportId { get; set; }
public ReportTypes TypeId { get; set; }
}
public enum ReportTypes
{
NotSpecified,
Monthly, Yearly
}
Мы можем зарегистрировать привязку модели на основе сеанса для этой модели в Global.asax в методе Application_Start :
protected void Application_Start()
{
.........
// Model binders.
// Remember to specy unique SessionKey
ModelBinders.Binders.Add(typeof(ReportInfo),
new SessionDataModelBinder<ReportInfo>("ReportInfo"));
}
Шаг третий: используйте его!
Теперь мы можем извлечь выгоду из этого связующего устройства просто путем добавления параметра к нашим действиям :
public class HomeController : Controller
{
public ActionResult Index(ReportInfo reportInfo)
{
// Simply set properties
reportInfo.TypeId = ReportTypes.Monthly;
return View();
}
public ActionResult About(ReportInfo reportInfo)
{
// reportInfo.TypeId is Monthly now because we set
// it previously in Index action.
ReportTypes currentReportType = reportInfo.TypeId;
return View();
}
}
Запретить привязку к PostModel
Учитывая (пост) модель:
public class User
{
public string FirstName { get; set; }
public bool IsAdmin { get; set; }
}
С таким видом:
@using (Html.BeginForm()) {
@Html.EditorFor(model => model.FirstName)
<input type="submit" value="Save" />
}
Чтобы злоумышленник не мог назначить IsAdmin, вы можете использовать атрибут Bind
в действии:
[HttpPost]
public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user)
{
// ...
}
Файл загружен
Модель:
public class SampleViewModel
{
public HttpPostedFileBase file {get;set;}
}
Посмотреть:
@model HelloWorldMvcApp.SampleViewModel
@using (Html.BeginForm("Index","Home",FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
@Html.TextBoxFor(model => model.file, new {@class="form-control", type="file"})
@Html.ValidationMessageFor(model => model.file)
</div>
<button type="submit" class="btn btn-success submit">Upload</button>
}
Действие:
[HttpPost]
public ActionResult Index(SampleViewModel model)
{
if (model.file.ContentLength > 0)
{
string fileName = Path.GetFileName(model.file.FileName);
string fileLocation = "~/App_Data/uploads/"+ fileName;
model.file.SaveAs(Server.MapPath(fileLocation));
}
return View(model);
}
Проверка полей даты вручную с помощью динамических форматов с использованием связующего
Если разные пользователи нуждаются в другом формате datetime, вам может понадобиться проанализировать строку входящей даты до фактической даты в соответствии с форматом. В этом случае этот фрагмент может помочь вам.
public class DateTimeBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
DateTime date;
var displayFormat = Session["DateTimeFormat"];
if (value.AttemptedValue != "")
{
if (DateTime.TryParseExact(value.AttemptedValue, displayFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
{
return date;
}
else
{
bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Invalid date format");
}
}
}
return base.BindModel(controllerContext, bindingContext);
}