visual valid name example documentacion comment comentarios c# asp.net-web-api

valid - param name c#



Propiedad de interfaz de vinculaciĆ³n de modelo con API web (2)

Tengo un comando parecido a:

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

La solicitud REST es:

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

Tengo una acción de controlador de API mirando:

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

La propiedad de Title en mi modelo se completa con el cuerpo de la solicitud, pero me gustaría vincular la propiedad command.UserId utilizando algunos valores de los encabezados de solicitud (por ejemplo, de un token de autenticación).

¿Cómo puedo vincular la propiedad de IUserAware partir de un valor de encabezado de solicitud, por ejemplo, una carpeta de modelo, sin tener que crear una carpeta para la clase concreta CreateSomething ?

IModelBinder varias combinaciones de la interfaz IModelBinder en la API web, pero sin suerte.

También se siente redundante para usar:

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

O haciendo que UserId dependa del controlador y UserId como el anterior.

Cómo se hace en ASP.NET MVC

En ASP.NET MVC, es posible hacer lo siguiente para que funcione:

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

Y conectelo al inicio con:

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

y agregar atributo en la declaración de tipo

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


Basado en el último comentario de @Todd, la respuesta a la pregunta es:

Cree una clase 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! } } }

Y HttpConfiguration en HttpConfiguration :

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

Si alguien sabe cómo se hace esto en .NET Core MVC, edite esta publicación o comentario.