使用Web API进行模型绑定接口属性

我有一个命令看起来像:

public interface ICommand { // Just a marker interface } public interface IUserAware { Guid UserId { get; set; } } public class CreateSomething : ICommand, IUserAware { public string Title { get; set; } public Guid UserId { get; set; } } 

REST请求是:

 PUT /create HTTP/1.1 UserId: 7da6f9ee-2bfc-70b1-f93c-10c950c8f6b0 // Possible an Auth token and not a userId like here. Host: localhost:63079 Content-Type: application/json Cache-Control: no-cache { "title": "This is a test title" } 

我有一个API控制器动作:

 [HttpPut, Route("create")] public IHttpActionResult CreateSomething([FromBody]CreateSomething command) { // I would like command.UserId already binded here } 

我的模型上的Title属性用请求的主体填充,但我想使用请求头中的一些值(例如来自身份validation令牌)绑定command.UserId属性。

如何使用例如模型绑定IUserAware从请求标头值绑定IUserAware的属性,而无需为具体类CreateSomething创建绑定CreateSomething

我在Web API中尝试过各种IModelBinder接口组合,但没有真正的运气。

使用时也感觉多余:

 [HttpPut, Route("create")] public IHttpActionResult CreateSomething([FromBody]CreateSomething command) { command.UserId = GetUserIdFromTheRequest(); } 

或者从控制器的依赖关系中获取UserId并将其设置为如上所述。

如何在ASP.NET MVC中完成

在ASP.NET MVC中,可以执行以下操作以使其工作:

 public class UserAwareModelBinder : DefaultModelBinder { protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType) { var baseModel = base.CreateModel(controllerContext, bindingContext, modelType); var commandModel = baseModel as IUserAware; if (commandModel != null) { commandModel.UserId = controllerContext.HttpContext.User; // or get it from the HttpContext headers. } return baseModel; } } 

并在启动时将其连接起来:

 ModelBinders.Binders.DefaultBinder = new UserAwareModelBinder(); 

 public class CreateSomethingModelBinder : IModelBinder { public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { string key = bindingContext.ModelName; ValueProviderResult val = bindingContext.ValueProvider.GetValue(key); if (val != null) { string s = val.AttemptedValue as string; if (s != null) { return new CreateSomething(){Title = s; UserId = new Guid(ControllerContext.HttpContext.Request.Headers["userId"]);} } } return null; } } 

并在类型声明上添加属性

 [ModelBinder(typeof(CreateSomethingModelBinder))] public class CreateSomething { ... } 

基于@Todd的最后评论,该问题的答案是:

创建一个HttpParameterBinding类:

 public class UserAwareHttpParameterBinding : HttpParameterBinding { private readonly HttpParameterBinding _paramaterBinding; private readonly HttpParameterDescriptor _httpParameterDescriptor; public UserAwareHttpParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor) { _httpParameterDescriptor = descriptor; _paramaterBinding = new FromBodyAttribute().GetBinding(descriptor); } public override async Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken) { await _paramaterBinding.ExecuteBindingAsync(metadataProvider, actionContext, cancellationToken); var baseModel = actionContext.ActionArguments[_httpParameterDescriptor.ParameterName] as IUserAware; if (baseModel != null) { baseModel.UserId = new Guid("6ed85eb7-e55b-4049-a5de-d977003e020f"); // Or get it form the actionContext.RequestContext! } } } 

并在HttpConfiguration

 configuration.ParameterBindingRules.Insert(0, descriptor => typeof(IUserAware).IsAssignableFrom(descriptor.ParameterType) ? new UserAwareHttpParameterBinding(descriptor) : null); 

如果有人知道如何在.NET Core MVC中完成此操作 – 请编辑此post或评论。