Поиск…


Вступление

Связывание модели - это процесс приема параметров 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);
    }


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow