我收到“必须输入AccountEmail字段。”使用FromHeader属性将值传递给API时

时间:2019-06-06 02:24:19

标签: c# asp.net-core model

我正在尝试使用ASP.NET中内置的RESTful API从演示数据库中获取信息。为了从数据库中获取信息,我需要通过标头传递一个对象。但是,我的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获取账户,但是我有一个Filter,它需要AccountAccessKey和AccountEmail在Filter中进行一些AWS验证,因此为什么决定将账户标头传递给api调用。

我尝试在模型中删除AccountEmail的[Required]属性,然后API调用起作用,但是我需要具有[Required]属性。

我想念什么吗?我知道错误是由[Required]属性引起的,但我不确定为什么

1 个答案:

答案 0 :(得分:0)

根据您的要求,您需要实现自己的模型绑定程序。

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