RunUIAsync
BasePage를 상속한 화면에서 비동기 UI 작업을 실행하고 예외를 공통 레이아웃의 작업 오류 표시로 전달하는 실행 패턴입니다. 문서 제목은 RunUIAsync이지만 실제 메서드 이름은 대소문자를 포함해 RunUiAsync입니다.
메서드 계약
protected async Task RunUiAsync(
string source,
string operation,
Func<Task> action)
source는 오류가 발생한 화면이나 구성요소, operation은 사용자가 수행하던 작업, action은 실제 비동기 처리입니다.
처리 흐름
| 단계 | 동작 |
|---|---|
| 1 | 전달된 action 실행 |
| 2 | 성공하면 호출 화면으로 복귀 |
| 3 | 예외가 발생하면 BaseMainLayout 존재 여부 확인 |
| 4 | 레이아웃이 있으면 ShowOperationError로 작업 정보와 예외 전달 |
| 5 | 레이아웃이 없으면 예외를 다시 발생시켜 원인을 숨기지 않음 |
기본 사용
private Task SaveAsync()
=> RunUiAsync(
nameof(ItemPage),
"품목 저장",
async () =>
{
await itemService.SaveAsync(model);
await ReloadAsync();
});
버튼 이벤트에서 async void로 감싸지 말고 가능한 경우 Task를 그대로 반환합니다. 이렇게 해야 호출 수명주기와 테스트에서 작업 완료를 추적할 수 있습니다.
source와 operation 작성
source에는 개발자가 위치를 찾을 수 있는 화면명을 사용하고, operation에는 사용자가 이해할 수 있는 작업명을 사용합니다. “오류”, “작업”처럼 범위가 넓은 표현보다 “거래처 저장”, “첨부 파일 삭제”처럼 실제 행동을 적습니다.
오류 표시 책임
RunUiAsync는 예외 전달을 통일하지만 입력 검증, 재시도와 트랜잭션을 대신하지 않습니다. 예상 가능한 업무 오류는 API 응답 계약으로 처리하고, 예외는 네트워크 실패나 처리 중단처럼 정상 흐름으로 완료할 수 없는 상황에 사용합니다.
레이아웃이 없는 경우
테스트나 일부 독립 화면에서 BaseMainLayout이 설정되지 않으면 예외를 다시 발생시킵니다. 이 동작은 오류를 조용히 삼키지 않기 위한 것입니다. 테스트에서는 예외가 발생해야 하는 조건을 명시적으로 검증합니다.
중복 실행
이 메서드는 버튼 비활성화나 취소 토큰을 자동으로 제공하지 않습니다. 저장과 삭제처럼 중복 실행에 민감한 작업은 호출 화면에서 진행 상태를 관리하고, 서버 API에서도 멱등성 또는 중복 방지 규칙을 적용합니다.
문제 확인
RunUIAsync로 잘못 호출하지 않고 실제 이름RunUiAsync를 사용하는지 확인합니다.- 사용자 입력 오류를 예외로만 표시하지 않습니다.
- 작업 실패 후 로딩 표시와 버튼 상태가 원래대로 돌아오는지 확인합니다.
- 오류 메시지에 비밀번호, 토큰과 내부 연결 문자열이 포함되지 않도록 합니다.
