Организация клиентского API - PullRequest
1 голос
/ 11 февраля 2020

У меня есть пользовательский API-клиент, вызывающий пользовательскую службу API со многими контроллерами. На самом деле у меня есть этот класс:

public abstract class APIClientBase
{
    protected HttpClient _httpClient;

    public APIClientBase()
    {
        _httpClient = new HttpClient();
        _httpClient.BaseAddress = new Uri("https://localhost:44369/");
    }
}

, который реализуется многими классами, подобными этому:

public class APIClientEmployee : APIClientBase
{
    public async Task<ObservableCollection<Employee>> GetAllEmployeesRequestAsync()
    {
        ObservableCollection<Employee> employees = null;
        HttpResponseMessage response = await _httpClient.GetAsync($"api/employees");

        if (response.IsSuccessStatusCode)
        {
            employees = response.Content.ReadAsAsync<ObservableCollection<Employee>>().Result;
        }

        return employees;
    }

    public ObservableCollection<Employee> GetAllVeterinaryEmployeesRequest()
    {
        ObservableCollection<Employee> employees = null;
        HttpResponseMessage response = _httpClient.GetAsync($"api/employees/veterinaryemployees").Result;

        if (response.IsSuccessStatusCode)
        {
            employees = response.Content.ReadAsAsync<ObservableCollection<Employee>>().Result;
        }

        return employees;
    }

    public async Task<Employee> GetSingleEmployeeRequestAsync(int id)
    {
        Employee employee = null;
        HttpResponseMessage response = await _httpClient.GetAsync($"api/employees/{id}");

        if (response.IsSuccessStatusCode)
        {
            employee = response.Content.ReadAsAsync<Employee>().Result;
        }

        return employee;
    }

    public Employee GetSingleEmployeeRequest(int id)
    {
        Employee employee = null;
        HttpResponseMessage response = _httpClient.GetAsync($"api/employees/{id}").Result;

        if (response.IsSuccessStatusCode)
        {
            employee = response.Content.ReadAsAsync<Employee>().Result;
        }

        return employee;
    }

    public async Task PutSingleEmployeeRequestAsync(Employee employee)
    {
        HttpResponseMessage response = await _httpClient.PutAsJsonAsync($"api/employees/{employee.EmployeeID}", employee);
        response.EnsureSuccessStatusCode();
    }

    public async Task PostSingleEmployeeRequestAsync(Employee employee)
    {
        HttpResponseMessage response = await _httpClient.PostAsJsonAsync($"api/employees", employee);
        response.EnsureSuccessStatusCode();
    }

    public async Task DeleteSingleEmployeeRequestAsync(int id)
    {
        HttpResponseMessage response = await _httpClient.DeleteAsync($"api/employees/{id}");
        response.EnsureSuccessStatusCode();
    }
}

И я использую их так в своих моделях представления:

 public class EmployeeListViewModel
 {
    private APIClientEmployee _apiClientEmployee;

    private ObservableCollection<Employee> _employees;

    public ObservableCollection<Employee> Employees
    {
        get
        {
            return _employees;
        }
        set
        {
            _employees = value;
            OnPropertyChanged("Employees");
        }
    }

    public EmployeeListViewModel()
    {
        _apiClientEmployee = new APIClientEmployee();
        FillEmployeeList();
    }

    public async void FillEmployeeList()
    {
        Employees = await _apiClientEmployee.GetAllEmployeesRequestAsync();
    }
}

Я делаю что-то подобное во многих местах. Кроме того, я создаю другие APIClientEmployee в других ViewModels, потому что мне нужны данные о сотрудниках в некоторых других местах. Но этот метод заставляет меня создавать много объектов APIClient / Http-клиента, и я чувствую, что что-то не так в том, как я это делаю. Я думаю, что я мог бы сломать свой сокет лимит или что-то подобное, и тогда это вызовет проблемы. Я прочитал много учебников, но они часто не являются сложными. Должен ли я иметь только один класс с каждым вызовом API? Должен ли я реализовать синглтон с одним экземпляром каждого из моих классов APIClient? Я не знаю, что делать, и я хотел бы получить предложения ...

1 Ответ

1 голос
/ 11 февраля 2020

Вы совершенно правы. Проверьте официальную документацию по HttpClient :

HttpClient предназначен для однократного создания экземпляра и повторного использования в течение всего жизненного цикла приложения. Создание класса HttpClient для каждого запроса приведет к исчерпанию количества сокетов, доступных при больших нагрузках. Это приведет к ошибкам SocketException. Ниже приведен пример правильного использования HttpClient.

Вот как он объявлен

static readonly HttpClient client = new HttpClient();

Вы можете сделать следующее:

public abstract class APIClientBase
{
    protected static readonly HttpClient client = new HttpClient();

И затем использовать как это:

HttpResponseMessage response = await APIClientBase.client.GetAsync($"api/employees/{id}");
...