Я получаю сообщение "Поле AccountEmail обязательно для заполнения."при передаче значений в API с атрибутом FromHeader - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь получить информацию из демонстрационной базы данных, используя RESTful API, встроенный в ASP.NET. Чтобы получить информацию из базы данных, мне нужно передать объект через заголовок. Однако мой API не получает эти значения. Моя функция API использует атрибут [FromHeader], но ничего не получается. Я получаю статус 400 со следующим сообщением об ошибке: {"AccountEmail": ["Поле AccountEmail обязательно."]}

Так вот следующий код:

У меня есть модель, которая выглядит так:

{
    [Serializable]
    public class Account
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Required]
        public long AccountId { get; protected set; }
        [Required]
        [EmailAddress]
        public string AccountEmail { get; set; }
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Required]
        public Guid AccountAccessKey { get; set; }
    }
}

The API call looks like 

[HttpGet]
        [AccountFilter]
        public async Task<ActionResult<Account>> GetAccount([FromHeader] Account account) {
            try
            {
                return await _Context.GetAccount(account.AccountEmail);
            }
            catch { }
            return BadRequest(new Error()
            {
                ErrorTitle = "Unable to get Account",
                ErrorMessage = "ValidationError"
            });
        }

Where GetAccount looks like 

public Task<Account> GetAccount(string email)
       {
           return _context.Accounts.FirstOrDefaultAsync(x => x.AccountEmail == email);
       }

The API call looks like this

let account = new Account({
            AccountEmail: 'gazefekini@eaglemail.top',
            AccountAccessKey:'00000000-0000-0000-0000-000000000000',
            AccountId:0
        })

        fetch(process.env.API + '/api/Account/GetAccount', {
            method:'GET',
            headers: {
                "Accept":"application/json",
                "account": "" + account
            }
        })

Я мог бы использовать FromQuery и получить учетную запись через AccountId, но у меня есть Фильтр, которому требуются AccountAccessKey и AccountEmail для выполнения некоторой проверки AWS в Фильтре, поэтому я решил передать заголовок учетной записи в вызов API.

Я попытался удалить атрибут [Required] для AccountEmail в модели, и затем вызов API работает, но мне нужно иметь атрибут [Required].

Я что-то упустил? Я понимаю, что ошибка исходит из этого [Обязательного] атрибута, но я не уверен, почему

1 Ответ

0 голосов
/ 07 июня 2019

В соответствии с вашими требованиями вам необходимо внедрить собственную модель переплета.

  1. Пользовательский HeaderComplexModelBinder

    public class HeaderComplexModelBinder : IModelBinder
    {
            public Task BindModelAsync(ModelBindingContext bindingContext)
            {
            if (bindingContext == null)
            {
                    throw new ArgumentNullException(nameof(bindingContext));
            }
    
            if (bindingContext == null)
            {
                    throw new ArgumentNullException(nameof(bindingContext));
            }
    
            var headerModel = bindingContext.HttpContext.Request.Headers[bindingContext.OriginalModelName].FirstOrDefault();
            var modelType = bindingContext.ModelMetadata.ModelType;
    
            bindingContext.Model = JsonConvert.DeserializeObject(headerModel, modelType);
            bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
    
            return Task.CompletedTask;
            }
    }
    
  2. Пользовательский IModelBinderProvider

    public class HeaderComplexModelBinderProvider : IModelBinderProvider
    {
    
            public IModelBinder GetBinder(ModelBinderProviderContext context)
            {
            if (context == null)
            {
                    throw new ArgumentNullException(nameof(context));
            }
    
            if (context.Metadata.IsComplexType)
            {
                    var x = context.Metadata as Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadata;
                    var headerAttribute = x.Attributes.Attributes.Where(a => a.GetType() == typeof(FromHeaderAttribute)).FirstOrDefault();
                    if (headerAttribute != null)
                    {
                    return new BinderTypeModelBinder(typeof(HeaderComplexModelBinder));
                    }
                    else
                    {
                    return null;
                    }
            }
            else
            {
                    return null;
            }
            }
    }
    
  3. Настроить в Startup.cs

    services.AddMvc(options => {
            options.ModelBinderProviders.Insert(0, new HeaderComplexModelBinderProvider());
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...