mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-01 06:35:28 +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:
		| @@ -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) | ||||||
|  |  | ||||||
|             context.Items.Add("DownstreamUrl", downstreamUrl); |  | ||||||
|  |  | ||||||
|             await _next.Invoke(context); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private DownstreamRoute GetDownstreamRouteFromOwinItems(HttpContext context) |  | ||||||
|         { |  | ||||||
|             object obj; |  | ||||||
|             DownstreamRoute downstreamRoute = null; |  | ||||||
|             if (context.Items.TryGetValue("DownstreamRoute", out obj)) |  | ||||||
|             { |             { | ||||||
|                 downstreamRoute = (DownstreamRoute) obj; |                 await _responder.CreateNotFoundResponse(context); | ||||||
|  |                 return; | ||||||
|             } |             } | ||||||
|             return downstreamRoute; |  | ||||||
|  |             var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); | ||||||
|  |  | ||||||
|  |             _requestDataService.Add("DownstreamUrl", downstreamUrl); | ||||||
|  |                  | ||||||
|  |             await _next.Invoke(context); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -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(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 TomPallister
					TomPallister