internal class SailplayApiStrictClient: ISailplayApiStrictClient { private readonly IAuthorizationExecutor authorizationExecutor; private readonly IRequestExecutor requestExecutor; public SailplayApiStrictClient( IAuthorizationExecutor authorizationExecutor, IRequestExecutor requestExecutor) { this.authorizationExecutor = authorizationExecutor; this.requestExecutor = requestExecutor; } public async Task < UpdateUserResult > UpdateUserAsync( SailplayCredentials credentials, UpdateUser requestData, CancellationToken cancellationToken) { var updateUserRequest = new UpdateUserRequest( credentials: credentials, requestData: requestData); var apiResponse = await this.requestExecutor.ExecuteApiRequestAsync( apiPath: ApiPath.UsersUpdate, sailplayApiRequest: updateUserRequest, cancellationToken: cancellationToken); return apiResponse.Match( onSuccess: UpdateUserResult.FromSuccess, onError: errorResult => { return errorResult.ErrorCode switch { ApiResponse.ErrorCodes.InvalidValue => UpdateUserResult.FromError( ErrorResult.FromInvalidValue( errorCode: errorResult.ErrorCode, message: errorResult.Message)), ApiResponse.ErrorCodes.UserNotFound => UpdateUserResult.FromError( ErrorResult.FromUserNotFound( errorCode: errorResult.ErrorCode, message: errorResult.Message)), ApiResponse.ErrorCodes.EmailIsUsed => UpdateUserResult.FromError( ErrorResult.FromEmailIsUsed( errorCode: errorResult.ErrorCode, message: errorResult.Message)), ApiResponse.ErrorCodes.PhoneIsUsed => UpdateUserResult.FromError( ErrorResult.FromPhoneIsUsed( errorCode: errorResult.ErrorCode, message: errorResult.Message)), _ => UpdateUserResult.FromError( ErrorResult.FromGeneralError( errorCode: errorResult.ErrorCode, message: errorResult.Message)), }; }, onUnexpectedHttpStatusCode: UpdateUserResult.FromUnexpectedHttpStatusCode); } } internal class RequestExecutor: IRequestExecutor { private readonly HttpClient httpClient; private readonly IMetricsCollector metricsCollector; private readonly ITokenProvider tokenProvider; public RequestExecutor( HttpClient httpClient, IMetricsCollector metricsCollector, ITokenProvider tokenProvider) { this.httpClient = httpClient; this.metricsCollector = metricsCollector; this.tokenProvider = tokenProvider; } public async Task < SailplayApiResult > ExecuteApiRequestAsync( string apiPath, ISailplayApiRequest sailplayApiRequest, CancellationToken cancellationToken) { var tokenResult = await this.tokenProvider .GetTokenAsync( credentials: sailplayApiRequest.Credentials, cancellationToken: cancellationToken); return await Policy.HandleResult < SailplayApiResult > (apiResult => apiResult.IsAuthorizationTokenError) .RetryAsync( retryCount: 1, onRetryAsync: async (_, _, _) => { tokenResult = await this.tokenProvider.RenewTokenAsync( credentials: sailplayApiRequest.Credentials, cancellationToken: cancellationToken); }) .ExecuteAsync( async () => await tokenResult .Match( onSuccess: async successfullyGetTokenResult => { var request = HttpRequestMessageFactory.BuildPost( requestUri: apiPath); request.Content = sailplayApiRequest.ConvertToHttpContent( token: successfullyGetTokenResult.Token); return await this .ExecuteRequestAsync( request: request, cancellationToken: cancellationToken); }, onError: result => Task.FromResult( SailplayApiResult.FromError( statusCode: result.ErrorCode, message: result.Message)), onUnexpectedHttpStatusCode: result => Task.FromResult( SailplayApiResult.FromUnexpectedHttpStatusCode( httpStatusCode: result.StatusCode)))); } private async Task < SailplayApiResult > ExecuteRequestAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var stopwatch = Stopwatch.StartNew(); using var httpResponseMessage = await this .httpClient .SendAsync( request: request, cancellationToken: cancellationToken); this.metricsCollector.CollectHttpRequestDuration( uri: request.RequestUri, statusCode: httpResponseMessage.StatusCode, elapsedMilliseconds: stopwatch.ElapsedMilliseconds); var result = await this.MapHttpResponseAsync( httpResponseMessage: httpResponseMessage, cancellationToken: cancellationToken); return result; } private async Task < SailplayApiResult > MapHttpResponseAsync( HttpResponseMessage httpResponseMessage, CancellationToken cancellationToken) { var basicResponse = await httpResponseMessage .Content .ReadFromJsonAsync < BasicResponse > ( cancellationToken: cancellationToken); return httpResponseMessage.StatusCode switch { HttpStatusCode.OK => basicResponse!.Match( onStatusOk: SailplayApiResult.FromSuccess, onStatusError: SailplayApiResult.FromError), _ => SailplayApiResult.FromUnexpectedHttpStatusCode(httpResponseMessage.StatusCode), }; } } internal class UpdateUserRequest: ISailplayApiRequest { private readonly UpdateUser requestData; internal UpdateUserRequest( SailplayCredentials credentials, UpdateUser requestData) { this.Credentials = credentials; this.requestData = requestData; } public SailplayCredentials Credentials { get; set; } public HttpContent ConvertToHttpContent( string token) { var keyValuePairs = new List < KeyValuePair < string, string >> { FormDataFactory.FromToken(token), FormDataFactory.FromStoreDepartmentId(this.Credentials.StoreDepartmentId), }; keyValuePairs.AddRange(FormDataFactory.FromUserId(this.requestData.UserId)); this.requestData.Phone.MatchSome(phone => keyValuePairs.Add(FormDataFactory.FromNewPhone(phone))); this.requestData.Email.MatchSome(email => keyValuePairs.Add(FormDataFactory.FromNewEmail(email))); this.requestData.FirstName.MatchSome(firstName => keyValuePairs.Add(FormDataFactory.FromFirstName(firstName))); this.requestData.MiddleName.MatchSome(middleName => keyValuePairs.Add(FormDataFactory.FromMiddleName(middleName))); this.requestData.LastName.MatchSome(lastName => keyValuePairs.Add(FormDataFactory.FromLastName(lastName))); this.requestData.BirthDate.MatchSome(birthDate => keyValuePairs.Add(FormDataFactory.FromBirthDate(birthDate))); this.requestData.Sex.MatchSome(sex => keyValuePairs.Add(FormDataFactory.FromSex(sex))); this.requestData.RegisterDate.MatchSome(registerDate => keyValuePairs.Add(FormDataFactory.FromRegisterDate(registerDate))); return new FormUrlEncodedContent(keyValuePairs); } } у меня есть три класса, я бы хотел, чтобы UpdateUserRequest можно было создать где угодно, а его метод ConvertToHttpContent можно было вызвать только в RequestExecutor