asp.net-mvc
Modellbindung
Suche…
Einführung
Die Modellbindung ist der Vorgang, bei dem HTTP-Parameter verwendet werden, normalerweise in der Abfragezeichenfolge einer GET-Anforderung oder im POST-Hauptteil, und diese auf ein Objekt anwenden, das dann objektorientiert überprüft und verwendet werden kann, ohne dass Controller-Aktionen erforderlich sind mit vertrauten Kenntnissen über das Abrufen von HTTP-Parametern.
Mit anderen Worten: Mit der Modellbindung können Aktionen in MVC über einen oder mehrere Parameter verfügen, unabhängig davon, ob es sich um einen Werttyp oder ein Objekt handelt.
Bemerkungen
Um zu versuchen, eine Instanz in der Aktion zu erstellen, durchsucht der Bindungsmodellprozess Daten an verschiedenen Stellen:
- Formulardaten
- Routendaten
- Abfragezeichenfolge
- Files Custom (Cookies zum Beispiel)
Routenwertbindung
Wenn Sie einige Standardrouten wie {controller=Home}/{action=Index}/{id?}
Angegeben haben, wenn Sie die URL https://stackoverflow.com/questions/1558902
Dies würde an den QuestionsController gehen und der Wert 1558902 würde einem id-Parameter einer Indexaktion zugeordnet werden, dh
public ActionResult Index(int? id){
//id would be bound to id of the route
}
Abfrage-String-Bindung
Um die Routenbindung zu erweitern, sagen Sie, Sie hätten eine URL wie https://stackoverflow.com/questions/1558902?sort=desc
und Routing wie {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"
}
An Objekte binden
Häufig arbeiten Sie mit Ansichtsmodellklassen in asp.net-mvc und möchten Eigenschaften an diese binden. Dies funktioniert ähnlich wie bei der Zuordnung zu einzelnen Parametern.
Angenommen, Sie hatten ein einfaches Ansichtsmodell für ein PostViewModel wie dieses
public class PostViewModel{
public int Id {get;set;}
public int SnappyTitle {get;set;}
}
Dann hatten Sie die Werte für Id und SnappyTitle aus einem Formular in der http-Anfrage gepostet und dann direkt auf dieses Modell abgebildet, wenn das Modell selbst der Aktionsparameter war, z
public ActionResult UpdatePost(PostViewModel viewModel){
//viewModel.Id would have our posted value
}
Beachten Sie, dass bei der Bindung die Parameter- und Eigenschaftsnamen nicht berücksichtigt werden. Wenn möglich, werden auch Werte ausgegeben. Ich lasse mehr Randfälle für spezifische Beispiele
Ajax-Bindung
Dies sind Formularwerte, die in der HTTP-Anforderung mit der POST-Methode gespeichert werden. (einschließlich jQuery-POST-Anforderungen).
Angenommen, Sie haben einen Ajax-Beitrag gemacht
$.ajax({
type: 'POST',
url: window.updatePost,
data: { id: 21, title: 'snappy title' },
//kept short for clarity
});
Hier wären die beiden Werte in json, id und title, an die passende Aktion gebunden, z
public JsonResult UpdatePost(int id, string title) {
...
}
Allgemeine, sitzungsbasierte Modellbindung
Manchmal müssen wir das gesamte Modell beibehalten und auf Aktionen oder sogar Controller übertragen. Speichern des Modells bei Sitzung Gute Lösung für diese Art von Anforderungen. Wenn wir dies mit den leistungsstarken Modellbindungsfunktionen von MVC kombinieren, erhalten Sie eine elegante Methode. Wir können eine generische, sitzungsbasierte Modellbindung in drei einfachen Schritten erstellen:
Schritt 1: Erstellen Sie einen Modellordner
Erstellen Sie selbst einen Modellordner. Ich persönlich habe die SessionDataModelBinder- Klasse im Ordner / Infrastructure / ModelBinders erstellt .
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;
}
}
Schritt zwei: Registrieren Sie den Ordner
Wenn wir modell wie unten haben:
public class ReportInfo
{
public int ReportId { get; set; }
public ReportTypes TypeId { get; set; }
}
public enum ReportTypes
{
NotSpecified,
Monthly, Yearly
}
Wir können einen sitzungsbasierten Modellbinder für dieses Modell in Global.asax in der Application_Start- Methode registrieren:
protected void Application_Start()
{
.........
// Model binders.
// Remember to specy unique SessionKey
ModelBinders.Binders.Add(typeof(ReportInfo),
new SessionDataModelBinder<ReportInfo>("ReportInfo"));
}
Schritt drei: Verwenden Sie es!
Jetzt können wir von diesem Modellordner profitieren, indem wir unseren Aktionen Parameter hinzufügen :
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();
}
}
Bindung an PostModel verhindern
Betrachten eines (Post-) Modells:
public class User
{
public string FirstName { get; set; }
public bool IsAdmin { get; set; }
}
Mit einer Ansicht wie so:
@using (Html.BeginForm()) {
@Html.EditorFor(model => model.FirstName)
<input type="submit" value="Save" />
}
Um zu verhindern, dass ein böswilliger Benutzer IsAdmin zuweist, können Sie das Bind
Attribut in der Aktion verwenden:
[HttpPost]
public ViewResult Edit([Bind(Exclude = "IsAdmin")] User user)
{
// ...
}
Datei-Upload
Modell:
public class SampleViewModel
{
public HttpPostedFileBase file {get;set;}
}
Aussicht:
@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>
}
Aktion:
[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);
}
Datumsfelder manuell mit dynamischen Formaten mithilfe des Modellbinders überprüfen
Wenn verschiedene Benutzer ein anderes datetime-Format benötigen, müssen Sie möglicherweise die eingehende Datumszeichenfolge entsprechend dem Format bis zum tatsächlichen Datum analysieren. In diesem Fall kann Ihnen dieses Snippet helfen.
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);
}