Model binding no ASP.NET Core

Este artigo explica o que é model binding, como ele funciona e como personalizar seu comportamento.

Exiba ou baixe o código de exemplo (como baixar).

O que é o model binding

Os controladores e Razor as páginas funcionam com dados provenientes de solicitações HTTP. Por exemplo, dados de rota podem fornecer uma chave de registro e campos de formulário postados podem fornecer valores para as propriedades do modelo. Escrever código para recuperar cada um desses valores e convertê-los de cadeias de caracteres em tipos .NET seria uma tarefa entediante e propensa a erro. O model binding automatiza esse processo. O sistema de model binding:

  • Recupera dados de várias fontes, como dados de rota, campos de formulário e cadeias de caracteres de consulta.
  • Fornece os dados para controladores e Razor páginas em parâmetros de método e propriedades públicas.
  • Converte dados de cadeia de caracteres em tipos .NET.
  • Atualiza as propriedades de tipos complexos.

Exemplo

Suponha que você tenha o seguinte método de ação:

[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)

E o aplicativo receba uma solicitação com esta URL:

http://contoso.com/api/pets/2?DogsOnly=true

A associação de modelo passa pelas seguintes etapas depois que o sistema de roteamento seleciona o método de ação:

  • Localiza o primeiro parâmetro de GetById, um número inteiro denominado id.
  • Examina as fontes disponíveis na solicitação HTTP e localiza id = "2" em dados de rota.
  • Converte a cadeia de caracteres "2" em inteiro 2.
  • Localiza o próximo parâmetro de GetById, um booliano chamado dogsOnly.
  • Examina as fontes e localiza "DogsOnly=true" na cadeia de consulta. A correspondência de nomes não diferencia maiúsculas de minúsculas.
  • Converte a cadeia de caracteres "true" no booliano true.

A estrutura então chama o método GetById, passando 2 para o parâmetro id e true para o parâmetro dogsOnly.

No exemplo anterior, os destinos do model binding são parâmetros de método que são tipos simples. Destinos também podem ser as propriedades de um tipo complexo. Depois de cada propriedade ser associada com êxito, a validação do modelo ocorre para essa propriedade. O registro de quais dados estão associados ao modelo, além de quaisquer erros de validação ou de associação, é armazenado em ControllerBase.ModelState ou PageModel.ModelState. Para descobrir se esse processo foi bem-sucedido, o aplicativo verifica o sinalizador ModelState.IsValid.

Destinos

O model binding tenta encontrar valores para os seguintes tipos de destinos:

  • Parâmetros do método de ação do controlador para o qual uma solicitação é roteada.
  • Parâmetros do Razor método de manipulador Pages para o qual uma solicitação é roteada.
  • Propriedades públicas de um controlador ou classe PageModel, se especificadas por atributos.

Atributo [BindProperty]

Pode ser aplicado a uma propriedade pública de um controlador ou classe PageModel para fazer o model binding ter essa propriedade como destino:

public class EditModel : InstructorsPageModel
{
    [BindProperty]
    public Instructor Instructor { get; set; }

Atributo [BindProperties]

Disponível no ASP.NET Core 2.1 e posteriores. Pode ser aplicado a um controlador ou classe PageModel para informar o model binding para ter todas as propriedades públicas da classe como destino:

[BindProperties(SupportsGet = true)]
public class CreateModel : InstructorsPageModel
{
    public Instructor Instructor { get; set; }

Model binding para solicitações HTTP GET

Por padrão, as propriedades não são vinculadas para solicitações HTTP GET. Normalmente, tudo o que você precisa para uma solicitação GET é um parâmetro de ID de registro. A ID do registro é usada para pesquisar o item no banco de dados. Portanto, não é necessário associar uma propriedade que contém uma instância do modelo. Em cenários em que você deseja associar propriedades a dados de solicitações GET, defina a propriedade SupportsGet como true:

[BindProperty(Name = "ai_user", SupportsGet = true)]
public string ApplicationInsightsCookie { get; set; }

Origens

Por padrão, o model binding obtém dados na forma de pares chave-valor das seguintes fontes em uma solicitação HTTP:

  1. Campos de formulário
  2. O corpo da solicitação (para controladores que têm o atributo [ApiController]).
  3. Rotear dados
  4. Parâmetros de cadeia de caracteres de consulta
  5. Arquivos carregados

Para cada parâmetro ou propriedade de destino, as fontes são verificadas na ordem indicada na lista anterior. Há algumas exceções:

  • Os valores de cadeia de caracteres de consulta e dados de rota são usados apenas para tipos simples.
  • Arquivos carregados são associados apenas a tipos de destino que implementam IFormFile ou IEnumerable<IFormFile>.

Se a origem padrão não estiver correta, use um dos seguintes atributos para especificar a origem:

  • [FromQuery] -Obtém valores da cadeia de caracteres de consulta.
  • [FromRoute] -Obtém valores de dados de rota.
  • [FromForm] -Obtém valores dos campos de formulário postados.
  • [FromBody] -Obtém valores do corpo da solicitação.
  • [FromHeader] -Obtém valores de cabeçalhos HTTP.

Esses atributos:

  • São adicionados às propriedades de modelo individualmente (não à classe de modelo), como no exemplo a seguir:

    public class Instructor
    {
        public int ID { get; set; }
    
        [FromQuery(Name = "Note")]
        public string NoteFromQueryString { get; set; }
    
  • Opcionalmente, aceite um valor de nome de modelo no construtor. Essa opção é fornecida caso o nome da propriedade não corresponda ao valor na solicitação. Por exemplo, o valor na solicitação pode ser um cabeçalho com um hífen em seu nome, como no exemplo a seguir:

