Создание действия, которое принимает параметр любого типа, производного от типа параметра (полиморфный параметр)

Я хочу создать динамическую структуру, чтобы клиент мог запрашивать сервер в веб-API. Я попытался использовать следующий код для решения моего вопроса, однако он не работает.

  1. Как я могу отправить общий тип, например <travel>, в службу
  2. Как я могу изменить код сервера (или вообще нужно изменить клиент/сервер)?

PS: Спасибо за терпение, если вы дочитали мой вопрос до конца.

Код клиента

var serializer = new JavaScriptSerializer();    
var product = new travel() { travel_desc = "select * from travel" };    
var jsonText = serializer.Serialize(product);    
var client = new HttpClient();    
client.BaseAddress = new Uri("http://localhost:65370/");     
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));    
StringContent content = new StringContent(jsonText, Encoding.UTF8, "application/json");     

var z = client.PostAsync<travel>("api/bb", product, new JsonMediaTypeFormatter()).Result;

Код сервера, который не работает

public IHttpActionResult Post< T > (Object x) where T : new()    
{    
                ........................    
}

кстати все нормально но я не знаю как отправить ‹ T > на сервер

public IHttpActionResult Post(Object x)    
{    
                ........................    
}     

Сообщение об ошибке
Client call server, server will be getting an error message " StatusCode: 404, ReasonPhrase: 'Not Found' "

 var z = client.PostAsync < travel > ("api/dd", product, new JsonMediaTypeFormatter()).Result; <--client

    public class ddController< T > : ApiController {public virtual void Post() {   ... }  } <---server    





  // sorry all , my English isn't very well , so I will try to use code to tell everyone how i want 
// in format situations,I will create 2 controller when I have 2 models(ex: users/product) , as following (client)
                var a = client.PostAsync("api/users", users, new JsonMediaTypeFormatter()).Result;
                var b = client.PostAsync("api/product", product, new JsonMediaTypeFormatter()).Result;

//and then when the users and product controllers was created the post code should be like as following (server)
                public IHttpActionResult Postusers(users travel) {}
                public IHttpActionResult Postproduct(product travel) {}

   //now i just want to create 1 controller for above  like as follwing 
                 var b = client.PostAsync<users/product>("api/all", product, new JsonMediaTypeFormatter()).Result;(client)

                 public IHttpActionResult Post<T>(Object ForAll) where T : new() {} (server)

person Willie Cheng    schedule 12.05.2015    source источник
comment
Что именно не работает?   -  person kamil-mrzyglod    schedule 12.05.2015
comment
Возможно, связано: stackoverflow.com/questions/12077361/generic-webapi-controller   -  person Konamiman    schedule 12.05.2015
comment
Hi Kamo Client не может инициировать событие POST сервера   -  person Willie Cheng    schedule 12.05.2015
comment
Привет Konamiman: в моем случае это не работает, у вас есть другие способы сделать это, спасибо   -  person Willie Cheng    schedule 12.05.2015
comment
Привет @Konamiman, извините, что беспокою вас, я долгое время не использовал переполнение стека, но теперь я не могу отправить ни одного вопроса, я не знаю, что я могу сделать, потому что я пытался изменить все свои вопросы, но Задавать вопрос - это не работа, так что я знаю, кто может мне помочь, еще раз извините, и, надеюсь, вы можете сделать мне одолжение, спасибо, Вилли   -  person Willie Cheng    schedule 29.12.2015


Ответы (1)


JSON.NET, сериализатор JSON веб-API, может отправлять информацию о типе при сериализации объекта и использовать эту же информацию для его десериализации.

Хитрость, которую он использует, заключается в том, чтобы включить свойство $type в качестве первого свойства объекта JSON.

Если вы хотите использовать эту технику, вам нужно иметь базовый класс или интерфейс, например ITravel, наследовать от него все возможные классы и использовать базовый класс или интерфейс в качестве типа параметра, например:

public interface ITravel
{
  public int TravelId { get; set; }
}

public class TravelTypeA : ITravel
{
  public int TravelId { get; set; }
  public string Destination { get; set; }
}

public class TravelTypeB : ITravel
{
  ...
}

[HttpPost]
public object PostMeATravel(ITravel travel)
{
    // check what type is travel with "is" or ".GetType()"
}

Вам также необходимо указать JSON включать информацию о типе при (де)сериализации ITravel объектов. (Обработка имен типов JSON ):

JsonSerializerSettings serializerSettings 
  = GlobalConfiguration.Configuration.Formatters
    .JsonFormatter.SerializerSettings;

serializerSettings.TypeNameHandling = TypeNameHandling.Auto;

И затем вы должны опубликовать JSON с typeInformation, например:

{
  $type: 'SampleApp.TravelTypeA, SampleApp',
  TravelId: 22,
  Destination: 'La Almunia de Doña Godina'
}

Когда вы это сделаете, JSON.NET будет использовать информацию о типе для создания объекта TravelTypeA и передать его в качестве параметра действию, которое ожидает ITravel. Внутри действия вы можете проверить тип полученного параметра, если вам это нужно, например: if (travel.GetType().Name == "TravelTypeA") { ... }

Посмотрите этот вопрос и ответ для получения дополнительной информации о том, как это сделать, как это работает, а также о преимуществах и недостатках этого метода и альтернативном способе его выполнения: Десериализация Json в производные типы в Asp.Net Web API

ПРИМЕЧАНИЕ: вы можете использовать отличное дополнение Postman для Chrome для тестирования методов веб-API

person JotaBe    schedule 12.05.2015
comment
Привет, JB, не могли бы вы дать мне краткий образец, включающий сайт клиент / сервер, я буду благодарен вам за то, что вы сделали это для меня, еще раз спасибо - person Willie Cheng; 13.05.2015
comment
В упомянутых вопросах и ответах у вас достаточно информации: добавьте конфигурацию JSON.NET в любой класс начальной загрузки в папке AppStart. Создайте контроллер, интерфейс и два класса, подобные тем, которые я показываю в этом ответе. И, наконец, сделайте POST-запрос к этому контроллеру со свойствами od TravelTypeA и добавьте $type: MyNamespace.TravelTypeA, MyAsssemblyName (полное имя типа) в качестве первого свойства объекта JSON. Ваше действие POST получит экземпляр TravelTypeA. Если у вас есть конкретная проблема с реализацией этого, сообщите мне об этом. Проверьте это с помощью почтальона Chrome - person JotaBe; 13.05.2015
comment
Привет, JB, может быть, это слишком сложно для меня, не могли бы вы помочь мне дать мне больше справочных URL-адресов, потому что я пытался, как указано выше, вы даете мне ссылки на мой код, открытый класс TravelTypeA: ITravel {} ‹-- не могли бы вы сказать мне как это настроить, дайте мне короткий пример, спасибо, Вилли - person Willie Cheng; 13.05.2015
comment
Я добавил немного больше информации в свой ответ. Пожалуйста, посмотри на это - person JotaBe; 13.05.2015
comment
JB. действительно, спасибо за вашу помощь, я поместил другой код в мой контекст, не могли бы вы увидеть его еще раз, извините за мой глупый английский, может быть, я не очень ясно описал свой вопрос для вас, вы можете понять, в чем мой вопрос , или на самом деле я решил свою проблему с вашим контентом, если да, я буду пытаться еще раз, мне это очень тяжело. еще раз спасибо за вашу доброту - person Willie Cheng; 13.05.2015