зеркало из https://github.com/Azure/Sia-Root.git
Updated shared components used for proxy communication by the gateway
This commit is contained in:
Родитель
2a8dfd5bf2
Коммит
35dd9473fe
|
@ -0,0 +1,35 @@
|
|||
using Sia.Shared.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace Sia.Shared.Authentication.Http
|
||||
{
|
||||
public class HttpClientLookup
|
||||
{
|
||||
private IDictionary<string, string> _endpointToBaseUrl;
|
||||
private IDictionary<string, HttpClient> _endpointToHttpClient { get; }
|
||||
|
||||
public HttpClientLookup()
|
||||
{
|
||||
_endpointToBaseUrl = new Dictionary<string, string>();
|
||||
_endpointToHttpClient = new Dictionary<string, HttpClient>();
|
||||
}
|
||||
|
||||
public void RegisterEndpoint(string endpointName, string baseUrl)
|
||||
=> _endpointToBaseUrl.Add(endpointName, baseUrl);
|
||||
|
||||
public HttpClient GetClientForEndpoint(string endpointName)
|
||||
{
|
||||
if (_endpointToHttpClient.TryGetValue(endpointName, out HttpClient storedHttpClient)) return storedHttpClient;
|
||||
if (!_endpointToBaseUrl.TryGetValue(endpointName, out string baseUrl)) throw new EndpointNotConfiguredException(endpointName);
|
||||
|
||||
var client = HttpClientExtensions.CreateHttpClient(baseUrl);
|
||||
|
||||
_endpointToHttpClient.Add(endpointName, client);
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace Sia.Shared.Exceptions
|
|||
{
|
||||
public static class ConvertStatusToException
|
||||
{
|
||||
public static void ThrowExceptionOnUnsuccessfulStatus<T>(this IResponse<T> response)
|
||||
public static void ThrowExceptionOnUnsuccessfulStatus(this IResponse response)
|
||||
{
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sia.Shared.Exceptions
|
||||
{
|
||||
public class EndpointNotConfiguredException : Exception
|
||||
{
|
||||
public EndpointNotConfiguredException(string endpointName)
|
||||
: base($"No base URI was configured for ${endpointName}")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,19 +3,23 @@ using Sia.Shared.Authentication;
|
|||
|
||||
namespace Sia.Shared.Requests
|
||||
{
|
||||
public abstract class AuthenticatedRequest<T> : IRequest<T>
|
||||
public abstract class AuthenticatedRequest<T> : AuthenticatedRequestBase, IRequest<T>
|
||||
{
|
||||
protected AuthenticatedRequest(AuthenticatedUserContext userContext)
|
||||
protected AuthenticatedRequest(AuthenticatedUserContext userContext) : base(userContext)
|
||||
{
|
||||
UserContext = userContext;
|
||||
}
|
||||
|
||||
public AuthenticatedUserContext UserContext { get; private set; }
|
||||
}
|
||||
|
||||
public abstract class AuthenticatedRequest : IRequest
|
||||
public abstract class AuthenticatedRequest : AuthenticatedRequestBase, IRequest
|
||||
{
|
||||
protected AuthenticatedRequest(AuthenticatedUserContext userContext)
|
||||
protected AuthenticatedRequest(AuthenticatedUserContext userContext) : base(userContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AuthenticatedRequestBase
|
||||
{
|
||||
protected AuthenticatedRequestBase(AuthenticatedUserContext userContext)
|
||||
{
|
||||
UserContext = userContext;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
using MediatR;
|
||||
using Sia.Shared.Authentication.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using Sia.Shared.Protocol;
|
||||
using Sia.Shared.Exceptions;
|
||||
using Newtonsoft.Json;
|
||||
using Sia.Shared.Requests;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace Sia.Shared.Extensions.Mediatr
|
||||
{
|
||||
public abstract class ProxyHandler<TRequest, TResult> : ProxyHandlerBase<TRequest>, IAsyncRequestHandler<TRequest, TResult>
|
||||
where TRequest : AuthenticatedRequest<TResult>
|
||||
{
|
||||
protected ProxyHandler(HttpClientLookup clientFactory, string endpointName)
|
||||
: base(clientFactory, endpointName)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual async Task<TResult> Handle(TRequest request)
|
||||
{
|
||||
var httpResponse = await SendRequest(request);
|
||||
var logicalResponse = await Response<TResult>.Create(httpResponse);
|
||||
logicalResponse.ThrowExceptionOnUnsuccessfulStatus();
|
||||
return logicalResponse.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ProxyHandler<TRequest> : ProxyHandlerBase<TRequest>, IAsyncRequestHandler<TRequest>
|
||||
where TRequest : AuthenticatedRequest
|
||||
{
|
||||
protected ProxyHandler(HttpClientLookup clientFactory, string endpointName)
|
||||
: base(clientFactory, endpointName)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual async Task Handle(TRequest request)
|
||||
{
|
||||
var httpResponse = await SendRequest(request);
|
||||
var logicalResponse = await Response.Create(httpResponse);
|
||||
logicalResponse.ThrowExceptionOnUnsuccessfulStatus();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ProxyHandlerBase<TRequest>
|
||||
where TRequest: AuthenticatedRequestBase
|
||||
{
|
||||
protected readonly HttpClient _client;
|
||||
protected abstract HttpMethod Method();
|
||||
protected abstract string RelativeUri(TRequest request);
|
||||
protected abstract object MessageContent(TRequest request);
|
||||
|
||||
protected virtual async Task<HttpResponseMessage> SendRequest(TRequest request)
|
||||
{
|
||||
var message = new HttpRequestMessage(Method(), RelativeUri(request));
|
||||
AddContentToMessage(request, message);
|
||||
await AddAuthorizationToMessage(request, message);
|
||||
return await _client.SendAsync(message);
|
||||
}
|
||||
protected virtual void AddContentToMessage(TRequest request, HttpRequestMessage message)
|
||||
{
|
||||
var content = MessageContent(request);
|
||||
if (content is null) return;
|
||||
var encodedContent = JsonConvert.SerializeObject(content);
|
||||
var httpContent = new StringContent(encodedContent, Encoding.UTF8, HttpClientExtensions.JsonMediaType);
|
||||
message.Content = httpContent;
|
||||
}
|
||||
protected virtual async Task AddAuthorizationToMessage(TRequest request, HttpRequestMessage message)
|
||||
{
|
||||
var tokenResult = await HttpClientExtensions.AcquireTokenAsync(request.UserContext);
|
||||
message.Headers.Authorization = new AuthenticationHeaderValue(request.UserContext.AuthConfig.Scheme, tokenResult);
|
||||
}
|
||||
|
||||
protected ProxyHandlerBase(HttpClientLookup clientFactory, string endpointName)
|
||||
{
|
||||
_client = clientFactory.GetClientForEndpoint(endpointName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,16 @@
|
|||
|
||||
namespace Sia.Shared.Protocol
|
||||
{
|
||||
public interface IResponse<T>
|
||||
public interface IResponse<T> : IResponse
|
||||
{
|
||||
T Value { get; }
|
||||
|
||||
}
|
||||
|
||||
public interface IResponse
|
||||
{
|
||||
HttpStatusCode StatusCode { get; }
|
||||
bool IsSuccessStatusCode { get; }
|
||||
string Content { get; }
|
||||
T Value { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,11 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Sia.Shared.Protocol
|
||||
{
|
||||
public class Response<T> : IResponse<T>
|
||||
public class Response<T> : Response, IResponse<T>
|
||||
{
|
||||
public HttpStatusCode StatusCode { get; private set; }
|
||||
public bool IsSuccessStatusCode { get; private set; }
|
||||
public string Content { get; private set; }
|
||||
public T Value { get; private set; }
|
||||
public static async Task<Response<T>> Create(HttpResponseMessage message)
|
||||
|
||||
public static new async Task<Response<T>> Create(HttpResponseMessage message)
|
||||
{
|
||||
var response = new Response<T>();
|
||||
response.IsSuccessStatusCode = message.IsSuccessStatusCode;
|
||||
|
@ -28,4 +26,18 @@ namespace Sia.Shared.Protocol
|
|||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
public class Response : IResponse
|
||||
{
|
||||
public HttpStatusCode StatusCode { get; protected set; }
|
||||
public bool IsSuccessStatusCode { get; protected set; }
|
||||
public string Content { get; protected set; }
|
||||
public static async Task<Response> Create(HttpResponseMessage message)
|
||||
=> new Response()
|
||||
{
|
||||
IsSuccessStatusCode = message.IsSuccessStatusCode,
|
||||
StatusCode = message.StatusCode,
|
||||
Content = await message.Content.ReadAsStringAsync()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче