mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:42:50 +08:00
Added some wrapper around the http context so i can at least pretend to access things from it without casting them
This commit is contained in:
parent
ab8407e7dc
commit
229c0878ed
@ -0,0 +1,11 @@
|
|||||||
|
using Ocelot.Library.Infrastructure.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.Services
|
||||||
|
{
|
||||||
|
public class CannotAddDataError : Error
|
||||||
|
{
|
||||||
|
public CannotAddDataError(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using Ocelot.Library.Infrastructure.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.Services
|
||||||
|
{
|
||||||
|
public class CannotFindDataError : Error
|
||||||
|
{
|
||||||
|
public CannotFindDataError(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
using Ocelot.Library.Infrastructure.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.Services
|
||||||
|
{
|
||||||
|
public interface IRequestDataService
|
||||||
|
{
|
||||||
|
Response Add<T>(string key, T value);
|
||||||
|
Response<T> Get<T>(string key);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Ocelot.Library.Infrastructure.Responses;
|
||||||
|
|
||||||
|
namespace Ocelot.Library.Infrastructure.Services
|
||||||
|
{
|
||||||
|
public class RequestDataService : IRequestDataService
|
||||||
|
{
|
||||||
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||||
|
|
||||||
|
public RequestDataService(IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
_httpContextAccessor = httpContextAccessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response Add<T>(string key, T value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_httpContextAccessor.HttpContext.Items.Add(key, value);
|
||||||
|
return new OkResponse();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
return new ErrorResponse(new List<Error>
|
||||||
|
{
|
||||||
|
new CannotAddDataError(string.Format($"Unable to add data for key: {key}, exception: {exception.Message}"))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<T> Get<T>(string key)
|
||||||
|
{
|
||||||
|
object obj;
|
||||||
|
|
||||||
|
if(_httpContextAccessor.HttpContext.Items.TryGetValue(key, out obj))
|
||||||
|
{
|
||||||
|
var data = (T) obj;
|
||||||
|
return new OkResponse<T>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ErrorResponse<T>(new List<Error>
|
||||||
|
{
|
||||||
|
new CannotFindDataError($"Unable to find data for key: {key}")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
using Ocelot.Library.Infrastructure.Responder;
|
using Ocelot.Library.Infrastructure.Responder;
|
||||||
|
using Ocelot.Library.Infrastructure.Services;
|
||||||
|
|
||||||
namespace Ocelot.Library.Middleware
|
namespace Ocelot.Library.Middleware
|
||||||
{
|
{
|
||||||
@ -10,14 +11,17 @@ namespace Ocelot.Library.Middleware
|
|||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
private readonly IDownstreamRouteFinder _downstreamRouteFinder;
|
||||||
private readonly IHttpResponder _responder;
|
private readonly IHttpResponder _responder;
|
||||||
|
private readonly IRequestDataService _requestDataService;
|
||||||
|
|
||||||
public DownstreamRouteFinderMiddleware(RequestDelegate next,
|
public DownstreamRouteFinderMiddleware(RequestDelegate next,
|
||||||
IDownstreamRouteFinder downstreamRouteFinder,
|
IDownstreamRouteFinder downstreamRouteFinder,
|
||||||
IHttpResponder responder)
|
IHttpResponder responder,
|
||||||
|
IRequestDataService requestDataService)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_downstreamRouteFinder = downstreamRouteFinder;
|
_downstreamRouteFinder = downstreamRouteFinder;
|
||||||
_responder = responder;
|
_responder = responder;
|
||||||
|
_requestDataService = requestDataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
@ -32,7 +36,7 @@ namespace Ocelot.Library.Middleware
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Items.Add("DownstreamRoute", downstreamRoute.Data);
|
_requestDataService.Add("DownstreamRoute", downstreamRoute.Data);
|
||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
|
using Ocelot.Library.Infrastructure.Responder;
|
||||||
|
using Ocelot.Library.Infrastructure.Services;
|
||||||
using Ocelot.Library.Infrastructure.UrlTemplateReplacer;
|
using Ocelot.Library.Infrastructure.UrlTemplateReplacer;
|
||||||
|
|
||||||
namespace Ocelot.Library.Middleware
|
namespace Ocelot.Library.Middleware
|
||||||
@ -9,34 +11,35 @@ namespace Ocelot.Library.Middleware
|
|||||||
{
|
{
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer;
|
private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer;
|
||||||
|
private readonly IRequestDataService _requestDataService;
|
||||||
|
private readonly IHttpResponder _responder;
|
||||||
|
|
||||||
public DownstreamUrlCreatorMiddleware(RequestDelegate next,
|
public DownstreamUrlCreatorMiddleware(RequestDelegate next,
|
||||||
IDownstreamUrlTemplateVariableReplacer urlReplacer)
|
IDownstreamUrlTemplateVariableReplacer urlReplacer,
|
||||||
|
IRequestDataService requestDataService,
|
||||||
|
IHttpResponder responder)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_urlReplacer = urlReplacer;
|
_urlReplacer = urlReplacer;
|
||||||
|
_requestDataService = requestDataService;
|
||||||
|
_responder = responder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
var downstreamRoute = GetDownstreamRouteFromOwinItems(context);
|
var downstreamRoute = _requestDataService.Get<DownstreamRoute>("DownstreamRoute");
|
||||||
|
|
||||||
var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute);
|
if (downstreamRoute.IsError)
|
||||||
|
{
|
||||||
|
await _responder.CreateNotFoundResponse(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context.Items.Add("DownstreamUrl", downstreamUrl);
|
var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data);
|
||||||
|
|
||||||
|
_requestDataService.Add("DownstreamUrl", downstreamUrl);
|
||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DownstreamRoute GetDownstreamRouteFromOwinItems(HttpContext context)
|
|
||||||
{
|
|
||||||
object obj;
|
|
||||||
DownstreamRoute downstreamRoute = null;
|
|
||||||
if (context.Items.TryGetValue("DownstreamRoute", out obj))
|
|
||||||
{
|
|
||||||
downstreamRoute = (DownstreamRoute) obj;
|
|
||||||
}
|
|
||||||
return downstreamRoute;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ using System.Threading.Tasks;
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Ocelot.Library.Infrastructure.Requester;
|
using Ocelot.Library.Infrastructure.Requester;
|
||||||
using Ocelot.Library.Infrastructure.Responder;
|
using Ocelot.Library.Infrastructure.Responder;
|
||||||
|
using Ocelot.Library.Infrastructure.Services;
|
||||||
|
|
||||||
namespace Ocelot.Library.Middleware
|
namespace Ocelot.Library.Middleware
|
||||||
{
|
{
|
||||||
@ -10,38 +11,36 @@ namespace Ocelot.Library.Middleware
|
|||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IHttpRequester _requester;
|
private readonly IHttpRequester _requester;
|
||||||
private readonly IHttpResponder _responder;
|
private readonly IHttpResponder _responder;
|
||||||
|
private readonly IRequestDataService _requestDataService;
|
||||||
|
|
||||||
public HttpRequesterMiddleware(RequestDelegate next,
|
public HttpRequesterMiddleware(RequestDelegate next,
|
||||||
IHttpRequester requester,
|
IHttpRequester requester,
|
||||||
IHttpResponder responder)
|
IHttpResponder responder,
|
||||||
|
IRequestDataService requestDataService)
|
||||||
{
|
{
|
||||||
_next = next;
|
_next = next;
|
||||||
_requester = requester;
|
_requester = requester;
|
||||||
_responder = responder;
|
_responder = responder;
|
||||||
|
_requestDataService = requestDataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(HttpContext context)
|
public async Task Invoke(HttpContext context)
|
||||||
{
|
{
|
||||||
var downstreamUrl = GetDownstreamUrlFromOwinItems(context);
|
var downstreamUrl = _requestDataService.Get<string>("DownstreamUrl");
|
||||||
|
|
||||||
|
if (downstreamUrl.IsError)
|
||||||
|
{
|
||||||
|
await _responder.CreateNotFoundResponse(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var response = await _requester
|
var response = await _requester
|
||||||
.GetResponse(context.Request.Method, downstreamUrl, context.Request.Body,
|
.GetResponse(context.Request.Method, downstreamUrl.Data, context.Request.Body,
|
||||||
context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType);
|
context.Request.Headers, context.Request.Cookies, context.Request.Query, context.Request.ContentType);
|
||||||
|
|
||||||
await _responder.CreateResponse(context, response);
|
await _responder.CreateResponse(context, response);
|
||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetDownstreamUrlFromOwinItems(HttpContext context)
|
|
||||||
{
|
|
||||||
object obj;
|
|
||||||
string downstreamUrl = null;
|
|
||||||
if (context.Items.TryGetValue("DownstreamUrl", out obj))
|
|
||||||
{
|
|
||||||
downstreamUrl = (string) obj;
|
|
||||||
}
|
|
||||||
return downstreamUrl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,11 +1,13 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
using Ocelot.Library.Infrastructure.DownstreamRouteFinder;
|
||||||
using Ocelot.Library.Infrastructure.Requester;
|
using Ocelot.Library.Infrastructure.Requester;
|
||||||
using Ocelot.Library.Infrastructure.Responder;
|
using Ocelot.Library.Infrastructure.Responder;
|
||||||
|
using Ocelot.Library.Infrastructure.Services;
|
||||||
using Ocelot.Library.Middleware;
|
using Ocelot.Library.Middleware;
|
||||||
|
|
||||||
namespace Ocelot
|
namespace Ocelot
|
||||||
@ -42,6 +44,10 @@ namespace Ocelot
|
|||||||
services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>();
|
services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>();
|
||||||
services.AddSingleton<IHttpRequester, HttpClientHttpRequester>();
|
services.AddSingleton<IHttpRequester, HttpClientHttpRequester>();
|
||||||
services.AddSingleton<IHttpResponder, HttpContextResponder>();
|
services.AddSingleton<IHttpResponder, HttpContextResponder>();
|
||||||
|
|
||||||
|
// see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
services.AddScoped<IRequestDataService, RequestDataService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
83
test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs
Normal file
83
test/Ocelot.UnitTests/Services/RequestDataServiceTests.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Moq;
|
||||||
|
using Ocelot.Library.Infrastructure.Responses;
|
||||||
|
using Ocelot.Library.Infrastructure.Services;
|
||||||
|
using Shouldly;
|
||||||
|
using TestStack.BDDfy;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Ocelot.UnitTests.Services
|
||||||
|
{
|
||||||
|
public class RequestDataServiceTests
|
||||||
|
{
|
||||||
|
private IRequestDataService _requestDataService;
|
||||||
|
private IHttpContextAccessor _httpContextAccesor;
|
||||||
|
private string _key;
|
||||||
|
private object _toAdd;
|
||||||
|
private Response<int[]> _result;
|
||||||
|
|
||||||
|
public RequestDataServiceTests()
|
||||||
|
{
|
||||||
|
_httpContextAccesor = new HttpContextAccessor();
|
||||||
|
_httpContextAccesor.HttpContext = new DefaultHttpContext();
|
||||||
|
_requestDataService = new RequestDataService(_httpContextAccesor);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_add_item()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenIHaveAnItemToAdd("blahh", new [] {1,2,3,4}))
|
||||||
|
.When(x => x.WhenIAddTheItem())
|
||||||
|
.Then(x => x.ThenTheItemIsAdded())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_get_item()
|
||||||
|
{
|
||||||
|
this.Given(x => x.GivenThereIsAnItemInTheContext("chest"))
|
||||||
|
.When(x => x.WhenIGetTheItem())
|
||||||
|
.Then(x => x.ThenTheItemIsReturned())
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheItemIsReturned()
|
||||||
|
{
|
||||||
|
_result.IsError.ShouldBeFalse();
|
||||||
|
_result.Data.ShouldNotBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIGetTheItem()
|
||||||
|
{
|
||||||
|
_result = _requestDataService.Get<int[]>(_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThereIsAnItemInTheContext(string key)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
var data = new[] {5435345};
|
||||||
|
_httpContextAccesor.HttpContext.Items.Add(key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenIHaveAnItemToAdd(string key, object toAdd)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
_toAdd = toAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WhenIAddTheItem()
|
||||||
|
{
|
||||||
|
_requestDataService.Add(_key, _toAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenTheItemIsAdded()
|
||||||
|
{
|
||||||
|
object obj;
|
||||||
|
_httpContextAccesor.HttpContext.Items.TryGetValue(_key, out obj).ShouldBeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user