Zoeken…


Invoering

Modelbinding is het proces van het nemen van HTTP-parameters, meestal in de Query String van een GET-verzoek, of binnen de POST-body, en het toepassen op een object dat vervolgens op een objectgeoriënteerde manier kan worden gevalideerd en geconsumeerd zonder dat controller-acties nodig zijn grondige kennis hebben van het ophalen van HTTP-parameters.

Met andere woorden, modelbinding is wat acties, in MVC, toestaat om ofwel parameter (s) te hebben, of het nu een waardetype of een object is.

Opmerkingen

Om te proberen een instantie in de actie te maken, zoekt het bindmodelproces op verschillende plaatsen naar gegevens:

  • Formuliergegevens
  • Routegegevens
  • Zoekopdrachtreeks
  • Bestanden aangepast (cookies bijvoorbeeld)

Route waarde bindend

Gegeven een aantal standaardrouting zoals {controller=Home}/{action=Index}/{id?} Als u de URL https://stackoverflow.com/questions/1558902

Dit zou naar de QuestionController gaan en de waarde 1558902 zou worden toegewezen aan een id-parameter van een indexactie, dwz

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

Zoekopdracht string bindend

Om uit te breiden op de route bindend zeggen dat je een url zoals https://stackoverflow.com/questions/1558902?sort=desc

en routing zoals {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"
}

Binden aan objecten

Vaak zou je met viewmodel-klassen in asp.net-mvc werken en zou je je hieraan willen binden. Dit werkt vergelijkbaar met het toewijzen aan individuele parameters.

Stel dat u een eenvoudig weergavemodel had, zo noemde PostViewModel

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

Dan had u waarden van ID en SnappyTitle gepost vanuit een formulier in het http-verzoek, dan zouden ze direct aan dat model worden toegewezen als het model zelf de actieparameter was, bijv.

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

Het is vermeldenswaard dat de binding hoofdletterongevoelig is voor de parameter- en eigenschapsnamen. Waar mogelijk worden ook waarden geworpen. Ik laat meer randgevallen achter voor specifieke voorbeelden

Ajax bindend

Dit zijn formulierwaarden die in het HTTP-verzoek worden gebruikt met behulp van de POST-methode. (inclusief jQuery POST-aanvragen).

Stel dat je een Ajax-bericht leuk vond

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

Hier zouden de twee waarden in json, id en titel gebonden zijn aan de overeenkomende actie, bijv

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

Generieke, op sessie gebaseerde modelbinding

Soms moeten we het hele model behouden en overdragen via acties of zelfs controllers. Model opslaan bij sessie goede oplossing voor dit soort vereisten. Als we dit combineren met krachtige model binding kenmerken van MVC krijgen we elegante manier om dit te doen. We kunnen generieke sessiegebaseerde modelbinding maken in drie eenvoudige stappen:

Stap één: Modelbinder maken

Maak zelf een modelbinder. Persoonlijk heb ik gemaakt SessionDataModelBinder klasse / Infrastructuur / ModelBinders map.

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

Stap twee: registerbinder registreren

Als we een model hebben zoals hieronder:

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

public enum ReportTypes
{
    NotSpecified,
    Monthly, Yearly
}

We kunnen op sessie gebaseerde modelbinder voor dit model registreren in Global.asax in de Application_Start- methode:

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

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

Stap drie: gebruik het!

Nu kunnen we profiteren van deze modelbinder door eenvoudig een parameter aan onze acties toe te voegen :

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

Voorkom binding op PostModel

Overweegt een (post) model:

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

Met een dergelijke blik:

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

Om te voorkomen dat een kwaadwillende gebruiker IsAdmin toewijst, kunt u het kenmerk Bind in de actie:

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

Bestand upload

Model:

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

Visie:

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

Actie:

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

Datumvelden handmatig valideren met dynamische indelingen met behulp van modelbinder

Als verschillende gebruikers een ander datetime-formaat nodig hebben, moet u mogelijk uw inkomende datareeks naar de werkelijke datum parseren volgens het formaat. In dit geval kan dit fragment u helpen.

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow