Изменение имени параметра. Привязка модели Web Api.

Я использую привязку модели Web API для анализа параметров запроса из URL-адреса. Например, вот модельный класс:

public class QueryParameters
{
    [Required]
    public string Cap { get; set; }

    [Required]
    public string Id { get; set; }
}

Это отлично работает, когда я вызываю что-то вроде /api/values/5?cap=somecap&id=1.

Можно ли каким-либо образом изменить имя свойства в классе модели, но сохранить имя параметра запроса одинаково - например:

public class QueryParameters
{
    [Required]
    public string Capability { get; set; }

    [Required]
    public string Id { get; set; }
}

Я думал, что добавление [Display(Name="cap")] в свойство Capability будет работать, но это не так. Есть ли какой-то тип аннотации данных, который я должен использовать?

Контроллер будет иметь метод, который выглядит следующим образом:

public IHttpActionResult GetValue([FromUri]QueryParameters param)    
{
    // Do Something with param.Cap and param.id
}

Ответ 1

Вы можете использовать свойство Name атрибута привязки FromUri для использования параметров строки запроса с разными именами в аргументах метода.

Если вы передаете простые параметры, а не свой тип QueryParameters, вы можете привязать значения следующим образом:

/api/values/5?cap=somecap&id=1

public IHttpActionResult GetValue([FromUri(Name = "cap")] string capabilities, int id)    
{
}

Ответ 2

Web API использует немного другой механизм привязки к модели, чем ASP.NET MVC. Он использует formatters для данных, переданных в теле и вложениях модели для данных, передаваемых в строке запроса (как в вашем случае). Форматы учитывают дополнительные атрибуты метаданных, в то время как привязки моделей не работают.

Итак, если вы передали свою модель в теле сообщения, а не в строке запроса, вы могли бы аннотировать ваши данные следующим образом, и это сработало бы:

public class QueryParameters
{
    [DataMember(Name="Cap")]
    public string Capability { get; set; }

    public string Id { get; set; }
}

Вы, наверное, уже об этом знаете. Чтобы заставить его работать с параметрами строки запроса и, следовательно, для связывания с образцами, вам придется использовать собственное собственное связующее устройство, которое фактически проверяет и использует атрибуты DataMember.

Следующий фрагмент кода сделал бы трюк (хотя он далек от качества продукции):

public class MemberModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var model = Activator.CreateInstance(bindingContext.ModelType);
        foreach (var prop in bindingContext.PropertyMetadata)
        {
            // Retrieving attribute
            var attr = bindingContext.ModelType.GetProperty(prop.Key)
                                     .GetCustomAttributes(false)
                                     .OfType<DataMemberAttribute>()
                                     .FirstOrDefault();
            // Overwriting name if attribute present
            var qsParam = (attr != null) ? attr.Name : prop.Key;
            // Setting value of model property based on query string value
            var value = bindingContext.ValueProvider.GetValue(qsParam).AttemptedValue;
            var property = bindingContext.ModelType.GetProperty(prop.Key);
            property.SetValue(model, value);
        }
        bindingContext.Model = model;
        return true;
    }
}

Вам также необходимо указать в своем методе контроллера, что вы хотите использовать это связующее устройство:

public IHttpActionResult GetValue([ModelBinder(typeof(MemberModelBinder))]QueryParameters param)

Ответ 3

Я провел несколько часов, работая над надежным решением одной и той же проблемы, когда однострочный трюк будет очень трюк:

myModel.Capability = HttpContext.Current.Request["cap"];

Ответ 4

Я просто столкнулся с этим и использовал getter в моем классе параметров, чтобы вернуть свойство bound.

Итак, в вашем примере:

public class QueryParameters
{
    public string cap {get; set;}
    public string Capability
    {
      get { return cap; }
    }

    public string Id { get; set; }
}

Теперь в вашем контроллере вы можете ссылаться на свойство Capability.

public IHttpActionResult GetValue([FromUri]QueryParameters param)    
{
    // Do Something with param.Capability,
    // except assign it a new value because it only a getter
}

Конечно, если вы используете отражение объекта param или сериализуете его, будет включено свойство cap. Не уверен, почему кому-то нужно будет это делать с параметрами запроса.