/// <exception cref="ApiException"></exception>
 private static async Task <HttpResponseMessage> SendCoreAsync(this HttpClient httpClient, HttpRequestMessage requestMessage, ApiRequest request)
 {
     try
     {
         return(await httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false));
     }
     catch (TaskCanceledException ex) when(ex.InnerException is TimeoutException)
     {
         // Handle timeout.
         throw ApiExceptions.ClientTimeout(request: request, innerException: ex);
     }
     catch (TaskCanceledException ex) when(ex.InnerException is SocketException)
     {
         throw ApiExceptions.ApiNotAvailable(request: request, innerException: ex);
     }
     catch (TaskCanceledException ex)
     {
         // Handle cancellation.
         throw ApiExceptions.RequestCanceled(request: request, innerException: ex);
     }
     //TODO: when using .net 5
     //catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
     //{
     //    // Handle 404
     //    Console.WriteLine("Not found: " + ex.Message);
     //}
     catch (OperationCanceledException ex)
     {
         throw ApiExceptions.ApiNotAvailable(request, ex);
     }
     catch (Exception ex)
     {
         throw ApiExceptions.ClientUnkownError(request: request, innerException: ex);
     }
 }
示例#2
0
        public IObservable <Unit> IsAvailable()
        {
            return(Observable.Create <Unit>(async observer =>
            {
                try
                {
                    var endpoint = endpoints.Get;
                    var request = new Request("", endpoint.Url, Enumerable.Empty <HttpHeader>(), endpoint.Method);
                    var response = await apiClient.Send(request).ConfigureAwait(false);

                    if (response.IsSuccess)
                    {
                        observer.OnNext(Unit.Default);
                    }
                    else
                    {
                        var error = ApiExceptions.For(request, response);
                        observer.OnError(error);
                    }
                }
                catch (Exception exception)
                {
                    observer.OnError(exception);
                }

                observer.OnCompleted();
            }));
        }
示例#3
0
 /// <exception cref="ApiException"></exception>
 protected static void EnsureApiNotReturnNull([ValidatedNotNull][NotNull] object?obj, string entityName)
 {
     if (obj == null)
     {
         throw ApiExceptions.ServerNullReturn(parameter: entityName);
     }
 }
示例#4
0
 /// <exception cref="ApiException"></exception>
 protected static void EnsureLogined()
 {
     if (!UserPreferences.IsLogined)
     {
         throw ApiExceptions.NoAuthority();
     }
 }
示例#5
0
        private static async Task <string> makeRequest(string endpoint, HttpMethod method, IUser user, string json)
        {
            var requestMessage = AuthorizedRequestBuilder.CreateRequest(
                Credentials.WithApiToken(user.ApiToken), endpoint, method);

            if (json != null)
            {
                requestMessage.Content = new StringContent(json, Encoding.UTF8, "application/json");
            }

            using (var client = new HttpClient())
            {
                var response = await client.SendAsync(requestMessage);

                var data = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    return(data);
                }

                throw ApiExceptions.For(
                          new Request(json, requestMessage.RequestUri, new HttpHeader[0], requestMessage.Method),
                          new Response(data, false, response.Content?.Headers?.ContentType?.MediaType, response.Headers,
                                       response.StatusCode));
            }
        }
示例#6
0
        protected IObservable <T> CreateObservable <T>(Endpoint endpoint, IEnumerable <HttpHeader> headers, string body = "")
        {
            var request = new Request(body, endpoint.Url, headers, endpoint.Method);

            return(Observable.Create <T>(async observer =>
            {
                var response = await apiClient.Send(request).ConfigureAwait(false);
                if (response.IsSuccess)
                {
                    try
                    {
                        var data = !string.IsNullOrEmpty(response.RawData)
                            ? await Task.Run(() => serializer.Deserialize <T>(response.RawData)).ConfigureAwait(false)
                            : default(T);
                        observer.OnNext(data);
                        observer.OnCompleted();
                    }
                    catch
                    {
                        observer.OnError(new DeserializationException <T>(response.RawData));
                    }
                }
                else
                {
                    var exception = ApiExceptions.ForResponse(response);
                    observer.OnError(exception);
                }
            }));
        }
            public void ReturnsServerErrorException(HttpStatusCode httpStatusCode, Type expectedExceptionType)
            {
                var response = createErrorResponse(httpStatusCode);

                var exception = ApiExceptions.ForResponse(response);

                exception.Should().BeAssignableTo <ServerErrorException>().And.BeOfType(expectedExceptionType);
            }
            public void ReturnsUnknownApiError(HttpStatusCode httpStatusCode)
            {
                var response = createErrorResponse(httpStatusCode);

                var exception = ApiExceptions.ForResponse(response);

                exception.Should().BeOfType <UnknownApiErrorException>()
                .Which.HttpCode.Should().Equals(httpStatusCode);
            }
示例#9
0
            public void ReturnsClientErrorException(HttpStatusCode httpStatusCode, Type expectedExceptionType)
            {
                var request  = createRequest(HttpMethod.Get);
                var response = createErrorResponse(httpStatusCode);

                var exception = ApiExceptions.For(request, response);

                exception.Should().BeAssignableTo <ClientErrorException>().And.BeOfType(expectedExceptionType);
            }
示例#10
0
            public void CreatesAStringStartingWithExceptionName(HttpStatusCode statusCode, Type exceptionType)
            {
                var request   = createRequest(HttpMethod.Get);
                var response  = createErrorResponse(statusCode);
                var exception = ApiExceptions.For(request, response);

                var serialized = exception.ToString();

                serialized.Should().StartWith($"{exceptionType.Name} ");
            }
示例#11
0
            public void ReturnsUnknownApiError(HttpStatusCode httpStatusCode)
            {
                var request  = createRequest(HttpMethod.Get);
                var response = createErrorResponse(httpStatusCode);

                var exception = ApiExceptions.For(request, response);

                exception.Should().BeOfType <UnknownApiErrorException>()
                .Which.HttpCode.Should().Be(httpStatusCode);
            }
示例#12
0
 public virtual IEnumerable <TModel> GetAll(Func <DbSet <TModel>, IQueryable <TModel> > includes = null)
 {
     try
     {
         return(GetIncludes(includes));
     }
     catch (Exception ex)
     {
         throw ApiExceptions.Error("Error while retrieving all objects", ex);
     }
 }
示例#13
0
        public async Task IsAvailable()
        {
            var endpoint = endpoints.Get;
            var request  = new Request("", endpoint.Url, Enumerable.Empty <HttpHeader>(), endpoint.Method);
            var response = await apiClient.Send(request).ConfigureAwait(false);

            if (response.IsSuccess)
            {
                return;
            }

            throw ApiExceptions.For(request, response);
        }
示例#14
0
        public TResponse Login <TRequest, TResponse>(TRequest request)
            where TRequest : IJokJaBreIdentityRequest
            where TResponse : IJokJaBreIdentityResponse
        {
            var model = request.ToIdentityModel <TRequest, TIdentityModel>(m_configuration);
            var user  = m_repository.Get(model);

            if (user == null)
            {
                throw ApiExceptions.NotFound("Username, email or password are not correct");
            }

            return(user.ToIdentityResponse <TResponse>(m_configuration));
        }
示例#15
0
        /// <exception cref="ApiException"></exception>
        protected static bool EnsureInternet(bool throwIfNot = true)
        {
            if (Connectivity.NetworkAccess != NetworkAccess.Internet)
            {
                if (throwIfNot)
                {
                    throw ApiExceptions.NoInternet(cause: "没有联网,且不允许离线");
                }

                return(false);
            }

            return(true);
        }
        public TIdentityModel Create(TIdentityModel model)
        {
            try
            {
                var res = m_context.Set <TIdentityModel>().Add(model);
                m_context.SaveChanges();
                res.Reload();

                return(res.Entity);
            }
            catch (Exception ex)
            {
                throw ApiExceptions.Error("Error while creating identity object", ex);
            }
        }
示例#17
0
        private async Task <Exception> getExceptionFor(IRequest request, IResponse response, IEnumerable <HttpHeader> headers)
        {
            try
            {
                if (response.StatusCode == HttpStatusCode.Forbidden && await isLoggedIn(headers).ConfigureAwait(false) == false)
                {
                    return(new UnauthorizedException(request, response));
                }
            }
            catch (HttpRequestException)
            {
                return(new OfflineException());
            }

            return(ApiExceptions.For(request, response));
        }
示例#18
0
 public virtual async Task <bool> Delete <TClass>(TClass key)
 {
     try
     {
         var obj = m_context.Find <TModel>(key);
         if (obj == null)
         {
             throw ApiExceptions.ObjectNotFound;
         }
         m_context.Remove(obj);
         return((await m_context.SaveChangesAsync()) > 0);
     }
     catch (Exception ex)
     {
         throw ApiExceptions.Error("Error while deleting object", ex);
     }
 }
示例#19
0
        public async Task <TModel> Create(TModel model)
        {
            try
            {
                var res = await m_context.Set <TModel>().AddAsync(model);

                await m_context.SaveChangesAsync();

                await res.ReloadAsync();

                return(res.Entity);
            }
            catch (Exception ex)
            {
                throw ApiExceptions.Error("Error while creating object", ex);
            }
        }
示例#20
0
        /// <summary>
        /// ProcessFormFileAsync
        /// </summary>
        /// <param name="formFile"></param>
        /// <param name="permittedFileSuffixes"></param>
        /// <param name="sizeLimit"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task <byte[]> ProcessFormFileAsync(IFormFile?formFile, string[] permittedFileSuffixes, long sizeLimit)
        {
            // Check the file length. This check doesn't catch files that only have
            // a BOM as their content.
            if (formFile == null || formFile.Length == 0 || permittedFileSuffixes.IsNullOrEmpty())
            {
                throw ApiExceptions.ApiUploadEmptyFile();
            }

            if (formFile.Length > sizeLimit)
            {
                throw ApiExceptions.ApiUploadOverSize();
            }

            try
            {
                using MemoryStream memoryStream = new MemoryStream();

                await formFile.CopyToAsync(memoryStream).ConfigureAwait(false);

                // Check the content length in case the file's only
                // content was a BOM and the content is actually
                // empty after removing the BOM.
                if (memoryStream.Length == 0)
                {
                    throw ApiExceptions.ApiUploadEmptyFile();
                }

                if (!IsValidFileExtensionAndSignature(
                        formFile.FileName, memoryStream, permittedFileSuffixes))
                {
                    throw ApiExceptions.ApiUploadWrongType();
                }
                else
                {
                    return(memoryStream.ToArray());
                }
            }
            catch (Exception ex)
            {
                throw ApiExceptions.ServerUnkownError(fileName: formFile.FileName, innerException: ex);
            }
        }
示例#21
0
        public virtual async Task <TModel> GetById <TClass>(TClass key, Func <DbSet <TModel>, IQueryable <TModel> > includes = null, bool shouldThrowIfNull = true)
        {
            TModel result;

            try
            {
                result = await((DbSet <TModel>)GetIncludes(includes)).FindAsync(key);
            }
            catch (Exception ex)
            {
                throw ApiExceptions.Error("Error while retrieving object", ex);
            }

            if (result == null && shouldThrowIfNull)
            {
                throw ApiExceptions.ObjectNotFound;
            }

            return(result);
        }
示例#22
0
        /// <exception cref="ApiException"></exception>
        public static async Task ThrowIfNotSuccessedAsync(HttpResponseMessage responseMessage)
        {
            if (responseMessage.IsSuccessStatusCode)
            {
                return;
            }

            //TODO: 可以处理404等ProblemDetails的返回
            ErrorCode?errorCode = await responseMessage.DeSerializeJsonAsync <ErrorCode>().ConfigureAwait(false);

            responseMessage.Dispose();

            if (errorCode == null)
            {
                throw ApiExceptions.ServerUnkownError(response: responseMessage);
            }
            else
            {
                throw ApiExceptions.ServerReturnError(errorCode);
            }
        }
示例#23
0
        public async Task <IResponse> Send(IRequest request)
        {
            var       numberOfTries = 0;
            IResponse lastResponse  = null;

            do
            {
                if (lastResponse != null)
                {
                    wait(lastResponse);
                }

                lastResponse = await internalClient.Send(request);

                if (!shouldRetry(lastResponse.StatusCode))
                {
                    return(lastResponse);
                }
            }while (++numberOfTries < maximumNumberOfTries);

            Console.WriteLine($"Maximum number of retries ({maximumNumberOfTries}) exceeded.");
            throw ApiExceptions.For(request, lastResponse);
        }
示例#24
0
        /// <summary>
        /// RefreshAccessTokenAsync
        /// </summary>
        /// <param name="apiClient"></param>
        /// <param name="endpointSettings"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public static async Task <bool> RefreshAccessTokenAsync(IApiClient apiClient, EndpointSettings?endpointSettings)
        {
            if (UserPreferences.AccessToken.IsNullOrEmpty())
            {
                return(false);
            }

            JwtEndpointSetting jwtEndpoint = endpointSettings == null?apiClient.GetDefaultJwtEndpointSetting() : endpointSettings.JwtEndpoint;

            string accessTokenHashKey = SecurityUtil.GetHash(UserPreferences.AccessToken);

            //这个AccessToken不久前刷新过
            if (!_requestLimiter.NoWaitLock(nameof(RefreshAccessTokenAsync), accessTokenHashKey, TimeSpan.FromSeconds(jwtEndpoint.RefreshIntervalSeconds)))
            {
                //可能已经有人在刷新,等他刷新完
                if (!await _lastRefreshResultsAccessSemaphore.WaitAsync(TimeSpan.FromSeconds(10)).ConfigureAwait(false))
                {
                    //等待失败
                    BaseApplication.ExceptionHandler(ApiExceptions.TokenRefreshError(cause: "AccessToken 有人刷新过,等待获取结果失败。"));
                    return(false);
                }

                try
                {
                    if (_lastRefreshResults.TryGetValue(accessTokenHashKey, out bool lastRefreshResult))
                    {
                        return(lastRefreshResult);
                    }

                    BaseApplication.ExceptionHandler(ApiExceptions.TokenRefreshError(cause: "AccessToken 有人刷新过,但结果获取为空。"));
                    return(false);
                }
                finally
                {
                    _lastRefreshResultsAccessSemaphore.Release();
                }
            }

            //开始刷新,其他想取结果的人等着
            await _lastRefreshResultsAccessSemaphore.WaitAsync().ConfigureAwait(false);

            try
            {
                if (UserPreferences.RefreshToken.IsNotNullOrEmpty())
                {
                    RefreshAccessTokenRequest refreshRequest = new RefreshAccessTokenRequest(
                        jwtEndpoint.EndpointName !,
                        jwtEndpoint.Version !,
                        HttpMethod.Get,
                        jwtEndpoint.ResourceName !,
                        UserPreferences.AccessToken,
                        UserPreferences.RefreshToken);

                    AccessTokenResource?resource = await apiClient.GetFirstOrDefaultAsync(refreshRequest).ConfigureAwait(false);

                    if (resource != null)
                    {
                        _lastRefreshResults.Clear();
                        _lastRefreshResults[accessTokenHashKey] = true;

                        OnRefreshSucceed(resource);

                        return(true);
                    }
                }

                //刷新失败
                _lastRefreshResults.Clear();
                _lastRefreshResults[accessTokenHashKey] = false;

                OnRefreshFailed();

                return(false);
            }
            catch
            {
                //刷新失败
                _lastRefreshResults.Clear();
                _lastRefreshResults[accessTokenHashKey] = false;

                OnRefreshFailed();

                throw;
            }
            finally
            {
                _lastRefreshResultsAccessSemaphore.Release();
            }
        }