    public void OnGet([FromHeader(Name = "Accept-Language")] string language)
    

Atributo [FromBody]

Aplique o [FromBody] atributo a um parâmetro para popular suas propriedades do corpo de uma solicitação HTTP. o tempo de execução de ASP.NET Core delega a responsabilidade de ler o corpo para um formatador de entrada. O formatadores de entrada são explicados posteriormente neste artigo.

Quando [FromBody] é aplicado a um parâmetro de tipo complexo, todos os atributos de origem de associação aplicados às suas propriedades são ignorados. Por exemplo, a ação a seguir Create especifica que seu pet parâmetro é populado a partir do corpo:

public ActionResult<Pet> Create([FromBody] Pet pet)

A Pet classe especifica que sua Breed propriedade é populada a partir de um parâmetro de cadeia de caracteres de consulta:

public class Pet
{
    public string Name { get; set; }

    [FromQuery] // Attribute is ignored.
    public string Breed { get; set; }
}

No exemplo anterior:

  • O [FromQuery] atributo é ignorado.
  • A Breed propriedade não é preenchida a partir de um parâmetro de cadeia de caracteres de consulta.

Os formatadores de entrada lêem apenas o corpo e não entendem os atributos de origem da associação. Se um valor adequado for encontrado no corpo, esse valor será usado para popular a Breed propriedade.

Não aplique [FromBody] a mais de um parâmetro por método de ação. Depois que o fluxo de solicitação é lido por um formatador de entrada, ele não está mais disponível para ser lido novamente para ligar outros [FromBody] parâmetros.

Fontes adicionais

Os dados de origem são fornecidos ao sistema de model binding pelos provedores de valor. Você pode escrever e registrar provedores de valor personalizados que obtêm dados para model binding de outras fontes. Por exemplo, talvez você queira dados do cookie estado da sessão ou do. Para obter dados de uma nova fonte:

  • Crie uma classe que implementa IValueProvider.
  • Crie uma classe que implementa IValueProviderFactory.
  • Registre a classe de alocador em Startup.ConfigureServices.

O aplicativo de exemplo inclui um provedor de valor e um exemplo de fábrica que obtém valores de cookie s. Aqui está o código de registro em 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();

O código mostrado coloca o provedor de valor personalizado depois de todos os provedores de valor internos. Para torná-lo o primeiro na lista, chame Insert(0, new CookieValueProviderFactory()), em vez de Add.

Nenhuma fonte para uma propriedade de modelo

Por padrão, um erro de estado de modelo não será criado se nenhum valor for encontrado para uma propriedade de modelo. A propriedade é definida como null ou um valor padrão:

  • Tipos simples anuláveis definidos como null.
  • Tipos de valor não anuláveis são definidos como default(T). Por exemplo, um parâmetro int id é definido como 0.
  • Para tipos complexos, o model binding cria uma instância usando o construtor padrão sem definir propriedades.
  • As matrizes são definidas como Array.Empty<T>(), exceto que matrizes byte[] são definidas como null.

Se o estado do modelo deve ser invalidado quando nada for encontrado em campos de formulário para uma propriedade de modelo, use o [BindRequired] atributo.

Observe que este comportamento [BindRequired] se aplica ao model binding de dados de formulário postados, não a dados JSON ou XML em um corpo da solicitação. Dados do corpo da solicitação são tratados pelos formatadores de entrada.

Erros de conversão de tipos

Se uma fonte for encontrada, mas não puder ser convertida no tipo de destino, o estado do modelo será sinalizado como inválido. O parâmetro ou a propriedade de destino é definido como nulo ou um valor padrão, conforme observado na seção anterior.

Em um controlador de API que tem o atributo [ApiController], um estado de modelo inválido resulta em uma resposta HTTP 400 automática.

Em uma Razor página, reexiba a página com uma mensagem de erro:

public IActionResult OnPost()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _instructorsInMemoryStore.Add(Instructor);
    return RedirectToPage("./Index");
}

A validação no lado do cliente captura dados mais inválidos que, de outra forma, seriam enviados a um Razor formulário de páginas. Essa validação torna difícil disparar o código realçado anterior. O aplicativo de exemplo inclui um botão Enviar com Data Inválida que coloca os dados inválidos no campo Data de Contratação e envia o formulário. Esse botão mostra como o código para exibir novamente a página funciona quando ocorrem erros de conversão de dados.

Quando a página é exibida novamente pelo código anterior, a entrada inválida não é mostrada no campo de formulário. Isso ocorre porque a propriedade do modelo foi definida como nulo ou um valor padrão. A entrada inválida aparece em uma mensagem de erro. Porém, se você quiser exibir novamente os dados inválidos no campo de formulário, considere tornar a propriedade do modelo uma cadeia de caracteres e fazer a conversão de dados manualmente.

A mesma estratégia será recomendada se você não desejar que erros de conversão de tipo resultem em erros de estado de modelo. Nesse caso, torne a propriedade de modelo uma cadeia de caracteres.

Tipos simples

Os tipos simples em que o associador de modelos pode converter cadeias de caracteres de origem incluem os seguintes:

Tipos complexos

Um tipo complexo deve ter um construtor padrão público e propriedades públicas graváveis para associar. Quando ocorre model binding, a classe é instanciada usando o construtor padrão público.

Para cada propriedade do tipo complexo, o model binding examina as fontes em busca do nome padrão prefix.property_name. Se nada for encontrado, ela procurará apenas property_name sem o prefixo.

Para associação a um parâmetro, o prefixo é o nome do parâmetro. Para associação a uma propriedade pública PageModel, o prefixo é o nome da propriedade pública. Alguns atributos têm uma propriedade Prefix que permite substituir o uso padrão do nome da propriedade ou do parâmetro.

Por exemplo, suponha que o tipo complexo seja a seguinte classe Instructor:

public class Instructor
{
    public int ID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

Prefixo = nome do parâmetro

Se o modelo a ser associado for um parâmetro chamado instructorToUpdate:

public IActionResult OnPost(int? id, Instructor instructorToUpdate)

O model binding começa examinando as fontes para a chave instructorToUpdate.ID. Se ela não for encontrada, procurará ID sem um prefixo.

Prefixo = nome da propriedade

Se o modelo a ser associado for uma propriedade chamada Instructor do controlador ou da classe PageModel:

[BindProperty]
public Instructor Instructor { get; set; }

O model binding começa examinando as fontes para a chave Instructor.ID. Se ela não for encontrada, procurará ID sem um prefixo.

Prefixo personalizado

Se o modelo a ser associado for um parâmetro denominado instructorToUpdate e um atributo Bind especificar Instructor como o prefixo:

public IActionResult OnPost(
    int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)

O model binding começa examinando as fontes para a chave Instructor.ID. Se ela não for encontrada, procurará ID sem um prefixo.

Atributos para destinos de tipo complexo

Vários atributos internos estão disponíveis para controlar o model binding de tipos complexos:

  • [Bind]
  • [BindRequired]
  • [BindNever]

Aviso

Esses atributos afetam o model binding quando os dados de formulário postados são a origem dos valores. Eles não afetam os formatadores de entrada, que processam os corpos de solicitação JSON e XML lançados. O formatadores de entrada são explicados posteriormente neste artigo.

Atributo [Bind]

Pode ser aplicado a uma classe ou a um parâmetro de método. Especifica quais propriedades de um modelo devem ser incluídas no model binding. [Bind] Não afeta os formatadores de entrada.

No exemplo a seguir, somente as propriedades especificadas do modelo Instructor são associadas quando qualquer método de ação ou o manipulador é chamado:

[Bind("LastName,FirstMidName,HireDate")]
public class Instructor

No exemplo a seguir, somente as propriedades especificadas do modelo Instructor são associadas quando o método OnPost é chamado:

[HttpPost]
public IActionResult OnPost([Bind("LastName,FirstMidName,HireDate")] Instructor instructor)

O atributo [Bind] pode ser usado para proteção contra o excesso de postagem cenários de criar. Ele não funciona bem em cenários de edição, pois as propriedades excluídas são definidas como nulas ou um valor padrão, em vez de serem deixadas inalteradas. Para defesa contra o excesso de postagem, são recomendados modelos de exibição, em vez do atributo [Bind]. Para obter mais informações, veja Observação de segurança sobre o excesso de postagem.

Atributo [ModelBinder]

ModelBinderAttribute pode ser aplicado a tipos, propriedades ou parâmetros. Ele permite especificar o tipo de associador de modelo usado para associar a instância ou o tipo específico. Por exemplo:

[HttpPost]
public IActionResult OnPost([ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)

O [ModelBinder] atributo também pode ser usado para alterar o nome de uma propriedade ou parâmetro quando ele está sendo associado a um modelo:

public class Instructor
{
    [ModelBinder(Name = "instructor_id")]
    public string Id { get; set; }

    public string Name { get; set; }
}

Atributo [BindRequired]

Somente pode ser aplicado às propriedades de modelo, não aos parâmetros do método. Faz com que o model binding adicione um erro de estado de modelo se a associação não puder ocorrer para a propriedade de um modelo. Aqui está um exemplo:

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

Veja também a discussão sobre o atributo [Required] em Validação do modelo.

Atributo [BindNever]

Somente pode ser aplicado às propriedades de modelo, não aos parâmetros do método. Impede que o model binding configure a propriedade de um modelo. Aqui está um exemplo:

public class InstructorWithDictionary
{
    [BindNever]
    public int ID { get; set; }

Coleções

Para destinos que são coleções de tipos simples, o model binding procura correspondências para parameter_name ou property_name. Se nenhuma correspondência for encontrada, procurará um dos formatos compatíveis sem o prefixo. Por exemplo:

  • Suponha que o parâmetro a ser associado seja uma matriz chamada selectedCourses:

    public IActionResult OnPost(int? id, int[] selectedCourses)
    
  • Dados de cadeia de caracteres de consulta ou formulário podem estar em um dos seguintes formatos:

    selectedCourses=1050&selectedCourses=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    
  • O formato a seguir é compatível apenas com os dados de formulário:

    selectedCourses[]=1050&selectedCourses[]=2000
    
  • Para todos os formatos do exemplo anterior, o model binding passa uma matriz de dois itens para o parâmetro selectedCourses:

    • selectedCourses[0]=1050
    • selectedCourses[1]=2000

    Formatos de dados que usam números subscritos (... [0]... [1]...) devem garantir que eles estejam numerados em sequência, começando com zero. Se houver quaisquer intervalos na numeração de subscrito, todos os itens após o intervalo serão ignorados. Por exemplo, se os subscritos forem 0 e 2, em vez de 0 e 1, o segundo item será ignorado.

Dicionários

Para destinos Dictionary, o model binding procura correspondências para parameter_name ou property_name. Se nenhuma correspondência for encontrada, procurará um dos formatos compatíveis sem o prefixo. Por exemplo:

  • Suponha que o parâmetro de destino seja um Dictionary<int, string> chamado selectedCourses:

    public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
    
  • Os dados de cadeia de caracteres de consulta ou formulário postados podem se parecer com um dos exemplos a seguir:

    selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics
    
    [1050]=Chemistry&selectedCourses[2000]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Para todos os formatos do exemplo anterior, o model binding passa um dicionário de dois itens para o parâmetro selectedCourses:

    • selectedCourses["1050"]="Chemistry"
    • selectedCourses["2000"]="Economics"

Associação de construtor e tipos de registro

A associação de modelo requer que os tipos complexos tenham um construtor sem parâmetros. Os System.Text.Json Newtonsoft.Json formatadores de entrada e com base dão suporte à desserialização de classes que não têm um construtor sem parâmetros.

O C# 9 apresenta tipos de registro, que são uma ótima maneira de representar de forma sucinta os dados pela rede. ASP.NET Core adiciona suporte para associação de modelo e validação de tipos de registro com um único construtor:

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)
   {
       ...
   }
}

Person/Index.cshtml:

@model Person

Name: <input asp-for="Name" />
...
Age: <input asp-for="Age" />

Ao validar tipos de registro, o tempo de execução pesquisa os metadados de associação e validação especificamente em parâmetros em vez de em Propriedades.

A estrutura permite a ligação e a validação de tipos de registro:

public record Person([Required] string Name, [Range(0, 100)] int Age);

Para que o anterior funcione, o tipo deve:

  • Ser um tipo de registro.
  • Ter exatamente um construtor público.
  • Contém parâmetros que têm uma propriedade com o mesmo nome e tipo. Os nomes não devem ser diferentes por maiúsculas e minúsculas.

POCOs sem construtores com parâmetros

POCOs que não têm construtores sem parâmetros não podem ser associados.

O código a seguir resulta em uma exceção dizendo que o tipo deve ter um construtor sem parâmetros:

public class Person(string Name)

public record Person([Required] string Name, [Range(0, 100)] int Age)
{
   public Person(string Name) : this (Name, 0);
}

Tipos de registro com construtores criados manualmente

Tipos de registro com construtores criados manualmente que se parecem com construtores primários funcionam

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

Tipos de registro, validação e metadados de associação

Para tipos de registro, os metadados validação e associação em parâmetros são usados. Todos os metadados em propriedades são ignorados

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

Validação e metadados

A validação usa metadados no parâmetro, mas usa a propriedade para ler o valor. No caso comum com construtores primários, os dois seriam idênticos. No entanto, há maneiras de derrotar:

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

TryUpdateModel não atualiza parâmetros em um tipo de registro

public record Person(string Name)
{
   public int Age { get; set; }
}

var person = new Person("initial-name");
TryUpdateModel(person, ...);

Nesse caso, o MVC não tentará se associar Name novamente. No entanto, o Age pode ser atualizado

Comportamento de globalização de dados de rota de associação de modelo e cadeias de consulta

o provedor de valor de rota ASP.NET Core e o provedor de valor de cadeia de consulta:

  • Tratar valores como cultura invariável.
  • Espere que as URLs sejam invariáveis de cultura.

Por outro lado, os valores provenientes de dados de formulário passam por uma conversão sensível à cultura. Isso ocorre por design para que as URLs sejam compartilháveis entre as localidades.

para tornar o provedor de valor de rota ASP.NET Core e o provedor de valor da cadeia de consulta passam por uma conversão sensível à cultura:

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

Tipos de dados especiais

Há alguns tipos de dados especiais com o model binding pode lidar.

IFormFile e IFormFileCollection

Um arquivo carregado incluído na solicitação HTTP. Também compatível com IEnumerable<IFormFile> para vários arquivos.

CancellationToken

As ações podem, opcionalmente, associar um CancellationToken como parâmetro. Isso associa os RequestAborted sinais quando a conexão subjacente à solicitação HTTP é anulada. As ações podem usar esse parâmetro para cancelar operações assíncronas de execução longa que são executadas como parte das ações do controlador.

FormCollection

Usado para recuperar todos os valores dos dados de formulário postados.

Formatadores de entrada

Dados no corpo da solicitação podem estar em JSON, XML ou algum outro formato. Para analisar esses dados, o model binding usa um formatador de entrada configurado para lidar com um determinado tipo de conteúdo. Por padrão, o ASP.NET Core inclui formatadores de entrada baseados em JSON para lidar com os dados JSON. Você pode adicionar outros formatadores para outros tipos de conteúdo.

O ASP.NET Core seleciona formatadores de entrada com base no atributo Consome. Se nenhum atributo estiver presente, ele usará o cabeçalho Content-Type.

Para usar os formatadores de entrada XML internos:

  • Instale o pacote do NuGet Microsoft.AspNetCore.Mvc.Formatters.Xml.

  • Em Startup.ConfigureServices, chame AddXmlSerializerFormatters ou AddXmlDataContractSerializerFormatters.

    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();
    
  • Aplique o atributo Consumes às classes de controlador ou aos métodos de ação que devem esperar XML no corpo da solicitação.

    [HttpPost]
    [Consumes("application/xml")]
    public ActionResult<Pet> Create(Pet pet)
    

    Para obter mais informações, veja Introdução à serialização XML.

Personalizar a associação de modelo com formatadores de entrada

Um formatador de entrada assume total responsabilidade pela leitura de dados do corpo da solicitação. Para personalizar esse processo, configure as APIs usadas pelo formatador de entrada. Esta seção descreve como personalizar o System.Text.Json formatador de entrada baseado em dados para entender um tipo personalizado chamado ObjectId .

Considere o seguinte modelo, que contém uma ObjectId propriedade personalizada chamada Id :

public class ModelWithObjectId
{
    public ObjectId Id { get; set; }
}

Para personalizar o processo de associação de modelo ao usar o System.Text.Json , crie uma classe derivada de JsonConverter<T> :

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

Para usar um conversor personalizado, aplique o JsonConverterAttribute atributo ao tipo. No exemplo a seguir, o ObjectId tipo é configurado com ObjectIdConverter como seu conversor personalizado:

[JsonConverter(typeof(ObjectIdConverter))]
public struct ObjectId
{
    public ObjectId(int id) =>
        Id = id;

    public int Id { get; }
}

Para obter mais informações, consulte como escrever conversores personalizados.

Excluir tipos especificados do model binding

O comportamento do sistema de validação e model binding é orientado pelo ModelMetadata. Você pode personalizar ModelMetadata adicionando um provedor de detalhes MvcOptions.ModelMetadataDetailsProviders. Provedores de detalhes internos estão disponíveis para desabilitar o model binding ou a validação para tipos especificados.

Para desabilitar o model binding em todos os modelos de um tipo especificado, adicione um ExcludeBindingMetadataProvider em Startup.ConfigureServices. Por exemplo, para desabilitar o model binding em todos os modelos do tipo 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();

Para desabilitar a validação nas propriedades de um tipo especificado, adicione um SuppressChildValidationMetadataProvider em Startup.ConfigureServices. Por exemplo, para desabilitar a validação nas propriedades do tipo 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();

Associadores de modelos personalizados

Você pode estender o model binding escrevendo um associador de modelos personalizado e usando o atributo [ModelBinder] para selecioná-la para um determinado destino. Saiba mais sobre o model binding personalizado.

Model binding manual

O model binding pode ser invocado manualmente usando o método TryUpdateModelAsync. O método é definido nas classes ControllerBase e PageModel. Sobrecargas de método permitem que você especifique o provedor de valor e prefixo a ser usado. O método retornará false se o model binding falhar. Aqui está um exemplo:

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 usa provedores de valor para obter dados do corpo do formulário, Cadeia de caracteres de consulta e dados de rota. TryUpdateModelAsync normalmente é:

  • Usado com Razor páginas e aplicativos MVC usando controladores e exibições para evitar o excesso de postagens.
  • Não usado com uma API da Web, a menos que consumido de dados de formulário, cadeias de caracteres de consulta e dados de rota. Os pontos de extremidade da API Web que consomem JSON usam formatadores de entrada para desserializar o corpo da solicitação em um objeto.

Para obter mais informações, consulte TryUpdateModelAsync.

Atributo [FromServices]

O nome do atributo segue o padrão dos atributos de model binding que especificam uma fonte de dados. Porém, não se trata de associar dados de um provedor de valor. Ele obtém uma instância de um tipo do contêiner de injeção de dependência. Sua finalidade é oferecer uma alternativa à injeção de construtor para quando você precisa de um serviço somente se um determinado método for chamado.

Recursos adicionais

Este artigo explica o que é model binding, como ele funciona e como personalizar seu comportamento.

Exiba ou baixe o código de exemplo (como baixar).

O que é o model binding

Os controladores e Razor as páginas funcionam com dados provenientes de solicitações HTTP. Por exemplo, dados de rota podem fornecer uma chave de registro e campos de formulário postados podem fornecer valores para as propriedades do modelo. Escrever código para recuperar cada um desses valores e convertê-los de cadeias de caracteres em tipos .NET seria uma tarefa entediante e propensa a erro. O model binding automatiza esse processo. O sistema de model binding:

  • Recupera dados de várias fontes, como dados de rota, campos de formulário e cadeias de caracteres de consulta.
  • Fornece os dados para controladores e Razor páginas em parâmetros de método e propriedades públicas.
  • Converte dados de cadeia de caracteres em tipos .NET.
  • Atualiza as propriedades de tipos complexos.

Exemplo

Suponha que você tenha o seguinte método de ação:

[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)

E o aplicativo receba uma solicitação com esta URL:

http://contoso.com/api/pets/2?DogsOnly=true

A associação de modelo passa pelas seguintes etapas depois que o sistema de roteamento seleciona o método de ação:

  • Localiza o primeiro parâmetro de GetByID, um número inteiro denominado id.
  • Examina as fontes disponíveis na solicitação HTTP e localiza id = "2" em dados de rota.
  • Converte a cadeia de caracteres "2" em inteiro 2.
  • Localiza o próximo parâmetro de GetByID, um booliano chamado dogsOnly.
  • Examina as fontes e localiza "DogsOnly=true" na cadeia de consulta. A correspondência de nomes não diferencia maiúsculas de minúsculas.
  • Converte a cadeia de caracteres "true" no booliano true.

A estrutura então chama o método GetById, passando 2 para o parâmetro id e true para o parâmetro dogsOnly.

No exemplo anterior, os destinos do model binding são parâmetros de método que são tipos simples. Destinos também podem ser as propriedades de um tipo complexo. Depois de cada propriedade ser associada com êxito, a validação do modelo ocorre para essa propriedade. O registro de quais dados estão associados ao modelo, além de quaisquer erros de validação ou de associação, é armazenado em ControllerBase.ModelState ou PageModel.ModelState. Para descobrir se esse processo foi bem-sucedido, o aplicativo verifica o sinalizador ModelState.IsValid.

Destinos

O model binding tenta encontrar valores para os seguintes tipos de destinos:

  • Parâmetros do método de ação do controlador para o qual uma solicitação é roteada.
  • Parâmetros do Razor método de manipulador Pages para o qual uma solicitação é roteada.
  • Propriedades públicas de um controlador ou classe PageModel, se especificadas por atributos.

Atributo [BindProperty]

Pode ser aplicado a uma propriedade pública de um controlador ou classe PageModel para fazer o model binding ter essa propriedade como destino:

public class EditModel : InstructorsPageModel
{
    [BindProperty]
    public Instructor Instructor { get; set; }

Atributo [BindProperties]

Disponível no ASP.NET Core 2.1 e posteriores. Pode ser aplicado a um controlador ou classe PageModel para informar o model binding para ter todas as propriedades públicas da classe como destino:

[BindProperties(SupportsGet = true)]
public class CreateModel : InstructorsPageModel
{
    public Instructor Instructor { get; set; }

Model binding para solicitações HTTP GET

Por padrão, as propriedades não são vinculadas para solicitações HTTP GET. Normalmente, tudo o que você precisa para uma solicitação GET é um parâmetro de ID de registro. A ID do registro é usada para pesquisar o item no banco de dados. Portanto, não é necessário associar uma propriedade que contém uma instância do modelo. Em cenários em que você deseja associar propriedades a dados de solicitações GET, defina a propriedade SupportsGet como true:

[BindProperty(Name = "ai_user", SupportsGet = true)]
public string ApplicationInsightsCookie { get; set; }

Origens

Por padrão, o model binding obtém dados na forma de pares chave-valor das seguintes fontes em uma solicitação HTTP:

  1. Campos de formulário
  2. O corpo da solicitação (para controladores que têm o atributo [ApiController]).
  3. Rotear dados
  4. Parâmetros de cadeia de caracteres de consulta
  5. Arquivos carregados

Para cada parâmetro ou propriedade de destino, as fontes são verificadas na ordem indicada na lista anterior. Há algumas exceções:

  • Os valores de cadeia de caracteres de consulta e dados de rota são usados apenas para tipos simples.
  • Arquivos carregados são associados apenas a tipos de destino que implementam IFormFile ou IEnumerable<IFormFile>.

Se a origem padrão não estiver correta, use um dos seguintes atributos para especificar a origem:

  • [FromQuery] -Obtém valores da cadeia de caracteres de consulta.
  • [FromRoute] -Obtém valores de dados de rota.
  • [FromForm] -Obtém valores dos campos de formulário postados.
  • [FromBody] -Obtém valores do corpo da solicitação.
  • [FromHeader] -Obtém valores de cabeçalhos HTTP.

Esses atributos:

  • São adicionados às propriedades de modelo individualmente (não à classe de modelo), como no exemplo a seguir:

    public class Instructor
    {
        public int ID { get; set; }
    
        [FromQuery(Name = "Note")]
        public string NoteFromQueryString { get; set; }
    
  • Opcionalmente, aceite um valor de nome de modelo no construtor. Essa opção é fornecida caso o nome da propriedade não corresponda ao valor na solicitação. Por exemplo, o valor na solicitação pode ser um cabeçalho com um hífen em seu nome, como no exemplo a seguir:

    public void OnGet([FromHeader(Name = "Accept-Language")] string language)
    

Atributo [FromBody]

Aplique o [FromBody] atributo a um parâmetro para popular suas propriedades do corpo de uma solicitação HTTP. o tempo de execução de ASP.NET Core delega a responsabilidade de ler o corpo para um formatador de entrada. O formatadores de entrada são explicados posteriormente neste artigo.

Quando [FromBody] é aplicado a um parâmetro de tipo complexo, todos os atributos de origem de associação aplicados às suas propriedades são ignorados. Por exemplo, a ação a seguir Create especifica que seu pet parâmetro é populado a partir do corpo:

public ActionResult<Pet> Create([FromBody] Pet pet)

A Pet classe especifica que sua Breed propriedade é populada a partir de um parâmetro de cadeia de caracteres de consulta:

public class Pet
{
    public string Name { get; set; }

    [FromQuery] // Attribute is ignored.
    public string Breed { get; set; }
}

No exemplo anterior:

  • O [FromQuery] atributo é ignorado.
  • A Breed propriedade não é preenchida a partir de um parâmetro de cadeia de caracteres de consulta.

Os formatadores de entrada lêem apenas o corpo e não entendem os atributos de origem da associação. Se um valor adequado for encontrado no corpo, esse valor será usado para popular a Breed propriedade.

Não aplique [FromBody] a mais de um parâmetro por método de ação. Depois que o fluxo de solicitação é lido por um formatador de entrada, ele não está mais disponível para ser lido novamente para ligar outros [FromBody] parâmetros.

Fontes adicionais

Os dados de origem são fornecidos ao sistema de model binding pelos provedores de valor. Você pode escrever e registrar provedores de valor personalizados que obtêm dados para model binding de outras fontes. Por exemplo, talvez você queira dados do cookie estado da sessão ou do. Para obter dados de uma nova fonte:

  • Crie uma classe que implementa IValueProvider.
  • Crie uma classe que implementa IValueProviderFactory.
  • Registre a classe de alocador em Startup.ConfigureServices.

O aplicativo de exemplo inclui um provedor de valor e um exemplo de fábrica que obtém valores de cookie s. Aqui está o código de registro em Startup.ConfigureServices:

services.AddMvc(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
    options.ModelMetadataDetailsProviders.Add(
        new ExcludeBindingMetadataProvider(typeof(System.Version)));
    options.ModelMetadataDetailsProviders.Add(
        new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

O código mostrado coloca o provedor de valor personalizado depois de todos os provedores de valor internos. Para torná-lo o primeiro na lista, chame Insert(0, new CookieValueProviderFactory()), em vez de Add.

Nenhuma fonte para uma propriedade de modelo

Por padrão, um erro de estado de modelo não será criado se nenhum valor for encontrado para uma propriedade de modelo. A propriedade é definida como null ou um valor padrão:

  • Tipos simples anuláveis definidos como null.
  • Tipos de valor não anuláveis são definidos como default(T). Por exemplo, um parâmetro int id é definido como 0.
  • Para tipos complexos, o model binding cria uma instância usando o construtor padrão sem definir propriedades.
  • As matrizes são definidas como Array.Empty<T>(), exceto que matrizes byte[] são definidas como null.

Se o estado do modelo deve ser invalidado quando nada for encontrado em campos de formulário para uma propriedade de modelo, use o [BindRequired] atributo .

Observe que este comportamento [BindRequired] se aplica ao model binding de dados de formulário postados, não a dados JSON ou XML em um corpo da solicitação. Dados do corpo da solicitação são tratados pelos formatadores de entrada.

Erros de conversão de tipos

Se uma fonte for encontrada, mas não puder ser convertida no tipo de destino, o estado do modelo será sinalizado como inválido. O parâmetro ou a propriedade de destino é definido como nulo ou um valor padrão, conforme observado na seção anterior.

Em um controlador de API que tem o atributo [ApiController], um estado de modelo inválido resulta em uma resposta HTTP 400 automática.

Em uma Razor página, replay a página com uma mensagem de erro:

public IActionResult OnPost()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _instructorsInMemoryStore.Add(Instructor);
    return RedirectToPage("./Index");
}

A validação do lado do cliente captura a maioria dos dados ruins que, de outra forma, seriam enviados para um formulário Razor de Páginas. Essa validação torna difícil disparar o código realçado anterior. O aplicativo de exemplo inclui um botão Enviar com Data Inválida que coloca os dados inválidos no campo Data de Contratação e envia o formulário. Esse botão mostra como o código para exibir novamente a página funciona quando ocorrem erros de conversão de dados.

Quando a página é exibida novamente pelo código anterior, a entrada inválida não é mostrada no campo de formulário. Isso ocorre porque a propriedade do modelo foi definida como nulo ou um valor padrão. A entrada inválida aparece em uma mensagem de erro. Porém, se você quiser exibir novamente os dados inválidos no campo de formulário, considere tornar a propriedade do modelo uma cadeia de caracteres e fazer a conversão de dados manualmente.

A mesma estratégia será recomendada se você não desejar que erros de conversão de tipo resultem em erros de estado de modelo. Nesse caso, torne a propriedade de modelo uma cadeia de caracteres.

Tipos simples

Os tipos simples em que o associador de modelos pode converter cadeias de caracteres de origem incluem os seguintes:

Tipos complexos

Um tipo complexo deve ter um construtor padrão público e propriedades públicas graváveis para associar. Quando ocorre model binding, a classe é instanciada usando o construtor padrão público.

Para cada propriedade do tipo complexo, o model binding examina as fontes em busca do nome padrão prefix.property_name. Se nada for encontrado, ela procurará apenas property_name sem o prefixo.

Para associação a um parâmetro, o prefixo é o nome do parâmetro. Para associação a uma propriedade pública PageModel, o prefixo é o nome da propriedade pública. Alguns atributos têm uma propriedade Prefix que permite substituir o uso padrão do nome da propriedade ou do parâmetro.

Por exemplo, suponha que o tipo complexo seja a seguinte classe Instructor:

public class Instructor
{
    public int ID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

Prefixo = nome do parâmetro

Se o modelo a ser associado for um parâmetro chamado instructorToUpdate:

public IActionResult OnPost(int? id, Instructor instructorToUpdate)

O model binding começa examinando as fontes para a chave instructorToUpdate.ID. Se ela não for encontrada, procurará ID sem um prefixo.

Prefixo = nome da propriedade

Se o modelo a ser associado for uma propriedade chamada Instructor do controlador ou da classe PageModel:

[BindProperty]
public Instructor Instructor { get; set; }

O model binding começa examinando as fontes para a chave Instructor.ID. Se ela não for encontrada, procurará ID sem um prefixo.

Prefixo personalizado

Se o modelo a ser associado for um parâmetro denominado instructorToUpdate e um atributo Bind especificar Instructor como o prefixo:

public IActionResult OnPost(
    int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)

O model binding começa examinando as fontes para a chave Instructor.ID. Se ela não for encontrada, procurará ID sem um prefixo.

Atributos para destinos de tipo complexo

Vários atributos internos estão disponíveis para controlar o model binding de tipos complexos:

  • [BindRequired]
  • [BindNever]
  • [Bind]

Observação

Esses atributos afetam o model binding quando os dados de formulário postados são a origem dos valores. Eles não afetam os formatadores de entrada, que processam corpos de solicitação XML e JSON postados. O formatadores de entrada são explicados posteriormente neste artigo.

Veja também a discussão sobre o atributo [Required] em Validação do modelo.

Atributo [BindRequired]

Somente pode ser aplicado às propriedades de modelo, não aos parâmetros do método. Faz com que o model binding adicione um erro de estado de modelo se a associação não puder ocorrer para a propriedade de um modelo. Aqui está um exemplo:

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

Atributo [BindNever]

Somente pode ser aplicado às propriedades de modelo, não aos parâmetros do método. Impede que o model binding configure a propriedade de um modelo. Aqui está um exemplo:

public class InstructorWithDictionary
{
    [BindNever]
    public int ID { get; set; }

Atributo [Bind]

Pode ser aplicado a uma classe ou a um parâmetro de método. Especifica quais propriedades de um modelo devem ser incluídas no model binding.

No exemplo a seguir, somente as propriedades especificadas do modelo Instructor são associadas quando qualquer método de ação ou o manipulador é chamado:

[Bind("LastName,FirstMidName,HireDate")]
public class Instructor

No exemplo a seguir, somente as propriedades especificadas do modelo Instructor são associadas quando o método OnPost é chamado:

[HttpPost]
public IActionResult OnPost([Bind("LastName,FirstMidName,HireDate")] Instructor instructor)

O atributo [Bind] pode ser usado para proteção contra o excesso de postagem cenários de criar. Ele não funciona bem em cenários de edição, pois as propriedades excluídas são definidas como nulas ou um valor padrão, em vez de serem deixadas inalteradas. Para defesa contra o excesso de postagem, são recomendados modelos de exibição, em vez do atributo [Bind]. Para obter mais informações, veja Observação de segurança sobre o excesso de postagem.

Coleções

Para destinos que são coleções de tipos simples, o model binding procura correspondências para parameter_name ou property_name. Se nenhuma correspondência for encontrada, procurará um dos formatos compatíveis sem o prefixo. Por exemplo:

  • Suponha que o parâmetro a ser associado seja uma matriz chamada selectedCourses:

    public IActionResult OnPost(int? id, int[] selectedCourses)
    
  • Dados de cadeia de caracteres de consulta ou formulário podem estar em um dos seguintes formatos:

    selectedCourses=1050&selectedCourses=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    
  • O formato a seguir é compatível apenas com os dados de formulário:

    selectedCourses[]=1050&selectedCourses[]=2000
    
  • Para todos os formatos do exemplo anterior, o model binding passa uma matriz de dois itens para o parâmetro selectedCourses:

    • selectedCourses[0]=1050
    • selectedCourses[1]=2000

    Formatos de dados que usam números subscritos (... [0]... [1]...) devem garantir que eles estejam numerados em sequência, começando com zero. Se houver quaisquer intervalos na numeração de subscrito, todos os itens após o intervalo serão ignorados. Por exemplo, se os subscritos forem 0 e 2, em vez de 0 e 1, o segundo item será ignorado.

Dicionários

Para destinos Dictionary, o model binding procura correspondências para parameter_name ou property_name. Se nenhuma correspondência for encontrada, procurará um dos formatos compatíveis sem o prefixo. Por exemplo:

  • Suponha que o parâmetro de destino seja um Dictionary<int, string> chamado selectedCourses:

    public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
    
  • Os dados de cadeia de caracteres de consulta ou formulário postados podem se parecer com um dos exemplos a seguir:

    selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics
    
    [1050]=Chemistry&selectedCourses[2000]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Para todos os formatos do exemplo anterior, o model binding passa um dicionário de dois itens para o parâmetro selectedCourses:

    • selectedCourses["1050"]="Chemistry"
    • selectedCourses["2000"]="Economics"

Comportamento de globalização de dados de rota de associação de modelo e cadeias de consulta

o provedor de valor de rota ASP.NET Core e o provedor de valor de cadeia de consulta:

  • Tratar valores como cultura invariável.
  • Espere que as URLs sejam invariáveis de cultura.

Por outro lado, os valores provenientes de dados de formulário passam por uma conversão sensível à cultura. Isso ocorre por design para que as URLs sejam compartilháveis entre as localidades.

para tornar o provedor de valor de rota ASP.NET Core e o provedor de valor da cadeia de consulta passam por uma conversão sensível à cultura:

services.AddMvc(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;
    }
}

Tipos de dados especiais

Há alguns tipos de dados especiais com o model binding pode lidar.

IFormFile e IFormFileCollection

Um arquivo carregado incluído na solicitação HTTP. Também compatível com IEnumerable<IFormFile> para vários arquivos.

CancellationToken

usado para cancelar a atividade em controladores assíncronos.

FormCollection

Usado para recuperar todos os valores dos dados de formulário postados.

Formatadores de entrada

Dados no corpo da solicitação podem estar em JSON, XML ou algum outro formato. Para analisar esses dados, o model binding usa um formatador de entrada configurado para lidar com um determinado tipo de conteúdo. Por padrão, o ASP.NET Core inclui formatadores de entrada baseados em JSON para lidar com os dados JSON. Você pode adicionar outros formatadores para outros tipos de conteúdo.

O ASP.NET Core seleciona formatadores de entrada com base no atributo Consome. Se nenhum atributo estiver presente, ele usará o cabeçalho Content-Type.

Para usar os formatadores de entrada XML internos:

  • Instale o pacote do NuGet Microsoft.AspNetCore.Mvc.Formatters.Xml.

  • Em Startup.ConfigureServices, chame AddXmlSerializerFormatters ou AddXmlDataContractSerializerFormatters.

    services.AddMvc(options =>
    {
        options.ValueProviderFactories.Add(new CookieValueProviderFactory());
        options.ModelMetadataDetailsProviders.Add(
            new ExcludeBindingMetadataProvider(typeof(System.Version)));
        options.ModelMetadataDetailsProviders.Add(
            new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
    })
    .AddXmlSerializerFormatters()
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
  • Aplique o atributo Consumes às classes de controlador ou aos métodos de ação que devem esperar XML no corpo da solicitação.

    [HttpPost]
    [Consumes("application/xml")]
    public ActionResult<Pet> Create(Pet pet)
    

    Para obter mais informações, veja Introdução à serialização XML.

Excluir tipos especificados do model binding

O comportamento do sistema de validação e model binding é orientado pelo ModelMetadata. Você pode personalizar ModelMetadata adicionando um provedor de detalhes MvcOptions.ModelMetadataDetailsProviders. Provedores de detalhes internos estão disponíveis para desabilitar o model binding ou a validação para tipos especificados.

Para desabilitar o model binding em todos os modelos de um tipo especificado, adicione um ExcludeBindingMetadataProvider em Startup.ConfigureServices. Por exemplo, para desabilitar o model binding em todos os modelos do tipo System.Version:

services.AddMvc(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
    options.ModelMetadataDetailsProviders.Add(
        new ExcludeBindingMetadataProvider(typeof(System.Version)));
    options.ModelMetadataDetailsProviders.Add(
        new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

Para desabilitar a validação nas propriedades de um tipo especificado, adicione um SuppressChildValidationMetadataProvider em Startup.ConfigureServices. Por exemplo, para desabilitar a validação nas propriedades do tipo System.Guid:

services.AddMvc(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
    options.ModelMetadataDetailsProviders.Add(
        new ExcludeBindingMetadataProvider(typeof(System.Version)));
    options.ModelMetadataDetailsProviders.Add(
        new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

Associadores de modelos personalizados

Você pode estender o model binding escrevendo um associador de modelos personalizado e usando o atributo [ModelBinder] para selecioná-la para um determinado destino. Saiba mais sobre o model binding personalizado.

Model binding manual

O model binding pode ser invocado manualmente usando o método TryUpdateModelAsync. O método é definido nas classes ControllerBase e PageModel. Sobrecargas de método permitem que você especifique o provedor de valor e prefixo a ser usado. O método retornará false se o model binding falhar. Aqui está um exemplo:

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

Atributo [FromServices]

O nome do atributo segue o padrão dos atributos de model binding que especificam uma fonte de dados. Porém, não se trata de associar dados de um provedor de valor. Ele obtém uma instância de um tipo do contêiner de injeção de dependência. Sua finalidade é oferecer uma alternativa à injeção de construtor para quando você precisa de um serviço somente se um determinado método for chamado.

Recursos adicionais