Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ostrzeżenie
Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
W tym artykule wyjaśniono, czym jest powiązanie modelu, jak działa i jak dostosować jego zachowanie.
Co to jest powiązanie modelu
Kontrolery i Razor strony współpracują z danymi pochodzącymi z żądań HTTP. Na przykład dane trasy mogą zawierać klucz rekordu, a opublikowane pola formularza mogą zawierać wartości właściwości modelu. Pisanie kodu w celu pobrania każdej z tych wartości i przekonwertowanie ich z ciągów na typy platformy .NET byłoby żmudne i podatne na błędy. Powiązanie modelu automatyzuje ten proces. System powiązania modelu:
Pobiera dane z różnych źródeł, takich jak dane trasy, pola formularza i ciągi zapytań.
Udostępnia dane kontrolerom i Razor stronom w parametrach metody i właściwościach publicznych.
Konwertuje dane ciągu na typy platformy .NET.
Aktualizuje właściwości typów złożonych.
Przykład
Załóżmy, że masz następującą metodę akcji:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Aplikacja otrzymuje żądanie z następującym adresem URL:
https://contoso.com/api/pets/2?DogsOnly=true
Powiązanie modelu wykonuje następujące kroki po wybraniu przez system routingu metody akcji:
Znajduje pierwszy parametr , GetByIdliczba całkowita o nazwie id.
Przegląda dostępne źródła w żądaniu HTTP i znajduje id = "2" w danych trasy.
Konwertuje ciąg "2" na liczbę całkowitą 2.
Znajduje następny parametr , GetByIdwartość logiczną o nazwie dogsOnly.
Przegląda źródła i znajduje ciąg zapytania "DogsOnly=true". Dopasowywanie nazw nie jest uwzględniane wielkości liter.
Konwertuje ciąg "true" na wartość logiczną true.
Następnie struktura wywołuje metodę GetById , przekazując wartość 2 dla parametru id i true parametru dogsOnly .
W poprzednim przykładzie docelowe powiązania modelu to parametry metody, które są prostymi typami. Obiekty docelowe mogą być również właściwościami typu złożonego. Po pomyślnym powiązaniu każdej właściwości walidacja modelu jest wykonywana dla tej właściwości. Rekord danych powiązanych z modelem oraz wszelkich błędów powiązań lub walidacji jest przechowywany w pliku ControllerBase.ModelState lub PageModel.ModelState. Aby dowiedzieć się, czy ten proces zakończył się pomyślnie, aplikacja sprawdza flagę ModelState.IsValid .
Elementy docelowe
Powiązanie modelu próbuje znaleźć wartości dla następujących rodzajów obiektów docelowych:
Parametry metody akcji kontrolera, do którego jest kierowane żądanie.
Razor Parametry metody obsługi stron, do których jest kierowane żądanie.
Publiczne właściwości kontrolera lub PageModel klasy, jeśli są określone przez atrybuty.
[BindProperty] , atrybut
Można zastosować do właściwości publicznej kontrolera lub PageModel klasy, aby spowodować powiązanie modelu z tą właściwością docelową:
public class EditModel : PageModel
{
[BindProperty]
public Instructor? Instructor { get; set; }
// ...
}
[BindProperties] , atrybut
Można zastosować do kontrolera lub PageModel klasy, aby poinformować powiązanie modelu w celu kierowania wszystkich właściwości publicznych klasy:
[BindProperties]
public class CreateModel : PageModel
{
public Instructor? Instructor { get; set; }
// ...
}
Powiązanie modelu dla żądań HTTP GET
Domyślnie właściwości nie są powiązane z żądaniami HTTP GET. Zazwyczaj wszystko, czego potrzebujesz do żądania GET, to parametr identyfikatora rekordu. Identyfikator rekordu służy do wyszukiwania elementu w bazie danych. W związku z tym nie ma potrzeby wiązania właściwości, która zawiera wystąpienie modelu. W scenariuszach, w których chcesz, aby właściwości powiązane z danymi z żądań GET ustawiły SupportsGet właściwość na true:
Tworzenie prostych i złożonych typów powiązania modelu
Powiązanie modelu używa określonych definicji dla typów, na których działa. Prosty typ jest konwertowany z jednego ciągu przy użyciu TypeConverter metody lub TryParse metody. Typ złożony jest konwertowany z wielu wartości wejściowych. Struktura określa różnicę na podstawie istnienia obiektu TypeConverter lub TryParse. Zalecamy utworzenie konwertera typów lub użycie TryParse metody do stringSomeType konwersji, która nie wymaga zasobów zewnętrznych ani wielu danych wejściowych.
Źródła
Domyślnie powiązanie modelu pobiera dane w postaci par klucz-wartość z następujących źródeł w żądaniu HTTP:
Są dodawane do właściwości modelu indywidualnie, a nie do klasy modelu, jak w poniższym przykładzie:
public class Instructor
{
public int Id { get; set; }
[FromQuery(Name = "Note")]
public string? NoteFromQueryString { get; set; }
// ...
}
Opcjonalnie zaakceptuj wartość nazwy modelu w konstruktorze. Ta opcja jest dostępna w przypadku, gdy nazwa właściwości nie jest zgodna z wartością w żądaniu. Na przykład wartość w żądaniu może być nagłówkiem z łącznikiem w jego nazwie, jak w poniższym przykładzie:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] , atrybut
Zastosuj atrybut do parametru, [FromBody] aby wypełnić jego właściwości z treści żądania HTTP. Środowisko uruchomieniowe ASP.NET Core deleguje odpowiedzialność za odczytywanie treści do elementu formatującego dane wejściowe. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
Po [FromBody] zastosowaniu do parametru typu złożonego wszystkie atrybuty źródła powiązania zastosowane do jego właściwości są ignorowane. Na przykład następująca Create akcja określa, że jego pet parametr jest wypełniany z treści:
public ActionResult<Pet> Create([FromBody] Pet pet)
Klasa Pet określa, że jego Breed właściwość jest wypełniana z parametru ciągu zapytania:
public class Pet
{
public string Name { get; set; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
W powyższym przykładzie:
Atrybut [FromQuery] jest ignorowany.
Właściwość Breed nie jest wypełniana z parametru ciągu zapytania.
Formatery wejściowe odczytują tylko treść i nie rozumieją atrybutów źródła powiązania. Jeśli w treści znajduje się odpowiednia wartość, ta wartość jest używana do wypełnienia Breed właściwości.
Nie należy stosować [FromBody] do więcej niż jednego parametru dla metody akcji. Gdy strumień żądania zostanie odczytany przez program formatujący dane wejściowe, nie będzie już dostępny do ponownego odczytania w celu powiązania innych [FromBody] parametrów.
Dodatkowe źródła
Dane źródłowe są dostarczane do systemu powiązania modelu przez dostawców wartości. Można zapisywać i rejestrować niestandardowych dostawców wartości, którzy pobierają dane na potrzeby powiązania modelu z innych źródeł. Możesz na przykład chcieć dane z plików cookie lub stanu sesji. Aby pobrać dane z nowego źródła:
Utwórz klasę, która implementuje IValueProvider.
Utwórz klasę, która implementuje IValueProviderFactory.
Zarejestruj klasę fabryki w pliku Program.cs.
Przykład zawiera dostawcę wartości i przykład fabryki, który pobiera wartości z plików cookie. Zarejestruj fabryki dostawców wartości niestandardowych w programie Program.cs:
Powyższy kod umieszcza niestandardowego dostawcę wartości po wszystkich wbudowanych dostawcach wartości. Aby ustawić ją jako pierwszą na liście, wywołaj metodę Insert(0, new CookieValueProviderFactory()) zamiast Add.
Brak źródła dla właściwości modelu
Domyślnie błąd stanu modelu nie jest tworzony, jeśli dla właściwości modelu nie zostanie znaleziona żadna wartość. Właściwość jest ustawiona na wartość null lub wartość domyślną:
Typy wartości innych niż null są ustawione na default(T)wartość . Na przykład parametr int id ma wartość 0.
W przypadku złożonych typów powiązanie modelu tworzy wystąpienie przy użyciu konstruktora domyślnego bez ustawiania właściwości.
Tablice są ustawione na Array.Empty<T>(), z tą różnicą, że byte[] tablice są ustawione na null.
Jeśli stan modelu powinien zostać unieważniony, jeśli nic nie zostanie znalezione w polach formularza dla właściwości modelu, użyj atrybutu [BindRequired] .
Należy pamiętać, że to [BindRequired] zachowanie dotyczy powiązania modelu z opublikowanych danych formularza, a nie danych JSON lub XML w treści żądania. Dane treści żądania są obsługiwane przez osoby formatujące dane wejściowe.
Błędy konwersji typów
Jeśli źródło zostanie znalezione, ale nie można go przekonwertować na typ docelowy, stan modelu jest oznaczony jako nieprawidłowy. Docelowy parametr lub właściwość jest ustawiona na wartość null lub wartość domyślną, jak wspomniano w poprzedniej sekcji.
W kontrolerze interfejsu [ApiController] API, który ma atrybut, nieprawidłowy stan modelu powoduje automatyczną odpowiedź HTTP 400.
Razor Na stronie redisplay strony z komunikatem o błędzie:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
Gdy strona jest redisplayed przez poprzedni kod, nieprawidłowe dane wejściowe nie są wyświetlane w polu formularza. Jest to spowodowane tym, że właściwość modelu została ustawiona na wartość null lub wartość domyślną. Nieprawidłowe dane wejściowe są wyświetlane w komunikacie o błędzie. Jeśli chcesz ponownie odtworzyć nieprawidłowe dane w polu formularza, rozważ utworzenie właściwości modelu jako ciągu i ręczne przeprowadzenie konwersji danych.
Ta sama strategia jest zalecana, jeśli nie chcesz, aby błędy konwersji typów powodowały błędy stanu modelu. W takim przypadku utwórz właściwość modelu jako ciąg.
Typy proste
Aby uzyskać wyjaśnienie prostych i złożonych typów, zobacz Powiązania modelu proste i złożone typy.
Proste typy, które binder modelu mogą konwertować ciągi źródłowe na następujące:
public static bool TryParse (string? s, IFormatProvider? provider, out TSelf result);
DateRange Następująca klasa implementuje IParsable<TSelf> obsługę powiązania zakresu dat:
public class DateRange : IParsable<DateRange>
{
public DateOnly? From { get; init; }
public DateOnly? To { get; init; }
public static DateRange Parse(string value, IFormatProvider? provider)
{
if (!TryParse(value, provider, out var result))
{
throw new ArgumentException("Could not parse supplied value.", nameof(value));
}
return result;
}
public static bool TryParse(string? value,
IFormatProvider? provider, out DateRange dateRange)
{
var segments = value?.Split(',', StringSplitOptions.RemoveEmptyEntries
| StringSplitOptions.TrimEntries);
if (segments?.Length == 2
&& DateOnly.TryParse(segments[0], provider, out var fromDate)
&& DateOnly.TryParse(segments[1], provider, out var toDate))
{
dateRange = new DateRange { From = fromDate, To = toDate };
return true;
}
dateRange = new DateRange { From = default, To = default };
return false;
}
}
Powyższy kod ma następujące działanie:
Konwertuje ciąg reprezentujący dwie daty na DateRange obiekt
Interfejs TryParse API obsługuje wartości parametrów akcji kontrolera powiązania:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
IParsable<T>.TryParse jest zalecanym podejściem do powiązania parametrów, ponieważ w przeciwieństwie do TryParsemetody , nie zależy od odbicia.
DateRangeTP Następująca klasa implementuje TryParseelement :
public class DateRangeTP
{
public DateOnly? From { get; }
public DateOnly? To { get; }
public DateRangeTP(string from, string to)
{
if (string.IsNullOrEmpty(from))
throw new ArgumentNullException(nameof(from));
if (string.IsNullOrEmpty(to))
throw new ArgumentNullException(nameof(to));
From = DateOnly.Parse(from);
To = DateOnly.Parse(to);
}
public static bool TryParse(string? value, out DateRangeTP? result)
{
var range = value?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (range?.Length != 2)
{
result = default;
return false;
}
result = new DateRangeTP(range[0], range[1]);
return true;
}
}
Następująca akcja kontrolera używa DateRangeTP klasy do powiązania zakresu dat:
// GET /WeatherForecast/ByRangeTP?range=7/24/2022,07/26/2022
public IActionResult ByRangeTP([FromQuery] DateRangeTP range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= range.From
&& DateOnly.FromDateTime(wf.Date) <= range.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d"),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Typy złożone
Typ złożony musi mieć publiczny konstruktor domyślny i publiczne właściwości zapisywalne do powiązania. Po utworzeniu powiązania modelu klasę tworzy się przy użyciu publicznego konstruktora domyślnego.
Dla każdej właściwości typu złożonego powiązanie modelu analizuje źródła wzorca nazwprefix.property_name. Jeśli nic nie zostanie znalezione, szuka tylko property_name bez prefiksu. Decyzja o użyciu prefiksu nie jest podjęta na właściwość. Na przykład z zapytaniem zawierającym ?Instructor.Id=100&Name=foometodę , powiązana z metodą OnGet(Instructor instructor), wynikowy obiekt typu Instructor zawiera:
Id ustaw wartość 100.
Name ustaw wartość null. Powiązanie modelu oczekuje, Instructor.Name ponieważ Instructor.Id zostało użyte w poprzednim parametrze zapytania.
W przypadku powiązania z parametrem prefiks jest nazwą parametru. W przypadku powiązania z właściwością publiczną PageModel prefiks jest nazwą właściwości publicznej. Niektóre atrybuty mają Prefix właściwość, która umożliwia zastąpienie domyślnego użycia parametru lub nazwy właściwości.
Załóżmy na przykład, że typ złożony to następująca Instructor klasa:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Prefiks = nazwa parametru
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza instructorToUpdate.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks = nazwa właściwości
Jeśli model, który ma być powiązany, jest właściwością o nazwie Instructor kontrolera lub PageModel klasy:
[BindProperty]
public Instructor Instructor { get; set; }
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks niestandardowy
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate , a Bind atrybut określa Instructor jako prefiks:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Atrybuty dla obiektów docelowych typu złożonego
Dostępnych jest kilka wbudowanych atrybutów do kontrolowania powiązania modelu typów złożonych:
Te atrybuty wpływają na powiązanie modelu, gdy opublikowane dane formularza są źródłem wartości. Nie mają one wpływu na formatery danych wejściowych, które przetwarzają treść żądań JSON i XML. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
[Bind] , atrybut
Można zastosować do klasy lub parametru metody. Określa, które właściwości modelu powinny być uwzględnione w powiązaniu modelu. [Bind]nie ma wpływu na formatery wejściowe.
W poniższym przykładzie tylko określone właściwości Instructor modelu są powiązane, gdy wywoływana jest dowolna metoda obsługi lub akcji:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
W poniższym przykładzie po wywołaniu OnPost metody są powiązane tylko określone właściwości Instructor modelu:
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atrybut [Bind] może służyć do ochrony przed przesłanianiem w scenariuszach tworzenia . Nie działa dobrze w scenariuszach edycji, ponieważ wykluczone właściwości są ustawione na wartość null lub wartość domyślną, a nie pozostawione bez zmian. W przypadku ochrony przed przesłanianiem zalecane są modele wyświetlania, a nie atrybut.[Bind] Aby uzyskać więcej informacji, zobacz Uwaga dotycząca zabezpieczeń dotycząca zastępowania.
[ModelBinder] , atrybut
ModelBinderAttribute można stosować do typów, właściwości lub parametrów. Umożliwia określenie typu powiązania modelu używanego do powiązania określonego wystąpienia lub typu. Na przykład:
[HttpPost]
public IActionResult OnPost(
[ModelBinder<MyInstructorModelBinder>] Instructor instructor)
Atrybut [ModelBinder] może również służyć do zmiany nazwy właściwości lub parametru, gdy jest powiązany model:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
// ...
}
[BindRequired] , atrybut
Powoduje, że powiązanie modelu powoduje dodanie błędu stanu modelu, jeśli powiązanie nie może wystąpić dla właściwości modelu. Oto przykład:
public class InstructorBindRequired
{
// ...
[BindRequired]
public DateTime HireDate { get; set; }
}
Zobacz również omówienie atrybutu [Required] w temacie Walidacja modelu.
[BindNever] , atrybut
Można zastosować do właściwości lub typu. Uniemożliwia ustawienie właściwości modelu przez powiązanie modelu. Po zastosowaniu do typu system powiązań modelu wyklucza wszystkie właściwości zdefiniowane przez typ. Oto przykład:
public class InstructorBindNever
{
[BindNever]
public int Id { get; set; }
// ...
}
Kolekcje
W przypadku obiektów docelowych, które są kolekcjami prostych typów, powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr, który ma być powiązany, to tablica o nazwie selectedCourses:
public IActionResult OnPost(int? id, int[] selectedCourses)
Dane formularza lub ciągu zapytania mogą być w jednym z następujących formatów:
Unikaj powiązania parametru lub właściwości o nazwie index lub Index , jeśli sąsiaduje z wartością kolekcji. Powiązanie modelu próbuje użyć index jako indeksu kolekcji, co może spowodować nieprawidłowe powiązanie. Rozważmy na przykład następującą akcję:
public IActionResult Post(string index, List<Product> products)
W poprzednim kodzie index parametr ciągu zapytania jest powiązany z parametrem index metody, a także jest używany do powiązania kolekcji produktów. Zmiana nazwy parametru index lub użycie atrybutu powiązania modelu w celu skonfigurowania powiązania pozwala uniknąć tego problemu:
public IActionResult Post(string productIndex, List<Product> products)
Następujący format jest obsługiwany tylko w danych formularza:
selectedCourses[]=1050&selectedCourses[]=2000
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje tablicę dwóch elementów do parametru selectedCourses :
selectedCourses[0]=1050
selectedCourses[1]=2000
Formaty danych używające liczb w indeksie dolnym (... [0] ... [1] ...) musi upewnić się, że są one numerowane sekwencyjnie rozpoczynające się od zera. Jeśli występują luki w numerowaniu indeksu dolnego, wszystkie elementy po przerwie są ignorowane. Jeśli na przykład indeksy dolny to 0 i 2 zamiast 0 i 1, drugi element jest ignorowany.
Słowniki
W przypadku Dictionary obiektów docelowych powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr docelowy Dictionary<int, string> ma nazwę selectedCourses:
public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Dane opublikowanego formularza lub ciągu zapytania mogą wyglądać podobnie do jednego z następujących przykładów:
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje słownik dwóch elementów do parametru selectedCourses :
selectedCourses["1050"]="Chemistry"
selectedCourses["2000"]="Economics"
Powiązanie konstruktora i typy rekordów
Powiązanie modelu wymaga, aby złożone typy miały konstruktor bez parametrów. Zarówno System.Text.Json metody formatowania danych wejściowych, jak i Newtonsoft.Json obsługują deserializację klas, które nie mają konstruktora bez parametrów.
Typy rekordów to doskonały sposób, aby zwięźle reprezentować dane za pośrednictwem sieci. ASP.NET Core obsługuje wiązanie modelu i weryfikowanie typów rekordów za pomocą jednego konstruktora:
public record Person(
[Required] string Name, [Range(0, 150)] int Age, [BindNever] int Id);
public class PersonController
{
public IActionResult Index() => View();
[HttpPost]
public IActionResult Index(Person person)
{
// ...
}
}
Podczas sprawdzania poprawności typów rekordów środowisko uruchomieniowe wyszukuje metadane powiązania i walidacji w szczególności na parametrach, a nie we właściwościach.
Platforma umożliwia wiązanie i weryfikowanie typów rekordów:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Aby poprzedni element działał, typ musi:
Być typem rekordu.
Mieć dokładnie jeden publiczny konstruktor.
Zawierają parametry, które mają właściwość o tej samej nazwie i typie. Nazwy nie mogą się różnić literami.
Obiekty POCO bez konstruktorów bez parametrów
Obiekty POC, które nie mają konstruktorów bez parametrów, nie mogą być powiązane.
Poniższy kod powoduje wyjątek z informacją, że typ musi mieć konstruktor bez parametrów:
public class Person {
public Person(string Name) { }
}
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0)
{
}
}
Typy rekordów z ręcznie utworzonymi konstruktorami
Typy rekordów z ręcznie utworzonymi konstruktorami, które wyglądają jak konstruktory podstawowe działają
public record Person
{
public Person([Required] string Name, [Range(0, 100)] int Age)
=> (this.Name, this.Age) = (Name, Age);
public string Name { get; set; }
public int Age { get; set; }
}
Typy rekordów, walidacja i metadane powiązania
W przypadku typów rekordów używane są metadane walidacji i powiązania parametrów. Wszystkie metadane właściwości są ignorowane
public record Person (string Name, int Age)
{
[BindProperty(Name = "SomeName")] // This does not get used
[Required] // This does not get used
public string Name { get; init; }
}
Walidacja i metadane
Walidacja używa metadanych w parametrze, ale używa właściwości do odczytania wartości. W zwykłych przypadkach z konstruktorami podstawowymi te dwa byłyby identyczne. Istnieją jednak sposoby, aby go pokonać:
public record Person([Required] string Name)
{
private readonly string _name;
// The following property is never null.
// However this object could have been constructed as "new Person(null)".
public string Name { get; init => _name = value ?? string.Empty; }
}
Funkcja TryUpdateModel nie aktualizuje parametrów typu rekordu
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
W takim przypadku usługa MVC nie podejmie ponownej próby powiązania Name . Age Można jednak zaktualizować
Zachowanie globalizacji danych trasy powiązania modelu i ciągów zapytań
Dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania:
Traktuj wartości jako niezmienną kulturę.
Spodziewaj się, że adresy URL są niezmienne dla kultury.
Natomiast wartości pochodzące z danych formularza są poddawane konwersji wrażliwej na kulturę. Jest to zaprojektowane tak, aby adresy URL można udostępniać między ustawieniami regionalnymi.
Aby dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania przeszedł konwersję wrażliwą na kulturę:
Zastąp domyślną fabrykę dostawcy wartości w opcjach MVC nowym:
public class CultureQueryStringValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
_ = context ?? throw new ArgumentNullException(nameof(context));
var query = context.ActionContext.HttpContext.Request.Query;
if (query?.Count > 0)
{
context.ValueProviders.Add(
new QueryStringValueProvider(
BindingSource.Query,
query,
CultureInfo.CurrentCulture));
}
return Task.CompletedTask;
}
}
builder.Services.AddControllers(options =>
{
var index = options.ValueProviderFactories.IndexOf(
options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>()
.Single());
options.ValueProviderFactories[index] =
new CultureQueryStringValueProviderFactory();
});
Specjalne typy danych
Istnieją pewne specjalne typy danych, które mogą obsłużyć powiązanie modelu.
IFormFile i IFormFileCollection
Przekazany plik uwzględniony w żądaniu HTTP. Obsługiwane jest IEnumerable<IFormFile> również w przypadku wielu plików.
CancellationToken
Akcje mogą opcjonalnie powiązać element CancellationToken jako parametr. RequestAborted Wiąże się to z sygnałem, gdy połączenie bazowe żądania HTTP zostanie przerwane. Akcje mogą używać tego parametru do anulowania długotrwałych operacji asynchronicznych wykonywanych w ramach akcji kontrolera.
FormCollection
Służy do pobierania wszystkich wartości z opublikowanych danych formularza.
Formatery danych wejściowych
Dane w treści żądania mogą być w formacie JSON, XML lub innym formacie. Aby przeanalizować te dane, powiązanie modelu używa formatującego danych wejściowych skonfigurowanego do obsługi określonego typu zawartości. Domyślnie ASP.NET Core zawiera formatery wejściowe oparte na formacie JSON do obsługi danych JSON. Możesz dodać inne formatery dla innych typów zawartości.
ASP.NET Core wybiera formatery wejściowe na podstawie atrybutu Consumes . Jeśli atrybut nie jest obecny, używa nagłówka Content-Type.
Dostosowywanie powiązania modelu za pomocą formaterów wejściowych
Moduł formatujący dane wejściowe ponosi pełną odpowiedzialność za odczytywanie danych z treści żądania. Aby dostosować ten proces, skonfiguruj interfejsy API używane przez program formatujący dane wejściowe. W tej sekcji opisano sposób dostosowywania opartego na formatatorze System.Text.Jsondanych wejściowych w celu zrozumienia niestandardowego typu o nazwie ObjectId.
Rozważmy następujący model, który zawiera właściwość niestandardową ObjectId :
public class InstructorObjectId
{
[Required]
public ObjectId ObjectId { get; set; } = null!;
}
Aby dostosować proces powiązania modelu podczas używania metody System.Text.Json, utwórz klasę pochodzącą z JsonConverter<T>klasy :
internal class ObjectIdConverter : JsonConverter<ObjectId>
{
public override ObjectId Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> new(JsonSerializer.Deserialize<int>(ref reader, options));
public override void Write(
Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
=> writer.WriteNumberValue(value.Id);
}
Aby użyć konwertera niestandardowego, zastosuj JsonConverterAttribute atrybut do typu. W poniższym przykładzie ObjectId typ jest skonfigurowany ObjectIdConverter jako konwerter niestandardowy:
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
Zachowanie systemów powiązań i walidacji modelu jest sterowane przez ModelMetadataprogram . Możesz dostosować ModelMetadata , dodając dostawcę szczegółów do elementu MvcOptions.ModelMetadataDetailsProviders. Wbudowani dostawcy szczegółów są dostępni do wyłączania powiązania modelu lub walidacji dla określonych typów.
Aby wyłączyć powiązanie modelu dla wszystkich modeli określonego typu, dodaj element w elemExcludeBindingMetadataProvider.Program.cs Aby na przykład wyłączyć powiązanie modelu dla wszystkich modeli typu System.Version:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Aby wyłączyć walidację właściwości określonego typu, dodaj element SuppressChildValidationMetadataProvider w Program.cspliku . Aby na przykład wyłączyć walidację właściwości typu System.Guid:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Niestandardowe powiązania modelu
Powiązanie modelu można rozszerzyć, pisząc powiązanie modelu niestandardowego i używając atrybutu [ModelBinder] , aby wybrać go dla danego obiektu docelowego. Dowiedz się więcej o powiązaniu modelu niestandardowego.
Ręczne powiązanie modelu
Powiązanie modelu można wywołać ręcznie przy użyciu TryUpdateModelAsync metody . Metoda jest definiowana w klasach ControllerBase i PageModel . Przeciążenia metody umożliwiają określenie prefiksu i dostawcy wartości do użycia. Metoda zwraca false wartość , jeśli powiązanie modelu nie powiedzie się. Oto przykład:
if (await TryUpdateModelAsync(
newInstructor,
"Instructor",
x => x.Name, x => x.HireDate!))
{
_instructorStore.Add(newInstructor);
return RedirectToPage("./Index");
}
return Page();
TryUpdateModelAsync używa dostawców wartości do pobierania danych z treści formularza, ciągu zapytania i kierowania danych. TryUpdateModelAsync jest zwykle:
Używane z aplikacjami Razor Pages i MVC przy użyciu kontrolerów i widoków, aby zapobiec nadmiernemu delegowaniu.
Nie jest używany z internetowym interfejsem API, chyba że są używane z danych formularza, ciągów zapytań i danych trasy. Punkty końcowe internetowego interfejsu API, które używają formatu JSON, używają formatatorów wejściowych do deserializacji treści żądania do obiektu.
Nazwa tego atrybutu jest zgodna ze wzorcem atrybutów powiązania modelu, które określają źródło danych. Nie chodzi jednak o powiązanie danych od dostawcy wartości. Pobiera wystąpienie typu z kontenera wstrzykiwania zależności. Jego celem jest zapewnienie alternatywy dla iniekcji konstruktora, jeśli potrzebujesz usługi tylko wtedy, gdy wywoływana jest określona metoda.
Jeśli wystąpienie typu nie jest zarejestrowane w kontenerze wstrzykiwania zależności, aplikacja zgłasza wyjątek podczas próby powiązania parametru. Aby ustawić parametr jako opcjonalny, użyj jednego z następujących metod:
Ustaw parametr na wartość null.
Ustaw wartość domyślną parametru.
W przypadku parametrów dopuszczających wartość null upewnij się, że parametr nie null jest używany przed uzyskaniem do niego dostępu.
W tym artykule wyjaśniono, czym jest powiązanie modelu, jak działa i jak dostosować jego zachowanie.
Co to jest powiązanie modelu
Kontrolery i Razor strony współpracują z danymi pochodzącymi z żądań HTTP. Na przykład dane trasy mogą zawierać klucz rekordu, a opublikowane pola formularza mogą zawierać wartości właściwości modelu. Pisanie kodu w celu pobrania każdej z tych wartości i przekonwertowanie ich z ciągów na typy platformy .NET byłoby żmudne i podatne na błędy. Powiązanie modelu automatyzuje ten proces. System powiązania modelu:
Pobiera dane z różnych źródeł, takich jak dane trasy, pola formularza i ciągi zapytań.
Udostępnia dane kontrolerom i Razor stronom w parametrach metody i właściwościach publicznych.
Konwertuje dane ciągu na typy platformy .NET.
Aktualizuje właściwości typów złożonych.
Przykład
Załóżmy, że masz następującą metodę akcji:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Aplikacja otrzymuje żądanie z następującym adresem URL:
https://contoso.com/api/pets/2?DogsOnly=true
Powiązanie modelu wykonuje następujące kroki po wybraniu przez system routingu metody akcji:
Znajduje pierwszy parametr , GetByIdliczba całkowita o nazwie id.
Przegląda dostępne źródła w żądaniu HTTP i znajduje id = "2" w danych trasy.
Konwertuje ciąg "2" na liczbę całkowitą 2.
Znajduje następny parametr , GetByIdwartość logiczną o nazwie dogsOnly.
Przegląda źródła i znajduje ciąg zapytania "DogsOnly=true". Dopasowywanie nazw nie jest uwzględniane wielkości liter.
Konwertuje ciąg "true" na wartość logiczną true.
Następnie struktura wywołuje metodę GetById , przekazując wartość 2 dla parametru id i true parametru dogsOnly .
W poprzednim przykładzie docelowe powiązania modelu to parametry metody, które są prostymi typami. Obiekty docelowe mogą być również właściwościami typu złożonego. Po pomyślnym powiązaniu każdej właściwości walidacja modelu jest wykonywana dla tej właściwości. Rekord danych powiązanych z modelem oraz wszelkich błędów powiązań lub walidacji jest przechowywany w pliku ControllerBase.ModelState lub PageModel.ModelState. Aby dowiedzieć się, czy ten proces zakończył się pomyślnie, aplikacja sprawdza flagę ModelState.IsValid .
Elementy docelowe
Powiązanie modelu próbuje znaleźć wartości dla następujących rodzajów obiektów docelowych:
Parametry metody akcji kontrolera, do którego jest kierowane żądanie.
Razor Parametry metody obsługi stron, do których jest kierowane żądanie.
Publiczne właściwości kontrolera lub PageModel klasy, jeśli są określone przez atrybuty.
[BindProperty] , atrybut
Można zastosować do właściwości publicznej kontrolera lub PageModel klasy, aby spowodować powiązanie modelu z tą właściwością docelową:
public class EditModel : PageModel
{
[BindProperty]
public Instructor? Instructor { get; set; }
// ...
}
[BindProperties] , atrybut
Można zastosować do kontrolera lub PageModel klasy, aby poinformować powiązanie modelu w celu kierowania wszystkich właściwości publicznych klasy:
[BindProperties]
public class CreateModel : PageModel
{
public Instructor? Instructor { get; set; }
// ...
}
Powiązanie modelu dla żądań HTTP GET
Domyślnie właściwości nie są powiązane z żądaniami HTTP GET. Zazwyczaj wszystko, czego potrzebujesz do żądania GET, to parametr identyfikatora rekordu. Identyfikator rekordu służy do wyszukiwania elementu w bazie danych. W związku z tym nie ma potrzeby wiązania właściwości, która zawiera wystąpienie modelu. W scenariuszach, w których chcesz, aby właściwości powiązane z danymi z żądań GET ustawiły SupportsGet właściwość na true:
Tworzenie prostych i złożonych typów powiązania modelu
Powiązanie modelu używa określonych definicji dla typów, na których działa. Prosty typ jest konwertowany z jednego ciągu przy użyciu TypeConverter metody lub TryParse metody. Typ złożony jest konwertowany z wielu wartości wejściowych. Struktura określa różnicę na podstawie istnienia obiektu TypeConverter lub TryParse. Zalecamy utworzenie konwertera typów lub użycie TryParse metody do stringSomeType konwersji, która nie wymaga zasobów zewnętrznych ani wielu danych wejściowych.
Źródła
Domyślnie powiązanie modelu pobiera dane w postaci par klucz-wartość z następujących źródeł w żądaniu HTTP:
Są dodawane do właściwości modelu indywidualnie, a nie do klasy modelu, jak w poniższym przykładzie:
public class Instructor
{
public int Id { get; set; }
[FromQuery(Name = "Note")]
public string? NoteFromQueryString { get; set; }
// ...
}
Opcjonalnie zaakceptuj wartość nazwy modelu w konstruktorze. Ta opcja jest dostępna w przypadku, gdy nazwa właściwości nie jest zgodna z wartością w żądaniu. Na przykład wartość w żądaniu może być nagłówkiem z łącznikiem w jego nazwie, jak w poniższym przykładzie:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] , atrybut
Zastosuj atrybut do parametru, [FromBody] aby wypełnić jego właściwości z treści żądania HTTP. Środowisko uruchomieniowe ASP.NET Core deleguje odpowiedzialność za odczytywanie treści do elementu formatującego dane wejściowe. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
Po [FromBody] zastosowaniu do parametru typu złożonego wszystkie atrybuty źródła powiązania zastosowane do jego właściwości są ignorowane. Na przykład następująca Create akcja określa, że jego pet parametr jest wypełniany z treści:
public ActionResult<Pet> Create([FromBody] Pet pet)
Klasa Pet określa, że jego Breed właściwość jest wypełniana z parametru ciągu zapytania:
public class Pet
{
public string Name { get; set; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
W powyższym przykładzie:
Atrybut [FromQuery] jest ignorowany.
Właściwość Breed nie jest wypełniana z parametru ciągu zapytania.
Formatery wejściowe odczytują tylko treść i nie rozumieją atrybutów źródła powiązania. Jeśli w treści znajduje się odpowiednia wartość, ta wartość jest używana do wypełnienia Breed właściwości.
Nie należy stosować [FromBody] do więcej niż jednego parametru dla metody akcji. Gdy strumień żądania zostanie odczytany przez program formatujący dane wejściowe, nie będzie już dostępny do ponownego odczytania w celu powiązania innych [FromBody] parametrów.
Dodatkowe źródła
Dane źródłowe są dostarczane do systemu powiązania modelu przez dostawców wartości. Można zapisywać i rejestrować niestandardowych dostawców wartości, którzy pobierają dane na potrzeby powiązania modelu z innych źródeł. Możesz na przykład chcieć dane z plików cookie lub stanu sesji. Aby pobrać dane z nowego źródła:
Utwórz klasę, która implementuje IValueProvider.
Utwórz klasę, która implementuje IValueProviderFactory.
Zarejestruj klasę fabryki w pliku Program.cs.
Przykład zawiera dostawcę wartości i przykład fabryki, który pobiera wartości z plików cookie. Zarejestruj fabryki dostawców wartości niestandardowych w programie Program.cs:
Powyższy kod umieszcza niestandardowego dostawcę wartości po wszystkich wbudowanych dostawcach wartości. Aby ustawić ją jako pierwszą na liście, wywołaj metodę Insert(0, new CookieValueProviderFactory()) zamiast Add.
Brak źródła dla właściwości modelu
Domyślnie błąd stanu modelu nie jest tworzony, jeśli dla właściwości modelu nie zostanie znaleziona żadna wartość. Właściwość jest ustawiona na wartość null lub wartość domyślną:
Typy wartości innych niż null są ustawione na default(T)wartość . Na przykład parametr int id ma wartość 0.
W przypadku złożonych typów powiązanie modelu tworzy wystąpienie przy użyciu konstruktora domyślnego bez ustawiania właściwości.
Tablice są ustawione na Array.Empty<T>(), z tą różnicą, że byte[] tablice są ustawione na null.
Jeśli stan modelu powinien zostać unieważniony, jeśli nic nie zostanie znalezione w polach formularza dla właściwości modelu, użyj atrybutu [BindRequired] .
Należy pamiętać, że to [BindRequired] zachowanie dotyczy powiązania modelu z opublikowanych danych formularza, a nie danych JSON lub XML w treści żądania. Dane treści żądania są obsługiwane przez osoby formatujące dane wejściowe.
Błędy konwersji typów
Jeśli źródło zostanie znalezione, ale nie można go przekonwertować na typ docelowy, stan modelu jest oznaczony jako nieprawidłowy. Docelowy parametr lub właściwość jest ustawiona na wartość null lub wartość domyślną, jak wspomniano w poprzedniej sekcji.
W kontrolerze interfejsu [ApiController] API, który ma atrybut, nieprawidłowy stan modelu powoduje automatyczną odpowiedź HTTP 400.
Razor Na stronie redisplay strony z komunikatem o błędzie:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
Gdy strona jest redisplayed przez poprzedni kod, nieprawidłowe dane wejściowe nie są wyświetlane w polu formularza. Jest to spowodowane tym, że właściwość modelu została ustawiona na wartość null lub wartość domyślną. Nieprawidłowe dane wejściowe są wyświetlane w komunikacie o błędzie. Jeśli chcesz ponownie odtworzyć nieprawidłowe dane w polu formularza, rozważ utworzenie właściwości modelu jako ciągu i ręczne przeprowadzenie konwersji danych.
Ta sama strategia jest zalecana, jeśli nie chcesz, aby błędy konwersji typów powodowały błędy stanu modelu. W takim przypadku utwórz właściwość modelu jako ciąg.
Typy proste
Aby uzyskać wyjaśnienie prostych i złożonych typów, zobacz Powiązania modelu proste i złożone typy.
Proste typy, które binder modelu mogą konwertować ciągi źródłowe na następujące:
public static bool TryParse (string? s, IFormatProvider? provider, out TSelf result);
DateRange Następująca klasa implementuje IParsable<TSelf> obsługę powiązania zakresu dat:
public class DateRange : IParsable<DateRange>
{
public DateOnly? From { get; init; }
public DateOnly? To { get; init; }
public static DateRange Parse(string value, IFormatProvider? provider)
{
if (!TryParse(value, provider, out var result))
{
throw new ArgumentException("Could not parse supplied value.", nameof(value));
}
return result;
}
public static bool TryParse(string? value,
IFormatProvider? provider, out DateRange dateRange)
{
var segments = value?.Split(',', StringSplitOptions.RemoveEmptyEntries
| StringSplitOptions.TrimEntries);
if (segments?.Length == 2
&& DateOnly.TryParse(segments[0], provider, out var fromDate)
&& DateOnly.TryParse(segments[1], provider, out var toDate))
{
dateRange = new DateRange { From = fromDate, To = toDate };
return true;
}
dateRange = new DateRange { From = default, To = default };
return false;
}
}
Powyższy kod ma następujące działanie:
Konwertuje ciąg reprezentujący dwie daty na DateRange obiekt
Interfejs TryParse API obsługuje wartości parametrów akcji kontrolera powiązania:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
IParsable<T>.TryParse jest zalecanym podejściem do powiązania parametrów, ponieważ w przeciwieństwie do TryParsemetody , nie zależy od odbicia.
DateRangeTP Następująca klasa implementuje TryParseelement :
public class DateRangeTP
{
public DateOnly? From { get; }
public DateOnly? To { get; }
public DateRangeTP(string from, string to)
{
if (string.IsNullOrEmpty(from))
throw new ArgumentNullException(nameof(from));
if (string.IsNullOrEmpty(to))
throw new ArgumentNullException(nameof(to));
From = DateOnly.Parse(from);
To = DateOnly.Parse(to);
}
public static bool TryParse(string? value, out DateRangeTP? result)
{
var range = value?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (range?.Length != 2)
{
result = default;
return false;
}
result = new DateRangeTP(range[0], range[1]);
return true;
}
}
Następująca akcja kontrolera używa DateRangeTP klasy do powiązania zakresu dat:
// GET /WeatherForecast/ByRangeTP?range=7/24/2022,07/26/2022
public IActionResult ByRangeTP([FromQuery] DateRangeTP range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= range.From
&& DateOnly.FromDateTime(wf.Date) <= range.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d"),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Typy złożone
Typ złożony musi mieć publiczny konstruktor domyślny i publiczne właściwości zapisywalne do powiązania. Po utworzeniu powiązania modelu klasę tworzy się przy użyciu publicznego konstruktora domyślnego.
Dla każdej właściwości typu złożonego powiązanie modelu analizuje źródła wzorca nazwprefix.property_name. Jeśli nic nie zostanie znalezione, szuka tylko property_name bez prefiksu. Decyzja o użyciu prefiksu nie jest podjęta na właściwość. Na przykład z zapytaniem zawierającym ?Instructor.Id=100&Name=foometodę , powiązana z metodą OnGet(Instructor instructor), wynikowy obiekt typu Instructor zawiera:
Id ustaw wartość 100.
Name ustaw wartość null. Powiązanie modelu oczekuje, Instructor.Name ponieważ Instructor.Id zostało użyte w poprzednim parametrze zapytania.
W przypadku powiązania z parametrem prefiks jest nazwą parametru. W przypadku powiązania z właściwością publiczną PageModel prefiks jest nazwą właściwości publicznej. Niektóre atrybuty mają Prefix właściwość, która umożliwia zastąpienie domyślnego użycia parametru lub nazwy właściwości.
Załóżmy na przykład, że typ złożony to następująca Instructor klasa:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Prefiks = nazwa parametru
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza instructorToUpdate.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks = nazwa właściwości
Jeśli model, który ma być powiązany, jest właściwością o nazwie Instructor kontrolera lub PageModel klasy:
[BindProperty]
public Instructor Instructor { get; set; }
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks niestandardowy
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate , a Bind atrybut określa Instructor jako prefiks:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Atrybuty dla obiektów docelowych typu złożonego
Dostępnych jest kilka wbudowanych atrybutów do kontrolowania powiązania modelu typów złożonych:
Te atrybuty wpływają na powiązanie modelu, gdy opublikowane dane formularza są źródłem wartości. Nie mają one wpływu na formatery danych wejściowych, które przetwarzają treść żądań JSON i XML. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
[Bind] , atrybut
Można zastosować do klasy lub parametru metody. Określa, które właściwości modelu powinny być uwzględnione w powiązaniu modelu. [Bind]nie ma wpływu na formatery wejściowe.
W poniższym przykładzie tylko określone właściwości Instructor modelu są powiązane, gdy wywoływana jest dowolna metoda obsługi lub akcji:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
W poniższym przykładzie po wywołaniu OnPost metody są powiązane tylko określone właściwości Instructor modelu:
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atrybut [Bind] może służyć do ochrony przed przesłanianiem w scenariuszach tworzenia . Nie działa dobrze w scenariuszach edycji, ponieważ wykluczone właściwości są ustawione na wartość null lub wartość domyślną, a nie pozostawione bez zmian. W przypadku ochrony przed przesłanianiem zalecane są modele wyświetlania, a nie atrybut.[Bind] Aby uzyskać więcej informacji, zobacz Uwaga dotycząca zabezpieczeń dotycząca zastępowania.
[ModelBinder] , atrybut
ModelBinderAttribute można stosować do typów, właściwości lub parametrów. Umożliwia określenie typu powiązania modelu używanego do powiązania określonego wystąpienia lub typu. Na przykład:
[HttpPost]
public IActionResult OnPost(
[ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)
Atrybut [ModelBinder] może również służyć do zmiany nazwy właściwości lub parametru, gdy jest powiązany model:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
// ...
}
[BindRequired] , atrybut
Powoduje, że powiązanie modelu powoduje dodanie błędu stanu modelu, jeśli powiązanie nie może wystąpić dla właściwości modelu. Oto przykład:
public class InstructorBindRequired
{
// ...
[BindRequired]
public DateTime HireDate { get; set; }
}
Zobacz również omówienie atrybutu [Required] w temacie Walidacja modelu.
[BindNever] , atrybut
Można zastosować do właściwości lub typu. Uniemożliwia ustawienie właściwości modelu przez powiązanie modelu. Po zastosowaniu do typu system powiązań modelu wyklucza wszystkie właściwości zdefiniowane przez typ. Oto przykład:
public class InstructorBindNever
{
[BindNever]
public int Id { get; set; }
// ...
}
Kolekcje
W przypadku obiektów docelowych, które są kolekcjami prostych typów, powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr, który ma być powiązany, to tablica o nazwie selectedCourses:
public IActionResult OnPost(int? id, int[] selectedCourses)
Dane formularza lub ciągu zapytania mogą być w jednym z następujących formatów:
Unikaj powiązania parametru lub właściwości o nazwie index lub Index , jeśli sąsiaduje z wartością kolekcji. Powiązanie modelu próbuje użyć index jako indeksu kolekcji, co może spowodować nieprawidłowe powiązanie. Rozważmy na przykład następującą akcję:
public IActionResult Post(string index, List<Product> products)
W poprzednim kodzie index parametr ciągu zapytania jest powiązany z parametrem index metody, a także jest używany do powiązania kolekcji produktów. Zmiana nazwy parametru index lub użycie atrybutu powiązania modelu w celu skonfigurowania powiązania pozwala uniknąć tego problemu:
public IActionResult Post(string productIndex, List<Product> products)
Następujący format jest obsługiwany tylko w danych formularza:
selectedCourses[]=1050&selectedCourses[]=2000
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje tablicę dwóch elementów do parametru selectedCourses :
selectedCourses[0]=1050
selectedCourses[1]=2000
Formaty danych używające liczb w indeksie dolnym (... [0] ... [1] ...) musi upewnić się, że są one numerowane sekwencyjnie rozpoczynające się od zera. Jeśli występują luki w numerowaniu indeksu dolnego, wszystkie elementy po przerwie są ignorowane. Jeśli na przykład indeksy dolny to 0 i 2 zamiast 0 i 1, drugi element jest ignorowany.
Słowniki
W przypadku Dictionary obiektów docelowych powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr docelowy Dictionary<int, string> ma nazwę selectedCourses:
public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Dane opublikowanego formularza lub ciągu zapytania mogą wyglądać podobnie do jednego z następujących przykładów:
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje słownik dwóch elementów do parametru selectedCourses :
selectedCourses["1050"]="Chemistry"
selectedCourses["2000"]="Economics"
Powiązanie konstruktora i typy rekordów
Powiązanie modelu wymaga, aby złożone typy miały konstruktor bez parametrów. Zarówno System.Text.Json metody formatowania danych wejściowych, jak i Newtonsoft.Json obsługują deserializację klas, które nie mają konstruktora bez parametrów.
Typy rekordów to doskonały sposób, aby zwięźle reprezentować dane za pośrednictwem sieci. ASP.NET Core obsługuje wiązanie modelu i weryfikowanie typów rekordów za pomocą jednego konstruktora:
public record Person(
[Required] string Name, [Range(0, 150)] int Age, [BindNever] int Id);
public class PersonController
{
public IActionResult Index() => View();
[HttpPost]
public IActionResult Index(Person person)
{
// ...
}
}
Podczas sprawdzania poprawności typów rekordów środowisko uruchomieniowe wyszukuje metadane powiązania i walidacji w szczególności na parametrach, a nie we właściwościach.
Platforma umożliwia wiązanie i weryfikowanie typów rekordów:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Aby poprzedni element działał, typ musi:
Być typem rekordu.
Mieć dokładnie jeden publiczny konstruktor.
Zawierają parametry, które mają właściwość o tej samej nazwie i typie. Nazwy nie mogą się różnić literami.
Obiekty POCO bez konstruktorów bez parametrów
Obiekty POC, które nie mają konstruktorów bez parametrów, nie mogą być powiązane.
Poniższy kod powoduje wyjątek z informacją, że typ musi mieć konstruktor bez parametrów:
public class Person(string Name)
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0);
}
Typy rekordów z ręcznie utworzonymi konstruktorami
Typy rekordów z ręcznie utworzonymi konstruktorami, które wyglądają jak konstruktory podstawowe działają
public record Person
{
public Person([Required] string Name, [Range(0, 100)] int Age)
=> (this.Name, this.Age) = (Name, Age);
public string Name { get; set; }
public int Age { get; set; }
}
Typy rekordów, walidacja i metadane powiązania
W przypadku typów rekordów używane są metadane walidacji i powiązania parametrów. Wszystkie metadane właściwości są ignorowane
public record Person (string Name, int Age)
{
[BindProperty(Name = "SomeName")] // This does not get used
[Required] // This does not get used
public string Name { get; init; }
}
Walidacja i metadane
Walidacja używa metadanych w parametrze, ale używa właściwości do odczytania wartości. W zwykłych przypadkach z konstruktorami podstawowymi te dwa byłyby identyczne. Istnieją jednak sposoby, aby go pokonać:
public record Person([Required] string Name)
{
private readonly string _name;
// The following property is never null.
// However this object could have been constructed as "new Person(null)".
public string Name { get; init => _name = value ?? string.Empty; }
}
Funkcja TryUpdateModel nie aktualizuje parametrów typu rekordu
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
W takim przypadku usługa MVC nie podejmie ponownej próby powiązania Name . Age Można jednak zaktualizować
Zachowanie globalizacji danych trasy powiązania modelu i ciągów zapytań
Dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania:
Traktuj wartości jako niezmienną kulturę.
Spodziewaj się, że adresy URL są niezmienne dla kultury.
Natomiast wartości pochodzące z danych formularza są poddawane konwersji wrażliwej na kulturę. Jest to zaprojektowane tak, aby adresy URL można udostępniać między ustawieniami regionalnymi.
Aby dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania przeszedł konwersję wrażliwą na kulturę:
Zastąp domyślną fabrykę dostawcy wartości w opcjach MVC nowym:
public class CultureQueryStringValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
_ = context ?? throw new ArgumentNullException(nameof(context));
var query = context.ActionContext.HttpContext.Request.Query;
if (query?.Count > 0)
{
context.ValueProviders.Add(
new QueryStringValueProvider(
BindingSource.Query,
query,
CultureInfo.CurrentCulture));
}
return Task.CompletedTask;
}
}
builder.Services.AddControllers(options =>
{
var index = options.ValueProviderFactories.IndexOf(
options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>()
.Single());
options.ValueProviderFactories[index] =
new CultureQueryStringValueProviderFactory();
});
Specjalne typy danych
Istnieją pewne specjalne typy danych, które mogą obsłużyć powiązanie modelu.
IFormFile i IFormFileCollection
Przekazany plik uwzględniony w żądaniu HTTP. Obsługiwane jest IEnumerable<IFormFile> również w przypadku wielu plików.
CancellationToken
Akcje mogą opcjonalnie powiązać element CancellationToken jako parametr. RequestAborted Wiąże się to z sygnałem, gdy połączenie bazowe żądania HTTP zostanie przerwane. Akcje mogą używać tego parametru do anulowania długotrwałych operacji asynchronicznych wykonywanych w ramach akcji kontrolera.
FormCollection
Służy do pobierania wszystkich wartości z opublikowanych danych formularza.
Formatery danych wejściowych
Dane w treści żądania mogą być w formacie JSON, XML lub innym formacie. Aby przeanalizować te dane, powiązanie modelu używa formatującego danych wejściowych skonfigurowanego do obsługi określonego typu zawartości. Domyślnie ASP.NET Core zawiera formatery wejściowe oparte na formacie JSON do obsługi danych JSON. Możesz dodać inne formatery dla innych typów zawartości.
ASP.NET Core wybiera formatery wejściowe na podstawie atrybutu Consumes . Jeśli atrybut nie jest obecny, używa nagłówka Content-Type.
Dostosowywanie powiązania modelu za pomocą formaterów wejściowych
Moduł formatujący dane wejściowe ponosi pełną odpowiedzialność za odczytywanie danych z treści żądania. Aby dostosować ten proces, skonfiguruj interfejsy API używane przez program formatujący dane wejściowe. W tej sekcji opisano sposób dostosowywania opartego na formatatorze System.Text.Jsondanych wejściowych w celu zrozumienia niestandardowego typu o nazwie ObjectId.
Rozważmy następujący model, który zawiera właściwość niestandardową ObjectId :
public class InstructorObjectId
{
[Required]
public ObjectId ObjectId { get; set; } = null!;
}
Aby dostosować proces powiązania modelu podczas używania metody System.Text.Json, utwórz klasę pochodzącą z JsonConverter<T>klasy :
internal class ObjectIdConverter : JsonConverter<ObjectId>
{
public override ObjectId Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> new(JsonSerializer.Deserialize<int>(ref reader, options));
public override void Write(
Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
=> writer.WriteNumberValue(value.Id);
}
Aby użyć konwertera niestandardowego, zastosuj JsonConverterAttribute atrybut do typu. W poniższym przykładzie ObjectId typ jest skonfigurowany ObjectIdConverter jako konwerter niestandardowy:
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
Zachowanie systemów powiązań i walidacji modelu jest sterowane przez ModelMetadataprogram . Możesz dostosować ModelMetadata , dodając dostawcę szczegółów do elementu MvcOptions.ModelMetadataDetailsProviders. Wbudowani dostawcy szczegółów są dostępni do wyłączania powiązania modelu lub walidacji dla określonych typów.
Aby wyłączyć powiązanie modelu dla wszystkich modeli określonego typu, dodaj element w elemExcludeBindingMetadataProvider.Program.cs Aby na przykład wyłączyć powiązanie modelu dla wszystkich modeli typu System.Version:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Aby wyłączyć walidację właściwości określonego typu, dodaj element SuppressChildValidationMetadataProvider w Program.cspliku . Aby na przykład wyłączyć walidację właściwości typu System.Guid:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Niestandardowe powiązania modelu
Powiązanie modelu można rozszerzyć, pisząc powiązanie modelu niestandardowego i używając atrybutu [ModelBinder] , aby wybrać go dla danego obiektu docelowego. Dowiedz się więcej o powiązaniu modelu niestandardowego.
Ręczne powiązanie modelu
Powiązanie modelu można wywołać ręcznie przy użyciu TryUpdateModelAsync metody . Metoda jest definiowana w klasach ControllerBase i PageModel . Przeciążenia metody umożliwiają określenie prefiksu i dostawcy wartości do użycia. Metoda zwraca false wartość , jeśli powiązanie modelu nie powiedzie się. Oto przykład:
if (await TryUpdateModelAsync(
newInstructor,
"Instructor",
x => x.Name, x => x.HireDate!))
{
_instructorStore.Add(newInstructor);
return RedirectToPage("./Index");
}
return Page();
TryUpdateModelAsync używa dostawców wartości do pobierania danych z treści formularza, ciągu zapytania i kierowania danych. TryUpdateModelAsync jest zwykle:
Używane z aplikacjami Razor Pages i MVC przy użyciu kontrolerów i widoków, aby zapobiec nadmiernemu delegowaniu.
Nie jest używany z internetowym interfejsem API, chyba że są używane z danych formularza, ciągów zapytań i danych trasy. Punkty końcowe internetowego interfejsu API, które używają formatu JSON, używają formatatorów wejściowych do deserializacji treści żądania do obiektu.
Nazwa tego atrybutu jest zgodna ze wzorcem atrybutów powiązania modelu, które określają źródło danych. Nie chodzi jednak o powiązanie danych od dostawcy wartości. Pobiera wystąpienie typu z kontenera wstrzykiwania zależności. Jego celem jest zapewnienie alternatywy dla iniekcji konstruktora, jeśli potrzebujesz usługi tylko wtedy, gdy wywoływana jest określona metoda.
Jeśli wystąpienie typu nie jest zarejestrowane w kontenerze wstrzykiwania zależności, aplikacja zgłasza wyjątek podczas próby powiązania parametru. Aby ustawić parametr jako opcjonalny, użyj jednego z następujących metod:
Ustaw parametr na wartość null.
Ustaw wartość domyślną parametru.
W przypadku parametrów dopuszczających wartość null upewnij się, że parametr nie null jest używany przed uzyskaniem do niego dostępu.
W tym artykule wyjaśniono, czym jest powiązanie modelu, jak działa i jak dostosować jego zachowanie.
Co to jest powiązanie modelu
Kontrolery i Razor strony współpracują z danymi pochodzącymi z żądań HTTP. Na przykład dane trasy mogą zawierać klucz rekordu, a opublikowane pola formularza mogą zawierać wartości właściwości modelu. Pisanie kodu w celu pobrania każdej z tych wartości i przekonwertowanie ich z ciągów na typy platformy .NET byłoby żmudne i podatne na błędy. Powiązanie modelu automatyzuje ten proces. System powiązania modelu:
Pobiera dane z różnych źródeł, takich jak dane trasy, pola formularza i ciągi zapytań.
Udostępnia dane kontrolerom i Razor stronom w parametrach metody i właściwościach publicznych.
Konwertuje dane ciągu na typy platformy .NET.
Aktualizuje właściwości typów złożonych.
Przykład
Załóżmy, że masz następującą metodę akcji:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Aplikacja otrzymuje żądanie z następującym adresem URL:
https://contoso.com/api/pets/2?DogsOnly=true
Powiązanie modelu wykonuje następujące kroki po wybraniu przez system routingu metody akcji:
Znajduje pierwszy parametr , GetByIdliczba całkowita o nazwie id.
Przegląda dostępne źródła w żądaniu HTTP i znajduje id = "2" w danych trasy.
Konwertuje ciąg "2" na liczbę całkowitą 2.
Znajduje następny parametr , GetByIdwartość logiczną o nazwie dogsOnly.
Przegląda źródła i znajduje ciąg zapytania "DogsOnly=true". Dopasowywanie nazw nie jest uwzględniane wielkości liter.
Konwertuje ciąg "true" na wartość logiczną true.
Następnie struktura wywołuje metodę GetById , przekazując wartość 2 dla parametru id i true parametru dogsOnly .
W poprzednim przykładzie docelowe powiązania modelu to parametry metody, które są prostymi typami. Obiekty docelowe mogą być również właściwościami typu złożonego. Po pomyślnym powiązaniu każdej właściwości walidacja modelu jest wykonywana dla tej właściwości. Rekord danych powiązanych z modelem oraz wszelkich błędów powiązań lub walidacji jest przechowywany w pliku ControllerBase.ModelState lub PageModel.ModelState. Aby dowiedzieć się, czy ten proces zakończył się pomyślnie, aplikacja sprawdza flagę ModelState.IsValid .
Elementy docelowe
Powiązanie modelu próbuje znaleźć wartości dla następujących rodzajów obiektów docelowych:
Parametry metody akcji kontrolera, do którego jest kierowane żądanie.
Razor Parametry metody obsługi stron, do których jest kierowane żądanie.
Publiczne właściwości kontrolera lub PageModel klasy, jeśli są określone przez atrybuty.
[BindProperty] , atrybut
Można zastosować do właściwości publicznej kontrolera lub PageModel klasy, aby spowodować powiązanie modelu z tą właściwością docelową:
public class EditModel : PageModel
{
[BindProperty]
public Instructor? Instructor { get; set; }
// ...
}
[BindProperties] , atrybut
Można zastosować do kontrolera lub PageModel klasy, aby poinformować powiązanie modelu w celu kierowania wszystkich właściwości publicznych klasy:
[BindProperties]
public class CreateModel : PageModel
{
public Instructor? Instructor { get; set; }
// ...
}
Powiązanie modelu dla żądań HTTP GET
Domyślnie właściwości nie są powiązane z żądaniami HTTP GET. Zazwyczaj wszystko, czego potrzebujesz do żądania GET, to parametr identyfikatora rekordu. Identyfikator rekordu służy do wyszukiwania elementu w bazie danych. W związku z tym nie ma potrzeby wiązania właściwości, która zawiera wystąpienie modelu. W scenariuszach, w których chcesz, aby właściwości powiązane z danymi z żądań GET ustawiły SupportsGet właściwość na true:
Są dodawane do właściwości modelu indywidualnie, a nie do klasy modelu, jak w poniższym przykładzie:
public class Instructor
{
public int Id { get; set; }
[FromQuery(Name = "Note")]
public string? NoteFromQueryString { get; set; }
// ...
}
Opcjonalnie zaakceptuj wartość nazwy modelu w konstruktorze. Ta opcja jest dostępna w przypadku, gdy nazwa właściwości nie jest zgodna z wartością w żądaniu. Na przykład wartość w żądaniu może być nagłówkiem z łącznikiem w jego nazwie, jak w poniższym przykładzie:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] , atrybut
Zastosuj atrybut do parametru, [FromBody] aby wypełnić jego właściwości z treści żądania HTTP. Środowisko uruchomieniowe ASP.NET Core deleguje odpowiedzialność za odczytywanie treści do elementu formatującego dane wejściowe. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
Po [FromBody] zastosowaniu do parametru typu złożonego wszystkie atrybuty źródła powiązania zastosowane do jego właściwości są ignorowane. Na przykład następująca Create akcja określa, że jego pet parametr jest wypełniany z treści:
public ActionResult<Pet> Create([FromBody] Pet pet)
Klasa Pet określa, że jego Breed właściwość jest wypełniana z parametru ciągu zapytania:
public class Pet
{
public string Name { get; set; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
W powyższym przykładzie:
Atrybut [FromQuery] jest ignorowany.
Właściwość Breed nie jest wypełniana z parametru ciągu zapytania.
Formatery wejściowe odczytują tylko treść i nie rozumieją atrybutów źródła powiązania. Jeśli w treści znajduje się odpowiednia wartość, ta wartość jest używana do wypełnienia Breed właściwości.
Nie należy stosować [FromBody] do więcej niż jednego parametru dla metody akcji. Gdy strumień żądania zostanie odczytany przez program formatujący dane wejściowe, nie będzie już dostępny do ponownego odczytania w celu powiązania innych [FromBody] parametrów.
Dodatkowe źródła
Dane źródłowe są dostarczane do systemu powiązania modelu przez dostawców wartości. Można zapisywać i rejestrować niestandardowych dostawców wartości, którzy pobierają dane na potrzeby powiązania modelu z innych źródeł. Możesz na przykład chcieć dane z plików cookie lub stanu sesji. Aby pobrać dane z nowego źródła:
Utwórz klasę, która implementuje IValueProvider.
Utwórz klasę, która implementuje IValueProviderFactory.
Zarejestruj klasę fabryki w pliku Program.cs.
Przykład zawiera dostawcę wartości i przykład fabryki, który pobiera wartości z plików cookie. Zarejestruj fabryki dostawców wartości niestandardowych w programie Program.cs:
Powyższy kod umieszcza niestandardowego dostawcę wartości po wszystkich wbudowanych dostawcach wartości. Aby ustawić ją jako pierwszą na liście, wywołaj metodę Insert(0, new CookieValueProviderFactory()) zamiast Add.
Brak źródła dla właściwości modelu
Domyślnie błąd stanu modelu nie jest tworzony, jeśli dla właściwości modelu nie zostanie znaleziona żadna wartość. Właściwość jest ustawiona na wartość null lub wartość domyślną:
Proste typy dopuszczane do wartości null są ustawione na nullwartość .
Typy wartości innych niż null są ustawione na default(T)wartość . Na przykład parametr int id ma wartość 0.
W przypadku złożonych typów powiązanie modelu tworzy wystąpienie przy użyciu konstruktora domyślnego bez ustawiania właściwości.
Tablice są ustawione na Array.Empty<T>(), z tą różnicą, że byte[] tablice są ustawione na null.
Jeśli stan modelu powinien zostać unieważniony, jeśli nic nie zostanie znalezione w polach formularza dla właściwości modelu, użyj atrybutu [BindRequired] .
Należy pamiętać, że to [BindRequired] zachowanie dotyczy powiązania modelu z opublikowanych danych formularza, a nie danych JSON lub XML w treści żądania. Dane treści żądania są obsługiwane przez osoby formatujące dane wejściowe.
Błędy konwersji typów
Jeśli źródło zostanie znalezione, ale nie można go przekonwertować na typ docelowy, stan modelu jest oznaczony jako nieprawidłowy. Docelowy parametr lub właściwość jest ustawiona na wartość null lub wartość domyślną, jak wspomniano w poprzedniej sekcji.
W kontrolerze interfejsu [ApiController] API, który ma atrybut, nieprawidłowy stan modelu powoduje automatyczną odpowiedź HTTP 400.
Razor Na stronie redisplay strony z komunikatem o błędzie:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
Gdy strona jest redisplayed przez poprzedni kod, nieprawidłowe dane wejściowe nie są wyświetlane w polu formularza. Jest to spowodowane tym, że właściwość modelu została ustawiona na wartość null lub wartość domyślną. Nieprawidłowe dane wejściowe są wyświetlane w komunikacie o błędzie. Jeśli chcesz ponownie odtworzyć nieprawidłowe dane w polu formularza, rozważ utworzenie właściwości modelu jako ciągu i ręczne przeprowadzenie konwersji danych.
Ta sama strategia jest zalecana, jeśli nie chcesz, aby błędy konwersji typów powodowały błędy stanu modelu. W takim przypadku utwórz właściwość modelu jako ciąg.
Typy proste
Proste typy, które binder modelu mogą konwertować ciągi źródłowe na następujące:
Typ złożony musi mieć publiczny konstruktor domyślny i publiczne właściwości zapisywalne do powiązania. Po utworzeniu powiązania modelu klasę tworzy się przy użyciu publicznego konstruktora domyślnego.
Dla każdej właściwości typu złożonego powiązanie modelu analizuje źródła wzorca nazwprefix.property_name. Jeśli nic nie zostanie znalezione, szuka tylko property_name bez prefiksu. Decyzja o użyciu prefiksu nie jest podjęta na właściwość. Na przykład z zapytaniem zawierającym ?Instructor.Id=100&Name=foometodę , powiązana z metodą OnGet(Instructor instructor), wynikowy obiekt typu Instructor zawiera:
Id ustaw wartość 100.
Name ustaw wartość null. Powiązanie modelu oczekuje, Instructor.Name ponieważ Instructor.Id zostało użyte w poprzednim parametrze zapytania.
W przypadku powiązania z parametrem prefiks jest nazwą parametru. W przypadku powiązania z właściwością publiczną PageModel prefiks jest nazwą właściwości publicznej. Niektóre atrybuty mają Prefix właściwość, która umożliwia zastąpienie domyślnego użycia parametru lub nazwy właściwości.
Załóżmy na przykład, że typ złożony to następująca Instructor klasa:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Prefiks = nazwa parametru
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza instructorToUpdate.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks = nazwa właściwości
Jeśli model, który ma być powiązany, jest właściwością o nazwie Instructor kontrolera lub PageModel klasy:
[BindProperty]
public Instructor Instructor { get; set; }
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks niestandardowy
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate , a Bind atrybut określa Instructor jako prefiks:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Atrybuty dla obiektów docelowych typu złożonego
Dostępnych jest kilka wbudowanych atrybutów do kontrolowania powiązania modelu typów złożonych:
Te atrybuty wpływają na powiązanie modelu, gdy opublikowane dane formularza są źródłem wartości. Nie mają one wpływu na formatery danych wejściowych, które przetwarzają treść żądań JSON i XML. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
[Bind] , atrybut
Można zastosować do klasy lub parametru metody. Określa, które właściwości modelu powinny być uwzględnione w powiązaniu modelu. [Bind]nie ma wpływu na formatery wejściowe.
W poniższym przykładzie tylko określone właściwości Instructor modelu są powiązane, gdy wywoływana jest dowolna metoda obsługi lub akcji:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
W poniższym przykładzie po wywołaniu OnPost metody są powiązane tylko określone właściwości Instructor modelu:
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atrybut [Bind] może służyć do ochrony przed przesłanianiem w scenariuszach tworzenia . Nie działa dobrze w scenariuszach edycji, ponieważ wykluczone właściwości są ustawione na wartość null lub wartość domyślną, a nie pozostawione bez zmian. W przypadku ochrony przed przesłanianiem zalecane są modele wyświetlania, a nie atrybut.[Bind] Aby uzyskać więcej informacji, zobacz Uwaga dotycząca zabezpieczeń dotycząca zastępowania.
[ModelBinder] , atrybut
ModelBinderAttribute można stosować do typów, właściwości lub parametrów. Umożliwia określenie typu powiązania modelu używanego do powiązania określonego wystąpienia lub typu. Na przykład:
[HttpPost]
public IActionResult OnPost(
[ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)
Atrybut [ModelBinder] może również służyć do zmiany nazwy właściwości lub parametru, gdy jest powiązany model:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
// ...
}
[BindRequired] , atrybut
Powoduje, że powiązanie modelu powoduje dodanie błędu stanu modelu, jeśli powiązanie nie może wystąpić dla właściwości modelu. Oto przykład:
public class InstructorBindRequired
{
// ...
[BindRequired]
public DateTime HireDate { get; set; }
}
Zobacz również omówienie atrybutu [Required] w temacie Walidacja modelu.
[BindNever] , atrybut
Można zastosować do właściwości lub typu. Uniemożliwia ustawienie właściwości modelu przez powiązanie modelu. Po zastosowaniu do typu system powiązań modelu wyklucza wszystkie właściwości zdefiniowane przez typ. Oto przykład:
public class InstructorBindNever
{
[BindNever]
public int Id { get; set; }
// ...
}
Kolekcje
W przypadku obiektów docelowych, które są kolekcjami prostych typów, powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr, który ma być powiązany, to tablica o nazwie selectedCourses:
public IActionResult OnPost(int? id, int[] selectedCourses)
Dane formularza lub ciągu zapytania mogą być w jednym z następujących formatów:
Unikaj powiązania parametru lub właściwości o nazwie index lub Index , jeśli sąsiaduje z wartością kolekcji. Powiązanie modelu próbuje użyć index jako indeksu kolekcji, co może spowodować nieprawidłowe powiązanie. Rozważmy na przykład następującą akcję:
public IActionResult Post(string index, List<Product> products)
W poprzednim kodzie index parametr ciągu zapytania jest powiązany z parametrem index metody, a także jest używany do powiązania kolekcji produktów. Zmiana nazwy parametru index lub użycie atrybutu powiązania modelu w celu skonfigurowania powiązania pozwala uniknąć tego problemu:
public IActionResult Post(string productIndex, List<Product> products)
Następujący format jest obsługiwany tylko w danych formularza:
selectedCourses[]=1050&selectedCourses[]=2000
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje tablicę dwóch elementów do parametru selectedCourses :
selectedCourses[0]=1050
selectedCourses[1]=2000
Formaty danych używające liczb w indeksie dolnym (... [0] ... [1] ...) musi upewnić się, że są one numerowane sekwencyjnie rozpoczynające się od zera. Jeśli występują luki w numerowaniu indeksu dolnego, wszystkie elementy po przerwie są ignorowane. Jeśli na przykład indeksy dolny to 0 i 2 zamiast 0 i 1, drugi element jest ignorowany.
Słowniki
W przypadku Dictionary obiektów docelowych powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr docelowy Dictionary<int, string> ma nazwę selectedCourses:
public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Dane opublikowanego formularza lub ciągu zapytania mogą wyglądać podobnie do jednego z następujących przykładów:
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje słownik dwóch elementów do parametru selectedCourses :
selectedCourses["1050"]="Chemistry"
selectedCourses["2000"]="Economics"
Powiązanie konstruktora i typy rekordów
Powiązanie modelu wymaga, aby złożone typy miały konstruktor bez parametrów. Zarówno System.Text.Json metody formatowania danych wejściowych, jak i Newtonsoft.Json obsługują deserializację klas, które nie mają konstruktora bez parametrów.
Typy rekordów to doskonały sposób, aby zwięźle reprezentować dane za pośrednictwem sieci. ASP.NET Core obsługuje wiązanie modelu i weryfikowanie typów rekordów za pomocą jednego konstruktora:
public record Person(
[Required] string Name, [Range(0, 150)] int Age, [BindNever] int Id);
public class PersonController
{
public IActionResult Index() => View();
[HttpPost]
public IActionResult Index(Person person)
{
// ...
}
}
Podczas sprawdzania poprawności typów rekordów środowisko uruchomieniowe wyszukuje metadane powiązania i walidacji w szczególności na parametrach, a nie we właściwościach.
Platforma umożliwia wiązanie i weryfikowanie typów rekordów:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Aby poprzedni element działał, typ musi:
Być typem rekordu.
Mieć dokładnie jeden publiczny konstruktor.
Zawierają parametry, które mają właściwość o tej samej nazwie i typie. Nazwy nie mogą się różnić literami.
Obiekty POCO bez konstruktorów bez parametrów
Obiekty POC, które nie mają konstruktorów bez parametrów, nie mogą być powiązane.
Poniższy kod powoduje wyjątek z informacją, że typ musi mieć konstruktor bez parametrów:
public class Person(string Name)
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0);
}
Typy rekordów z ręcznie utworzonymi konstruktorami
Typy rekordów z ręcznie utworzonymi konstruktorami, które wyglądają jak konstruktory podstawowe działają
public record Person
{
public Person([Required] string Name, [Range(0, 100)] int Age)
=> (this.Name, this.Age) = (Name, Age);
public string Name { get; set; }
public int Age { get; set; }
}
Typy rekordów, walidacja i metadane powiązania
W przypadku typów rekordów używane są metadane walidacji i powiązania parametrów. Wszystkie metadane właściwości są ignorowane
public record Person (string Name, int Age)
{
[BindProperty(Name = "SomeName")] // This does not get used
[Required] // This does not get used
public string Name { get; init; }
}
Walidacja i metadane
Walidacja używa metadanych w parametrze, ale używa właściwości do odczytania wartości. W zwykłych przypadkach z konstruktorami podstawowymi te dwa byłyby identyczne. Istnieją jednak sposoby, aby go pokonać:
public record Person([Required] string Name)
{
private readonly string _name;
// The following property is never null.
// However this object could have been constructed as "new Person(null)".
public string Name { get; init => _name = value ?? string.Empty; }
}
Funkcja TryUpdateModel nie aktualizuje parametrów typu rekordu
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
W takim przypadku usługa MVC nie podejmie ponownej próby powiązania Name . Age Można jednak zaktualizować
Zachowanie globalizacji danych trasy powiązania modelu i ciągów zapytań
Dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania:
Traktuj wartości jako niezmienną kulturę.
Spodziewaj się, że adresy URL są niezmienne dla kultury.
Natomiast wartości pochodzące z danych formularza są poddawane konwersji wrażliwej na kulturę. Jest to zaprojektowane tak, aby adresy URL można udostępniać między ustawieniami regionalnymi.
Aby dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania przeszedł konwersję wrażliwą na kulturę:
Zastąp domyślną fabrykę dostawcy wartości w opcjach MVC nowym:
public class CultureQueryStringValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
_ = context ?? throw new ArgumentNullException(nameof(context));
var query = context.ActionContext.HttpContext.Request.Query;
if (query?.Count > 0)
{
context.ValueProviders.Add(
new QueryStringValueProvider(
BindingSource.Query,
query,
CultureInfo.CurrentCulture));
}
return Task.CompletedTask;
}
}
builder.Services.AddControllers(options =>
{
var index = options.ValueProviderFactories.IndexOf(
options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>()
.Single());
options.ValueProviderFactories[index] =
new CultureQueryStringValueProviderFactory();
});
Specjalne typy danych
Istnieją pewne specjalne typy danych, które mogą obsłużyć powiązanie modelu.
IFormFile i IFormFileCollection
Przekazany plik uwzględniony w żądaniu HTTP. Obsługiwane jest IEnumerable<IFormFile> również w przypadku wielu plików.
CancellationToken
Akcje mogą opcjonalnie powiązać element CancellationToken jako parametr. RequestAborted Wiąże się to z sygnałem, gdy połączenie bazowe żądania HTTP zostanie przerwane. Akcje mogą używać tego parametru do anulowania długotrwałych operacji asynchronicznych wykonywanych w ramach akcji kontrolera.
FormCollection
Służy do pobierania wszystkich wartości z opublikowanych danych formularza.
Formatery danych wejściowych
Dane w treści żądania mogą być w formacie JSON, XML lub innym formacie. Aby przeanalizować te dane, powiązanie modelu używa formatującego danych wejściowych skonfigurowanego do obsługi określonego typu zawartości. Domyślnie ASP.NET Core zawiera formatery wejściowe oparte na formacie JSON do obsługi danych JSON. Możesz dodać inne formatery dla innych typów zawartości.
ASP.NET Core wybiera formatery wejściowe na podstawie atrybutu Consumes . Jeśli atrybut nie jest obecny, używa nagłówka Content-Type.
Dostosowywanie powiązania modelu za pomocą formaterów wejściowych
Moduł formatujący dane wejściowe ponosi pełną odpowiedzialność za odczytywanie danych z treści żądania. Aby dostosować ten proces, skonfiguruj interfejsy API używane przez program formatujący dane wejściowe. W tej sekcji opisano sposób dostosowywania opartego na formatatorze System.Text.Jsondanych wejściowych w celu zrozumienia niestandardowego typu o nazwie ObjectId.
Rozważmy następujący model, który zawiera właściwość niestandardową ObjectId :
public class InstructorObjectId
{
[Required]
public ObjectId ObjectId { get; set; } = null!;
}
Aby dostosować proces powiązania modelu podczas używania metody System.Text.Json, utwórz klasę pochodzącą z JsonConverter<T>klasy :
internal class ObjectIdConverter : JsonConverter<ObjectId>
{
public override ObjectId Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> new(JsonSerializer.Deserialize<int>(ref reader, options));
public override void Write(
Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
=> writer.WriteNumberValue(value.Id);
}
Aby użyć konwertera niestandardowego, zastosuj JsonConverterAttribute atrybut do typu. W poniższym przykładzie ObjectId typ jest skonfigurowany ObjectIdConverter jako konwerter niestandardowy:
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
Zachowanie systemów powiązań i walidacji modelu jest sterowane przez ModelMetadataprogram . Możesz dostosować ModelMetadata , dodając dostawcę szczegółów do elementu MvcOptions.ModelMetadataDetailsProviders. Wbudowani dostawcy szczegółów są dostępni do wyłączania powiązania modelu lub walidacji dla określonych typów.
Aby wyłączyć powiązanie modelu dla wszystkich modeli określonego typu, dodaj element w elemExcludeBindingMetadataProvider.Program.cs Aby na przykład wyłączyć powiązanie modelu dla wszystkich modeli typu System.Version:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Aby wyłączyć walidację właściwości określonego typu, dodaj element SuppressChildValidationMetadataProvider w Program.cspliku . Aby na przykład wyłączyć walidację właściwości typu System.Guid:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Niestandardowe powiązania modelu
Powiązanie modelu można rozszerzyć, pisząc powiązanie modelu niestandardowego i używając atrybutu [ModelBinder] , aby wybrać go dla danego obiektu docelowego. Dowiedz się więcej o powiązaniu modelu niestandardowego.
Ręczne powiązanie modelu
Powiązanie modelu można wywołać ręcznie przy użyciu TryUpdateModelAsync metody . Metoda jest definiowana w klasach ControllerBase i PageModel . Przeciążenia metody umożliwiają określenie prefiksu i dostawcy wartości do użycia. Metoda zwraca false wartość , jeśli powiązanie modelu nie powiedzie się. Oto przykład:
if (await TryUpdateModelAsync(
newInstructor,
"Instructor",
x => x.Name, x => x.HireDate!))
{
_instructorStore.Add(newInstructor);
return RedirectToPage("./Index");
}
return Page();
TryUpdateModelAsync używa dostawców wartości do pobierania danych z treści formularza, ciągu zapytania i kierowania danych. TryUpdateModelAsync jest zwykle:
Używane z aplikacjami Razor Pages i MVC przy użyciu kontrolerów i widoków, aby zapobiec nadmiernemu delegowaniu.
Nie jest używany z internetowym interfejsem API, chyba że są używane z danych formularza, ciągów zapytań i danych trasy. Punkty końcowe internetowego interfejsu API, które używają formatu JSON, używają formatatorów wejściowych do deserializacji treści żądania do obiektu.
Nazwa tego atrybutu jest zgodna ze wzorcem atrybutów powiązania modelu, które określają źródło danych. Nie chodzi jednak o powiązanie danych od dostawcy wartości. Pobiera wystąpienie typu z kontenera wstrzykiwania zależności. Jego celem jest zapewnienie alternatywy dla iniekcji konstruktora, jeśli potrzebujesz usługi tylko wtedy, gdy wywoływana jest określona metoda.
Jeśli wystąpienie typu nie jest zarejestrowane w kontenerze wstrzykiwania zależności, aplikacja zgłasza wyjątek podczas próby powiązania parametru. Aby ustawić parametr jako opcjonalny, użyj jednego z następujących metod:
Ustaw parametr na wartość null.
Ustaw wartość domyślną parametru.
W przypadku parametrów dopuszczających wartość null upewnij się, że parametr nie null jest używany przed uzyskaniem do niego dostępu.
Kontrolery i Razor strony współpracują z danymi pochodzącymi z żądań HTTP. Na przykład dane trasy mogą zawierać klucz rekordu, a opublikowane pola formularza mogą zawierać wartości właściwości modelu. Pisanie kodu w celu pobrania każdej z tych wartości i przekonwertowanie ich z ciągów na typy platformy .NET byłoby żmudne i podatne na błędy. Powiązanie modelu automatyzuje ten proces. System powiązania modelu:
Pobiera dane z różnych źródeł, takich jak dane trasy, pola formularza i ciągi zapytań.
Udostępnia dane kontrolerom i Razor stronom w parametrach metody i właściwościach publicznych.
Konwertuje dane ciągu na typy platformy .NET.
Aktualizuje właściwości typów złożonych.
Przykład
Załóżmy, że masz następującą metodę akcji:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Aplikacja otrzymuje żądanie z następującym adresem URL:
http://contoso.com/api/pets/2?DogsOnly=true
Powiązanie modelu wykonuje następujące kroki po wybraniu przez system routingu metody akcji:
Znajduje pierwszy parametr , GetByIdliczba całkowita o nazwie id.
Przegląda dostępne źródła w żądaniu HTTP i znajduje id = "2" w danych trasy.
Konwertuje ciąg "2" na liczbę całkowitą 2.
Znajduje następny parametr , GetByIdwartość logiczną o nazwie dogsOnly.
Przegląda źródła i znajduje ciąg zapytania "DogsOnly=true". Dopasowywanie nazw nie jest uwzględniane wielkości liter.
Konwertuje ciąg "true" na wartość logiczną true.
Następnie struktura wywołuje metodę GetById , przekazując wartość 2 dla parametru id i true parametru dogsOnly .
W poprzednim przykładzie docelowe powiązania modelu to parametry metody, które są prostymi typami. Obiekty docelowe mogą być również właściwościami typu złożonego. Po pomyślnym powiązaniu każdej właściwości walidacja modelu jest wykonywana dla tej właściwości. Rekord danych powiązanych z modelem oraz wszelkich błędów powiązań lub walidacji jest przechowywany w pliku ControllerBase.ModelState lub PageModel.ModelState. Aby dowiedzieć się, czy ten proces zakończył się pomyślnie, aplikacja sprawdza flagę ModelState.IsValid .
Elementy docelowe
Powiązanie modelu próbuje znaleźć wartości dla następujących rodzajów obiektów docelowych:
Parametry metody akcji kontrolera, do którego jest kierowane żądanie.
Razor Parametry metody obsługi stron, do których jest kierowane żądanie.
Publiczne właściwości kontrolera lub PageModel klasy, jeśli są określone przez atrybuty.
[BindProperty] , atrybut
Można zastosować do właściwości publicznej kontrolera lub PageModel klasy, aby spowodować powiązanie modelu z tą właściwością docelową:
public class EditModel : InstructorsPageModel
{
[BindProperty]
public Instructor Instructor { get; set; }
[BindProperties] , atrybut
Dostępne w systemie ASP.NET Core 2.1 lub nowszym. Można zastosować do kontrolera lub PageModel klasy, aby poinformować powiązanie modelu w celu kierowania wszystkich właściwości publicznych klasy:
[BindProperties(SupportsGet = true)]
public class CreateModel : InstructorsPageModel
{
public Instructor Instructor { get; set; }
Powiązanie modelu dla żądań HTTP GET
Domyślnie właściwości nie są powiązane z żądaniami HTTP GET. Zazwyczaj wszystko, czego potrzebujesz do żądania GET, to parametr identyfikatora rekordu. Identyfikator rekordu służy do wyszukiwania elementu w bazie danych. W związku z tym nie ma potrzeby wiązania właściwości, która zawiera wystąpienie modelu. W scenariuszach, w których chcesz, aby właściwości powiązane z danymi z żądań GET ustawiły SupportsGet właściwość na true:
Są dodawane do właściwości modelu indywidualnie (nie do klasy modelu), jak w poniższym przykładzie:
public class Instructor
{
public int ID { get; set; }
[FromQuery(Name = "Note")]
public string NoteFromQueryString { get; set; }
Opcjonalnie zaakceptuj wartość nazwy modelu w konstruktorze. Ta opcja jest dostępna w przypadku, gdy nazwa właściwości nie jest zgodna z wartością w żądaniu. Na przykład wartość w żądaniu może być nagłówkiem z łącznikiem w jego nazwie, jak w poniższym przykładzie:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] , atrybut
Zastosuj atrybut do parametru, [FromBody] aby wypełnić jego właściwości z treści żądania HTTP. Środowisko uruchomieniowe ASP.NET Core deleguje odpowiedzialność za odczytywanie treści do elementu formatującego dane wejściowe. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
Po [FromBody] zastosowaniu do parametru typu złożonego wszystkie atrybuty źródła powiązania zastosowane do jego właściwości są ignorowane. Na przykład następująca Create akcja określa, że jego pet parametr jest wypełniany z treści:
public ActionResult<Pet> Create([FromBody] Pet pet)
Klasa Pet określa, że jego Breed właściwość jest wypełniana z parametru ciągu zapytania:
public class Pet
{
public string Name { get; set; }
[FromQuery] // Attribute is ignored.
public string Breed { get; set; }
}
W powyższym przykładzie:
Atrybut [FromQuery] jest ignorowany.
Właściwość Breed nie jest wypełniana z parametru ciągu zapytania.
Formatery wejściowe odczytują tylko treść i nie rozumieją atrybutów źródła powiązania. Jeśli w treści znajduje się odpowiednia wartość, ta wartość jest używana do wypełnienia Breed właściwości.
Nie należy stosować [FromBody] do więcej niż jednego parametru dla metody akcji. Gdy strumień żądania zostanie odczytany przez program formatujący dane wejściowe, nie będzie już dostępny do ponownego odczytania w celu powiązania innych [FromBody] parametrów.
Dodatkowe źródła
Dane źródłowe są dostarczane do systemu powiązania modelu przez dostawców wartości. Można zapisywać i rejestrować niestandardowych dostawców wartości, którzy pobierają dane na potrzeby powiązania modelu z innych źródeł. Możesz na przykład chcieć dane z plików cookie lub stanu sesji. Aby pobrać dane z nowego źródła:
Utwórz klasę, która implementuje IValueProvider.
Utwórz klasę, która implementuje IValueProviderFactory.
Zarejestruj klasę fabryki w pliku Startup.ConfigureServices.
Przykładowa aplikacja zawiera dostawcę wartości i przykład fabryki, który pobiera wartości z plików cookie. Oto kod rejestracji w pliku Startup.ConfigureServices:
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(System.Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters();
Pokazany kod umieszcza niestandardowego dostawcę wartości po wszystkich wbudowanych dostawcach wartości. Aby ustawić ją jako pierwszą na liście, wywołaj metodę Insert(0, new CookieValueProviderFactory()) zamiast Add.
Brak źródła dla właściwości modelu
Domyślnie błąd stanu modelu nie jest tworzony, jeśli dla właściwości modelu nie zostanie znaleziona żadna wartość. Właściwość jest ustawiona na wartość null lub wartość domyślną:
Proste typy dopuszczane do wartości null są ustawione na nullwartość .
Typy wartości innych niż null są ustawione na default(T)wartość . Na przykład parametr int id ma wartość 0.
W przypadku złożonych typów powiązanie modelu tworzy wystąpienie przy użyciu konstruktora domyślnego bez ustawiania właściwości.
Tablice są ustawione na Array.Empty<T>(), z tą różnicą, że byte[] tablice są ustawione na null.
Jeśli stan modelu powinien zostać unieważniony, jeśli nic nie zostanie znalezione w polach formularza dla właściwości modelu, użyj atrybutu [BindRequired] .
Należy pamiętać, że to [BindRequired] zachowanie dotyczy powiązania modelu z opublikowanych danych formularza, a nie danych JSON lub XML w treści żądania. Dane treści żądania są obsługiwane przez osoby formatujące dane wejściowe.
Błędy konwersji typów
Jeśli źródło zostanie znalezione, ale nie można go przekonwertować na typ docelowy, stan modelu jest oznaczony jako nieprawidłowy. Docelowy parametr lub właściwość jest ustawiona na wartość null lub wartość domyślną, jak wspomniano w poprzedniej sekcji.
W kontrolerze interfejsu [ApiController] API, który ma atrybut, nieprawidłowy stan modelu powoduje automatyczną odpowiedź HTTP 400.
Razor Na stronie redisplay strony z komunikatem o błędzie:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
_instructorsInMemoryStore.Add(Instructor);
return RedirectToPage("./Index");
}
Walidacja po stronie klienta przechwytuje większość nieprawidłowych danych, które w przeciwnym razie zostaną przesłane do Razor formularza strony. Ta walidacja utrudnia wyzwolenie poprzedniego wyróżnionego kodu. Przykładowa aplikacja zawiera przycisk Prześlij z nieprawidłową datą , który umieszcza nieprawidłowe dane w polu Data zatrudnienia i przesyła formularz. Ten przycisk pokazuje, jak kod ponownego tworzenia strony działa po wystąpieniu błędów konwersji danych.
Gdy strona jest redisplayed przez poprzedni kod, nieprawidłowe dane wejściowe nie są wyświetlane w polu formularza. Jest to spowodowane tym, że właściwość modelu została ustawiona na wartość null lub wartość domyślną. Nieprawidłowe dane wejściowe są wyświetlane w komunikacie o błędzie. Jeśli jednak chcesz ponownie odtworzyć nieprawidłowe dane w polu formularza, rozważ ręczne utworzenie właściwości modelu jako ciągu i ręczne przeprowadzenie konwersji danych.
Ta sama strategia jest zalecana, jeśli nie chcesz, aby błędy konwersji typów powodowały błędy stanu modelu. W takim przypadku utwórz właściwość modelu jako ciąg.
Typy proste
Proste typy, które binder modelu mogą konwertować ciągi źródłowe na następujące:
Typ złożony musi mieć publiczny konstruktor domyślny i publiczne właściwości zapisywalne do powiązania. Po utworzeniu powiązania modelu klasę tworzy się przy użyciu publicznego konstruktora domyślnego.
Dla każdej właściwości typu złożonego powiązanie modelu analizuje źródła wzorca nazw prefix.property_name. Jeśli nic nie zostanie znalezione, szuka tylko property_name bez prefiksu.
W przypadku powiązania z parametrem prefiks jest nazwą parametru. W przypadku powiązania z właściwością publiczną PageModel prefiks jest nazwą właściwości publicznej. Niektóre atrybuty mają Prefix właściwość, która umożliwia zastąpienie domyślnego użycia parametru lub nazwy właściwości.
Załóżmy na przykład, że typ złożony to następująca Instructor klasa:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Prefiks = nazwa parametru
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza instructorToUpdate.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks = nazwa właściwości
Jeśli model, który ma być powiązany, jest właściwością o nazwie Instructor kontrolera lub PageModel klasy:
[BindProperty]
public Instructor Instructor { get; set; }
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Prefiks niestandardowy
Jeśli model, który ma być powiązany, jest parametrem o nazwie instructorToUpdate , a Bind atrybut określa Instructor jako prefiks:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Powiązanie modelu rozpoczyna się od przejrzenia źródeł klucza Instructor.ID. Jeśli to nie zostanie znalezione, szuka ID bez prefiksu.
Atrybuty dla obiektów docelowych typu złożonego
Dostępnych jest kilka wbudowanych atrybutów do kontrolowania powiązania modelu typów złożonych:
[Bind]
[BindRequired]
[BindNever]
Ostrzeżenie
Te atrybuty wpływają na powiązanie modelu, gdy opublikowane dane formularza są źródłem wartości. Nie mają one wpływu na formatery danych wejściowych, które przetwarzają treść żądań JSON i XML. Formatery danych wejściowych zostały wyjaśnione w dalszej części tego artykułu.
[Bind] , atrybut
Można zastosować do klasy lub parametru metody. Określa, które właściwości modelu powinny być uwzględnione w powiązaniu modelu. [Bind]nie ma wpływu na formatery wejściowe.
W poniższym przykładzie tylko określone właściwości Instructor modelu są powiązane, gdy wywoływana jest dowolna metoda obsługi lub akcji:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
W poniższym przykładzie po wywołaniu OnPost metody są powiązane tylko określone właściwości Instructor modelu:
[HttpPost]
public IActionResult OnPost([Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atrybut [Bind] może służyć do ochrony przed przesłanianiem w scenariuszach tworzenia . Nie działa dobrze w scenariuszach edycji, ponieważ wykluczone właściwości są ustawione na wartość null lub wartość domyślną, a nie pozostawione bez zmian. W przypadku ochrony przed przesłanianiem zalecane są modele wyświetlania, a nie atrybut.[Bind] Aby uzyskać więcej informacji, zobacz Uwaga dotycząca zabezpieczeń dotycząca zastępowania.
[ModelBinder] , atrybut
ModelBinderAttribute można stosować do typów, właściwości lub parametrów. Umożliwia określenie typu powiązania modelu używanego do powiązania określonego wystąpienia lub typu. Na przykład:
[HttpPost]
public IActionResult OnPost([ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)
Atrybut [ModelBinder] może również służyć do zmiany nazwy właściwości lub parametru, gdy jest powiązany model:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
public string Name { get; set; }
}
[BindRequired] , atrybut
Można stosować tylko do właściwości modelu, a nie do parametrów metody. Powoduje, że powiązanie modelu powoduje dodanie błędu stanu modelu, jeśli powiązanie nie może wystąpić dla właściwości modelu. Oto przykład:
public class InstructorWithCollection
{
public int ID { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Hire Date")]
[BindRequired]
public DateTime HireDate { get; set; }
Zobacz również omówienie atrybutu [Required] w temacie Walidacja modelu.
[BindNever] , atrybut
Można stosować tylko do właściwości modelu, a nie do parametrów metody. Uniemożliwia ustawienie właściwości modelu przez powiązanie modelu. Oto przykład:
public class InstructorWithDictionary
{
[BindNever]
public int ID { get; set; }
Kolekcje
W przypadku obiektów docelowych, które są kolekcjami prostych typów, powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr, który ma być powiązany, to tablica o nazwie selectedCourses:
public IActionResult OnPost(int? id, int[] selectedCourses)
Dane formularza lub ciągu zapytania mogą być w jednym z następujących formatów:
Unikaj powiązania parametru lub właściwości o nazwie index lub Index , jeśli sąsiaduje z wartością kolekcji. Powiązanie modelu próbuje użyć index jako indeksu kolekcji, co może spowodować nieprawidłowe powiązanie. Rozważmy na przykład następującą akcję:
public IActionResult Post(string index, List<Product> products)
W poprzednim kodzie index parametr ciągu zapytania jest powiązany z parametrem index metody, a także jest używany do powiązania kolekcji produktów. Zmiana nazwy parametru index lub użycie atrybutu powiązania modelu w celu skonfigurowania powiązania pozwala uniknąć tego problemu:
public IActionResult Post(string productIndex, List<Product> products)
Następujący format jest obsługiwany tylko w danych formularza:
selectedCourses[]=1050&selectedCourses[]=2000
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje tablicę dwóch elementów do parametru selectedCourses :
selectedCourses[0]=1050
selectedCourses[1]=2000
Formaty danych używające liczb w indeksie dolnym (... [0] ... [1] ...) musi upewnić się, że są one numerowane sekwencyjnie rozpoczynające się od zera. Jeśli występują luki w numerowaniu indeksu dolnego, wszystkie elementy po przerwie są ignorowane. Jeśli na przykład indeksy dolny to 0 i 2 zamiast 0 i 1, drugi element jest ignorowany.
Słowniki
W przypadku Dictionary obiektów docelowych powiązanie modelu wyszukuje dopasowania do parameter_name lub property_name. Jeśli nie zostanie znalezione dopasowanie, szuka jednego z obsługiwanych formatów bez prefiksu. Na przykład:
Załóżmy, że parametr docelowy Dictionary<int, string> ma nazwę selectedCourses:
public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Dane opublikowanego formularza lub ciągu zapytania mogą wyglądać podobnie do jednego z następujących przykładów:
We wszystkich poprzednich przykładowych formatach powiązanie modelu przekazuje słownik dwóch elementów do parametru selectedCourses :
selectedCourses["1050"]="Chemistry"
selectedCourses["2000"]="Economics"
Powiązanie konstruktora i typy rekordów
Powiązanie modelu wymaga, aby złożone typy miały konstruktor bez parametrów. Zarówno System.Text.Json metody formatowania danych wejściowych, jak i Newtonsoft.Json obsługują deserializację klas, które nie mają konstruktora bez parametrów.
W języku C# 9 wprowadzono typy rekordów, które są doskonałym sposobem zwięźle reprezentowania danych za pośrednictwem sieci. ASP.NET Core dodaje obsługę wiązania modelu i sprawdzania poprawności typów rekordów za pomocą jednego konstruktora:
public record Person([Required] string Name, [Range(0, 150)] int Age, [BindNever] int Id);
public class PersonController
{
public IActionResult Index() => View();
[HttpPost]
public IActionResult Index(Person person)
{
...
}
}
Podczas sprawdzania poprawności typów rekordów środowisko uruchomieniowe wyszukuje metadane powiązania i walidacji w szczególności na parametrach, a nie we właściwościach.
Platforma umożliwia wiązanie i weryfikowanie typów rekordów:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Aby poprzedni element działał, typ musi:
Być typem rekordu.
Mieć dokładnie jeden publiczny konstruktor.
Zawierają parametry, które mają właściwość o tej samej nazwie i typie. Nazwy nie mogą się różnić literami.
Obiekty POCO bez konstruktorów bez parametrów
Obiekty POC, które nie mają konstruktorów bez parametrów, nie mogą być powiązane.
Poniższy kod powoduje wyjątek z informacją, że typ musi mieć konstruktor bez parametrów:
public class Person(string Name)
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0);
}
Typy rekordów z ręcznie utworzonymi konstruktorami
Typy rekordów z ręcznie utworzonymi konstruktorami, które wyglądają jak konstruktory podstawowe działają
public record Person
{
public Person([Required] string Name, [Range(0, 100)] int Age) => (this.Name, this.Age) = (Name, Age);
public string Name { get; set; }
public int Age { get; set; }
}
Typy rekordów, walidacja i metadane powiązania
W przypadku typów rekordów używane są metadane walidacji i powiązania parametrów. Wszystkie metadane właściwości są ignorowane
public record Person (string Name, int Age)
{
[BindProperty(Name = "SomeName")] // This does not get used
[Required] // This does not get used
public string Name { get; init; }
}
Walidacja i metadane
Walidacja używa metadanych w parametrze, ale używa właściwości do odczytania wartości. W zwykłych przypadkach z konstruktorami podstawowymi te dwa byłyby identyczne. Istnieją jednak sposoby, aby go pokonać:
public record Person([Required] string Name)
{
private readonly string _name;
public Name { get; init => _name = value ?? string.Empty; } // Now this property is never null. However this object could have been constructed as `new Person(null);`
}
Funkcja TryUpdateModel nie aktualizuje parametrów typu rekordu
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
W takim przypadku usługa MVC nie podejmie ponownej próby powiązania Name . Age Można jednak zaktualizować
Zachowanie globalizacji danych trasy powiązania modelu i ciągów zapytań
Dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania:
Traktuj wartości jako niezmienną kulturę.
Spodziewaj się, że adresy URL są niezmienne dla kultury.
Natomiast wartości pochodzące z danych formularza są poddawane konwersji wrażliwej na kulturę. Jest to zaprojektowane tak, aby adresy URL można udostępniać między ustawieniami regionalnymi.
Aby dostawca wartości trasy ASP.NET Core i dostawca wartości ciągu zapytania przeszedł konwersję wrażliwą na kulturę:
Zastąp domyślną fabrykę dostawcy wartości w opcjach MVC nowym:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews(options =>
{
var index = options.ValueProviderFactories.IndexOf(
options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>().Single());
options.ValueProviderFactories[index] = new CulturedQueryStringValueProviderFactory();
});
}
public class CulturedQueryStringValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var query = context.ActionContext.HttpContext.Request.Query;
if (query != null && query.Count > 0)
{
var valueProvider = new QueryStringValueProvider(
BindingSource.Query,
query,
CultureInfo.CurrentCulture);
context.ValueProviders.Add(valueProvider);
}
return Task.CompletedTask;
}
}
Specjalne typy danych
Istnieją pewne specjalne typy danych, które mogą obsłużyć powiązanie modelu.
IFormFile i IFormFileCollection
Przekazany plik uwzględniony w żądaniu HTTP. Obsługiwane jest IEnumerable<IFormFile> również w przypadku wielu plików.
CancellationToken
Akcje mogą opcjonalnie powiązać element CancellationToken jako parametr. RequestAborted Wiąże się to z sygnałem, gdy połączenie bazowe żądania HTTP zostanie przerwane. Akcje mogą używać tego parametru do anulowania długotrwałych operacji asynchronicznych wykonywanych w ramach akcji kontrolera.
FormCollection
Służy do pobierania wszystkich wartości z opublikowanych danych formularza.
Formatery danych wejściowych
Dane w treści żądania mogą być w formacie JSON, XML lub innym formacie. Aby przeanalizować te dane, powiązanie modelu używa formatującego danych wejściowych skonfigurowanego do obsługi określonego typu zawartości. Domyślnie ASP.NET Core zawiera formatery wejściowe oparte na formacie JSON do obsługi danych JSON. Możesz dodać inne formatery dla innych typów zawartości.
ASP.NET Core wybiera formatery wejściowe na podstawie atrybutu Consumes . Jeśli atrybut nie jest obecny, używa nagłówka Content-Type.
Dostosowywanie powiązania modelu za pomocą formaterów wejściowych
Moduł formatujący dane wejściowe ponosi pełną odpowiedzialność za odczytywanie danych z treści żądania. Aby dostosować ten proces, skonfiguruj interfejsy API używane przez program formatujący dane wejściowe. W tej sekcji opisano sposób dostosowywania opartego na formatatorze System.Text.Jsondanych wejściowych w celu zrozumienia niestandardowego typu o nazwie ObjectId.
Rozważmy następujący model, który zawiera właściwość niestandardową ObjectId o nazwie Id:
public class ModelWithObjectId
{
public ObjectId Id { get; set; }
}
Aby dostosować proces powiązania modelu podczas używania metody System.Text.Json, utwórz klasę pochodzącą z JsonConverter<T>klasy :
internal class ObjectIdConverter : JsonConverter<ObjectId>
{
public override ObjectId Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new ObjectId(JsonSerializer.Deserialize<int>(ref reader, options));
}
public override void Write(
Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
{
writer.WriteNumberValue(value.Id);
}
}
Aby użyć konwertera niestandardowego, zastosuj JsonConverterAttribute atrybut do typu. W poniższym przykładzie ObjectId typ jest skonfigurowany ObjectIdConverter jako konwerter niestandardowy:
[JsonConverter(typeof(ObjectIdConverter))]
public struct ObjectId
{
public ObjectId(int id) =>
Id = id;
public int Id { get; }
}
Zachowanie systemów powiązań i walidacji modelu jest sterowane przez ModelMetadataprogram . Możesz dostosować ModelMetadata , dodając dostawcę szczegółów do elementu MvcOptions.ModelMetadataDetailsProviders. Wbudowani dostawcy szczegółów są dostępni do wyłączania powiązania modelu lub walidacji dla określonych typów.
Aby wyłączyć powiązanie modelu dla wszystkich modeli określonego typu, dodaj element w elemExcludeBindingMetadataProvider.Startup.ConfigureServices Aby na przykład wyłączyć powiązanie modelu dla wszystkich modeli typu System.Version:
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(System.Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters();
Aby wyłączyć walidację właściwości określonego typu, dodaj element SuppressChildValidationMetadataProvider w Startup.ConfigureServicespliku . Aby na przykład wyłączyć walidację właściwości typu System.Guid:
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(System.Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters();
Niestandardowe powiązania modelu
Powiązanie modelu można rozszerzyć, pisząc powiązanie modelu niestandardowego i używając atrybutu [ModelBinder] , aby wybrać go dla danego obiektu docelowego. Dowiedz się więcej o powiązaniu modelu niestandardowego.
Ręczne powiązanie modelu
Powiązanie modelu można wywołać ręcznie przy użyciu TryUpdateModelAsync metody . Metoda jest definiowana w klasach ControllerBase i PageModel . Przeciążenia metody umożliwiają określenie prefiksu i dostawcy wartości do użycia. Metoda zwraca false wartość , jeśli powiązanie modelu nie powiedzie się. Oto przykład:
if (await TryUpdateModelAsync<InstructorWithCollection>(
newInstructor,
"Instructor",
i => i.FirstMidName, i => i.LastName, i => i.HireDate))
{
_instructorsInMemoryStore.Add(newInstructor);
return RedirectToPage("./Index");
}
PopulateAssignedCourseData(newInstructor);
return Page();
TryUpdateModelAsync używa dostawców wartości do pobierania danych z treści formularza, ciągu zapytania i kierowania danych. TryUpdateModelAsync jest zwykle:
Używane z aplikacjami Razor Pages i MVC przy użyciu kontrolerów i widoków, aby zapobiec nadmiernemu delegowaniu.
Nie jest używany z internetowym interfejsem API, chyba że są używane z danych formularza, ciągów zapytań i danych trasy. Punkty końcowe internetowego interfejsu API, które używają formatu JSON, używają formatatorów wejściowych do deserializacji treści żądania do obiektu.
Nazwa tego atrybutu jest zgodna ze wzorcem atrybutów powiązania modelu, które określają źródło danych. Nie chodzi jednak o powiązanie danych od dostawcy wartości. Pobiera wystąpienie typu z kontenera wstrzykiwania zależności. Jego celem jest zapewnienie alternatywy dla iniekcji konstruktora, jeśli potrzebujesz usługi tylko wtedy, gdy wywoływana jest określona metoda.
Źródło tej zawartości można znaleźć w witrynie GitHub, gdzie można również tworzyć i przeglądać problemy i żądania ściągnięcia. Więcej informacji znajdziesz w naszym przewodniku dla współtwórców.
Opinia o produkcie ASP.NET Core
ASP.NET Core to projekt typu open source. Wybierz link, aby przekazać opinię:
Utwórz interfejs użytkownika z powiązaniem danych. Interfejs użytkownika automatycznie aktualizuje się na podstawie najnowszych danych, a dane są aktualizowane w odpowiedzi na zmiany w interfejsie użytkownika.