Я пытаюсь создать модуль повторного использования для вызовов API в С#. Я хочу использовать это для нескольких API. Но мне трудно переносить мои классы данных динамически, как переменную в мою функцию, которая обрабатывает вызовы API.
Скажем, например, что я называю два совершенно разных API, мы будем называть их "Api # 1" и "Api # 2". И у меня есть следующие классы:
// This is the format of the response from Api #1 GET
public class Api01Get
{
public int orderId { get; set; }
public DateTime orderDate { get; set; }
}
// This is the format of the response from Api #2 GET
public class Api02Get
{
public bool isGreen { get; set; }
public string name { get; set; }
}
Вот вызов моей функции. Он отлично работает, если я использую один из моих классов данных следующим образом:
var result = CallAPI<Api02Get>(baseAddress, requestUri);
Но это не дает мне гибкости, которой я пользуюсь.
Вот определение моей функции (здесь я оставил другие параметры, которые не влияют на вещи):
private async Task<TResult> CallAPI<TResult>(Uri baseAddress, string requestUri)
{
using (var client = new HttpClient())
{
client.BaseAddress = baseAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = new HttpResponseMessage();
response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
TResult result = await response.Content.ReadAsAsync<TResult>();
}
}
// do other stuff...
return result;
}
Теперь это то место, где меня повесили. Я должен думать об этом неправильно, но то, что я пытаюсь сделать, это что-то вроде этого, например:
object apiModel;
switch (whichAPI)
{
case "API_01_GET":
apiModel = new Api01Get();
break;
case "API_02_GET":
apiModel = new Api02Get();
break;
// Other cases...
default:
break;
}
var result = CallAPI<apiModel>(baseAddress, requestUri);
При попытке последней строки я получаю сообщение об ошибке. "Тип или имя пространства имен" apiModel "не удалось найти (вы не указали директиву использования или ссылку на сборку?)". Я пробовал другие вещи, но это версия, которая показалась мне самой близкой, поэтому я опубликовал ее.
Поэтому я не уверен, как это сделать, или, может быть, есть лучший способ. Я ценю любые отзывы и буду рад прояснить, если это необходимо. Заранее спасибо.
К сожалению, вы не можете использовать generics здесь без дополнительного отражения для динамического вызова CallAPI<T>
.
К счастью, HttpContentExtensions имеет дополнительные перегрузки, которые позволят вам передать Type
. Вам просто нужно перегрузить ваш метод и внести незначительные изменения в ReadAsAsync
.
private async Task<object> CallAPI(Uri baseAddress, string requestUri, Type apiType)
{
using (var client = new HttpClient())
{
....
if (response.IsSuccessStatusCode)
{
object result = await response.Content.ReadAsAsync(apiType);
}
}
....
return result;
}
Возможно, вам все равно придется изменить некоторые из своих кодов до этого, так как вы застряли в object
.
apiModel
- это не тип, а объект. ПопробуйтеapiModel.GetType()
. (Я не уверен на 100%, что будет работать)result
переменная, поэтому вы не можете ничего с этим сделать.