Ricerca…


introduzione

Il bind del modello è il processo di prendere i parametri HTTP, in genere nella stringa di query di una richiesta GET, o all'interno del corpo POST e applicarlo in un oggetto che può quindi essere convalidato e consumato in modo orientato agli oggetti senza la necessità di azioni del controllore avere una conoscenza approfondita di come recuperare i parametri HTTP.

In altre parole, l'associazione modello è ciò che consente alle azioni, in MVC, di avere uno o più parametri, sia che si tratti di un tipo di valore o di un oggetto.

Osservazioni

Per provare a creare un'istanza nell'azione, il processo del modello di bind cercherà i dati in vari punti:

  • Dati del modulo
  • Route Data
  • Stringa della domanda
  • File personalizzati (cookie ad esempio)

Legame del valore del percorso

Dato un certo routing predefinito come {controller=Home}/{action=Index}/{id?} Se hai l'URL https://stackoverflow.com/questions/1558902

Questo andrebbe a QuestionsController e il valore 1558902 verrebbe mappato a un parametro id di un'azione indice, vale a dire

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

Stringa di query vincolante

Per estendere sulla rotta vincolante dire che hai avuto un URL come https://stackoverflow.com/questions/1558902?sort=desc

e il routing come {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"
}

Legare agli oggetti

Spesso lavoreresti con le classi viewmodel in asp.net-mvc e vorremmo associarli alle proprietà su questi. Funziona in modo simile alla mappatura di singoli parametri.

Supponiamo che tu abbia avuto un semplice modello di visualizzazione per chiamare PostViewModel come questo

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

Quindi hai inserito i valori di Id e SnappyTitle da un modulo nella richiesta http, quindi sarebbero mappati direttamente su quel modello se il modello stesso era il parametro di azione, ad esempio

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

Vale la pena notare che l'associazione non fa distinzione tra maiuscole e minuscole per i nomi di parametri e proprietà. Inoltre, proietterà i valori laddove possibile. Sto lasciando più casi limite per esempi specifici

Associazione Ajax

Questi sono i valori dei moduli che vanno nella richiesta HTTP usando il metodo POST. (comprese le richieste POST jQuery).

Supponi di aver fatto un post ajax come

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

Qui i due valori in json, id e title, sarebbero associati all'azione corrispondente, ad es

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

Associazione modello generica basata su sessione

A volte abbiamo bisogno di preservare l' intero modello e trasferirlo attraverso azioni o persino controllori. Memorizzazione del modello in sessione buona soluzione per questo tipo di requisiti. Se combiniamo questo con le potenti funzionalità di associazione dei modelli di MVC otteniamo un modo elegante per farlo. Possiamo creare associazioni generiche basate su sessioni basate su tre semplici passaggi:

Fase 1: creare un raccoglitore di modelli

Crea un raccoglitore di modelli stesso. Personalmente ho creato la classe SessionDataModelBinder nella cartella / 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;
    }
}

Fase 2: registrare il raccoglitore

Se abbiamo modello come di seguito:

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

public enum ReportTypes
{
    NotSpecified,
    Monthly, Yearly
}

Possiamo registrare il modello di associazione basato su sessioni per questo modello in Global.asax nel metodo Application_Start :

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

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

Fase tre: usalo!

Ora possiamo trarre vantaggio da questo legatore di modelli semplicemente aggiungendo un parametro alle nostre azioni :

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

Impedisci il binding su PostModel

Considerando un modello (post):

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

Con una vista come questa:

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

Per impedire a un utente malintenzionato di assegnare IsAdmin, è possibile utilizzare l'attributo Bind nell'azione:

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

Upload di file

Modello:

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

Vista:

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

Azione:

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

Convalida dei campi data manualmente con i formati dinamici utilizzando il raccoglitore modello

Se diversi utenti necessitano di un formato datetime diverso, potrebbe essere necessario analizzare la stringa della data in arrivo alla data effettiva in base al formato. In questo caso questo frammento può aiutarti.

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow