Я пытаюсь понять, что делать с некоторыми ошибками в Unity, когда я вызываю API, и как распространить его на пользовательский интерфейс - где и как обрабатывать вещи. Я создал API-интерфейсы aspnet, но там я обычно использовал промежуточное программное обеспечение для обработки ошибок, чтобы поддерживать чистоту своих контроллеров.
Допустим, у нас есть такой код (я использую язык контроллера/репозитория, потому что это то, что я знаю).
Кнопка пользовательского интерфейса запускает событие, подобное OnLoginButtonPressed.
Класс AuthController реагирует на событие, вызывая метод входа в систему, а затем выполняя некоторую логику, когда приходит ответ, следующим образом:
public async void Login(LoginModel input)
{
var result = await AuthRepo.instance.Login(input);
app.token = result;
EventService.OnSuccessfulLogin();
}
Auth.Repo вызывает API и пытается вернуть класс Token (просто оболочка вокруг строки JWT).
public async Task<Token> Login(LoginModel input)
{
string json = JsonConvert.SerializeObject(input);
var request = UnityWebRequest.Post(app.baseURL + "authentication/login", json);
request.SetRequestHeader("Content-Type", "application/json");
request.SendWebRequest();
while (!request.isDone)
{
await Task.Yield();
}
if (request.result == UnityWebRequest.Result.Success)
{
Token token = JsonConvert.DeserializeObject<Token>(request.downloadHandler.text);
return token;
}
else
{
throw
}
}
Так что без обработки исключений. Итак, я хочу попытаться сообщить пользователю, есть ли ошибка подключения, или они указали неверные данные и т. д. Я предполагаю, что должен добавить некоторую логику в AuthRepo, например:
if (request.result == UnityWebRequest.Result.Success)
{
Token token = JsonConvert.DeserializeObject<Token>(request.downloadHandler.text);
return token;
}
else if (request.result== UnityWebRequest.Result.ConnectionError)
{
throw new ConnectionException(request.error);
}
else if (request.result == UnityWebRequest.Result.DataProcessingError)
{
throw new BadRequestException(request.error);
}
else
{
throw new System.Exception(request.error);
}
Кажется, что это много кода, и он окажется в каждом методе в каждом репо (если я не вытащу его в какой-нибудь вспомогательный метод?).... в любом случае, а затем в контроллере я бы сделал что-то вроде:
try {
var result = await AuthRepo.instance.Login(input);
app.token = result;
EventService.OnSuccessfulLogin();
}
catch (ConnectionException ex)
{
EventService.OnConnectionError(ex.Message);
//some UI object would listen for this event and show the connection error message.
}
catch (BadRequestException ex)
{
EventService.LoginFailedError(ex.Message);
}
finally
{
EventService.UnknownError(ex.Message);
}
Это совершенно неправильный путь? Похоже, что код просто завалится обработкой исключений, или это правильный путь?
Я просмотрел несколько видеороликов на YouTube, которые, кажется, предполагают, что это правильно, но на самом деле они не показывают мой вариант использования (разговор с API), поэтому я просто пытаюсь быть уверенным.
кстати .. finally
всегда выполняется .. также в случае успеха и ex
в этом случае не существовало бы
поскольку UnityWebRequest.Result
— это перечисление, здесь вы можете начать с оператора switch. Это не только чище, но и работает лучше.
Еще одна вещь, которую вы можете сделать, это создать абстрактный класс (например, APIException
) и сделать его ответственным за создание правильных экземпляров исключений, предоставив ему какой-нибудь статический метод, такой как APIException FromUWRResult(UnityWebRequest.Result result)
.
Обработка исключений также может быть выполнена в APIException
. Дайте ему абстрактный метод Handle()
и реализуйте его соответствующим образом в каждом из производных классов.
Теперь ваш код будет выглядеть так:
var ex = APIException.FromUWRResult(request.result);
if (ex != null) {
throw ex;
}
...
catch(APIException ex) {
ex.Handle();
}
Я не вижу ничего плохого в том, что в коде много обработки исключений ... Я бы предпочел абстрагировать это в
EventService.HandleException
и позволить службе решать в центральном месте, какие из них он знает, а какие Неизвестная ошибка => в вашем коде есть всегда будет одинcatch(Exception e) { EvntService.HandlException(e); }
=> таким образом, все известные исключения и возможные конкретные отображения находятся в одном центральном месте.. можно добавить дополнительные параметры/перегрузки вHandleException
, если это необходимо, например. опуская сообщение об исключении, но передайте собственное сообщение и т. д.