Recherche…


Introduction

La liaison de modèle est le processus consistant à prendre des paramètres HTTP, généralement dans la chaîne de requête d'une requête GET ou dans le corps POST, et à les appliquer à un objet pouvant être validé et orienté objet sans actions du contrôleur. avoir une connaissance intime de la façon de récupérer les paramètres HTTP.

En d'autres termes, la liaison de modèle est ce qui permet aux actions, dans MVC, d'avoir un ou plusieurs paramètres, qu'il s'agisse d'un type de valeur ou d'un objet.

Remarques

Pour essayer de créer une instance dans l'action, le processus de modèle de liaison recherche les données à différents endroits:

  • Données de formulaire
  • Données d'itinéraire
  • Chaîne de requête
  • Fichiers personnalisés (cookies par exemple)

Liaison de valeur d'itinéraire

Étant donné un routage par défaut tel que {controller=Home}/{action=Index}/{id?} Si vous avez l'URL https://stackoverflow.com/questions/1558902

Cela irait au QuestionsController et la valeur 1558902 serait mappée à un paramètre id d'une action d'index, c.-à-d.

public ActionResult Index(int? id){
     //id would be bound to id of the route
}

Liaison de chaîne de requête

Pour prolonger la liaison, indiquez une URL telle que https://stackoverflow.com/questions/1558902?sort=desc

et routage comme {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"
}

Liaison aux objets

Vous travailliez souvent avec des classes viewmodel dans asp.net-mvc et souhaitiez les associer à des propriétés. Cela fonctionne de la même manière que la correspondance avec des paramètres individuels.

Disons que vous aviez un simple modèle de vue appelez PostViewModel comme ceci

public class PostViewModel{
  public int Id {get;set;}
  public int SnappyTitle {get;set;}
}

Ensuite, vous aviez publié des valeurs de Id et SnappyTitle à partir d'un formulaire dans la requête http, puis ils mappaient directement sur ce modèle si le modèle lui-même était le paramètre d'action, par exemple

public ActionResult UpdatePost(PostViewModel viewModel){
  //viewModel.Id would have our posted value
}

Il convient de noter que la liaison est insensible à la casse pour les noms de paramètre et de propriété. Il jettera également des valeurs si possible. Je laisse plus de cas pour des exemples spécifiques

Liaison Ajax

Ce sont des valeurs de formulaire qui vont dans la requête HTTP en utilisant la méthode POST. (y compris les requêtes POST jQuery).

Dis que tu as fait un post ajax comme

$.ajax({
    type: 'POST',
    url: window.updatePost,
    data:  { id: 21, title: 'snappy title' },
    //kept short for clarity
});

Ici, les deux valeurs de json, id et title, seraient liées à l'action correspondante, par exemple

public JsonResult UpdatePost(int id, string title) {
    ...
}

Générique, liaison de modèle basée sur la session

Parfois, nous avons besoin de préserver tout le modèle et de le transférer à travers des actions ou même des contrôleurs. Stockage du modèle à la session bonne solution pour ce type d'exigences. Si nous combinons cela avec les puissantes fonctionnalités de liaison de modèles de MVC, nous obtenons une manière élégante de le faire. Nous pouvons créer une liaison de modèle générique basée sur la session en trois étapes simples:

Première étape: Créer un modèle de classeur

Créez un modèle de classeur lui-même. Personnellement, j'ai créé la classe SessionDataModelBinder dans le dossier / Infrastructure / 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;
    }
}

Deuxième étape: enregistrer le classeur

Si nous avons un modèle comme ci-dessous:

public class ReportInfo
{
    public int ReportId { get; set; }
    public ReportTypes TypeId { get; set; }
}

public enum ReportTypes
{
    NotSpecified,
    Monthly, Yearly
}

Nous pouvons enregistrer un modèle de classeur basé sur la session pour ce modèle dans Global.asax dans la méthode Application_Start :

protected void Application_Start()
{
    .........

    // Model binders.
    // Remember to specy unique SessionKey
    ModelBinders.Binders.Add(typeof(ReportInfo), 
        new SessionDataModelBinder<ReportInfo>("ReportInfo"));
}

Troisième étape: utilisez-le!

Nous pouvons maintenant bénéficier de ce modèle en ajoutant simplement des paramètres à nos actions :

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();
    }
}

Empêcher la liaison sur PostModel

Considérant un modèle (post):

public class User
{
    public string FirstName { get; set; }
    public bool IsAdmin { get; set; }
}

Avec une vue comme ça:

@using (Html.BeginForm()) {
    @Html.EditorFor(model => model.FirstName)
    <input type="submit" value="Save" />       
}

Afin d'empêcher un utilisateur malveillant d'attribuer IsAdmin, vous pouvez utiliser l'attribut Bind dans l'action:

[HttpPost]
public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user)
{
    // ...
}

Téléchargement de fichiers

Modèle:

public class SampleViewModel
{
    public HttpPostedFileBase file {get;set;}
}

Vue:

@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>
}

Action:

[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);
}

Validation manuelle des champs de date avec des formats dynamiques à l'aide du modèle de classeur

Si différents utilisateurs ont besoin d'un format datetime différent, vous devrez peut-être analyser votre chaîne de date entrante à la date réelle en fonction du format. Dans ce cas, cet extrait peut vous aider.

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow