2014-01-03 2 views
4

У меня есть объект, который выглядит довольно много, как это:Сильно типизированных и произвольные свойства в Web API объекта запроса

public class MyNiceRequest 
{ 
    [Required] 
    public string FirstName { get; set; } 
    [Required] 
    public string LastName { get; set; } 

    public string SomeOptionalField { get; set; } 
} 

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

public MyNiceResponse Post(MyNiceRequest request) { 
... 
} 

Из внешнего интерфейса вызывающего приложения я хочу включить больше полей, чем три, указанные в объекте. Эти поля генерируются во время выполнения (контролируются через интерфейс администратора), поэтому я не могу применить их к классу запросов. Тем не менее, я не нашел хороший способ получить их в контроллере.

Я могу сделать свой объект запроса (MyNiceRequest) наследовать от Dictionary<string,string> - тогда я получу их все, но они не будут привязаны к их соответствующим свойствам на строго типизированном классе (похоже, словарь связан перед отдых в любом используемом устройстве для связывания). Кроме того, что более важно, валидация, которая имеет решающее значение для приложения, перестает работать.

Я видел this вопрос, но это не дает мне ничего, поскольку Request.Content.Read... -methods дает мне пустые результаты (так как это уже прочитано и привязано к модели?).

Скажем, я хочу следующие поля от переднего конца:

  • FirstName (должен привязываться сильно типизированных, нигде)
  • LastName (должен привязываться сильно типизированных, нигде)
  • SomeOptionalField (должен привязываться сильно типизированных, нигде)
  • RuntimeGenerated1 (должен закончиться в словаре)
  • RuntimeGenerated2 (должен закончиться в словаре)

Я хочу, чтобы один из двух решений:

  • Либо иметь возможность наследовать от Dictionary<string,string>, но пусть словарь будет связан после того, как сильно типизированные свойства, чтобы валидация do it is work
  • Есть отдельное свойство на MyNiceRequest, которое может быть чем-то вроде Dictionary<string,string> TheRest { get; set; } и привязать его к оставшимся входящим свойствам где-нибудь.

Перезапись переднего конца для передачи в поле времени генерируемых полей в виде отдельной коллекции не является вариантом.

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

+0

Что такое ваш тип содержимого запроса? Является ли это JSON? – LostInComputer

+0

Да. Для реального общего решения я предполагаю, что он должен обрабатывать любые прикладные медиаформаты, но для этого конкретного случая поддержка только JSON совершенно прекрасна. –

ответ

3

Для типа контента application/json вы можете использовать DynamicObject с форматированием по умолчанию для WebAPI по умолчанию.

public class MyNiceRequest : DynamicObject 
{ 
    private Dictionary<string, string> _dynamicMembers = new Dictionary<string, string>(); 

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

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

    public string SomeOptionalField { get; set; } 

    [JsonIgnore] 
    public Dictionary<string, string> DynamicMembers 
    { 
     get { return _dynamicMembers; } 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object value) 
    { 
     string stringValue; 
     var isFound = _dynamicMembers.TryGetValue(binder.Name, out stringValue); 
     value = stringValue; 
     return isFound; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     if (value is string) 
     { 
      _dynamicMembers[binder.Name] = (string)value; 
      return true; 
     } 
     return false; 
    } 
} 

Редактировать

  1. Если вы хотите, чтобы объект сериализации в том же формате, осуществлять IDictionary<string, string>. Это легко, просто делегировать реализацию интерфейса для _dynamicMembers

  2. Это решение не работает с XML по умолчанию и х-WWW-форм-urlencoded форматтеров :(

+0

Просто великолепно. Работает как шарм! –

2

Вы можете использовать DTO.

public class MyNiceRequest 
{ 
    [Required] 
    public string FirstName { get; set; } 
    [Required] 
    public string LastName { get; set; } 

    public string SomeOptionalField { get; set; } 

    public Dictionary<string, string> TheRest { get; set; } 
} 

Если вы размещаете JSON в теле запроса, как этот {"firstname":"arve", "therest":{"key":"value"}}, FirstName свойство будет заполнено. TheRest будет иметь элемент с ключом «ключ» и значением «значение». Конечно, ModelState.IsValid будет false, так как JSON не содержит LastName.

+0

Это честный ответ, но я не хочу переписывать перед тем, как поставить все эти динамические поля в отдельную коллекцию (TheRest) - они должны быть на «базовом уровне», как и все остальное. Уточненный исходный вопрос. –

Смежные вопросы