mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-10-31 23:15: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 Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Infrastructure.Services; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
| @@ -10,14 +11,17 @@ namespace Ocelot.Library.Middleware | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IDownstreamRouteFinder _downstreamRouteFinder; | ||||
|         private readonly IHttpResponder _responder; | ||||
|         private readonly IRequestDataService _requestDataService; | ||||
|  | ||||
|         public DownstreamRouteFinderMiddleware(RequestDelegate next,  | ||||
|             IDownstreamRouteFinder downstreamRouteFinder,  | ||||
|             IHttpResponder responder) | ||||
|             IHttpResponder responder, | ||||
|             IRequestDataService requestDataService) | ||||
|         { | ||||
|             _next = next; | ||||
|             _downstreamRouteFinder = downstreamRouteFinder; | ||||
|             _responder = responder; | ||||
|             _requestDataService = requestDataService; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
| @@ -32,7 +36,7 @@ namespace Ocelot.Library.Middleware | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             context.Items.Add("DownstreamRoute", downstreamRoute.Data); | ||||
|             _requestDataService.Add("DownstreamRoute", downstreamRoute.Data); | ||||
|              | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Infrastructure.Services; | ||||
| using Ocelot.Library.Infrastructure.UrlTemplateReplacer; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| @@ -9,34 +11,35 @@ namespace Ocelot.Library.Middleware | ||||
|     { | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; | ||||
|         private readonly IRequestDataService _requestDataService; | ||||
|         private readonly IHttpResponder _responder; | ||||
|  | ||||
|         public DownstreamUrlCreatorMiddleware(RequestDelegate next,  | ||||
|             IDownstreamUrlTemplateVariableReplacer urlReplacer) | ||||
|             IDownstreamUrlTemplateVariableReplacer urlReplacer, | ||||
|             IRequestDataService requestDataService,  | ||||
|             IHttpResponder responder) | ||||
|         { | ||||
|             _next = next; | ||||
|             _urlReplacer = urlReplacer; | ||||
|             _requestDataService = requestDataService; | ||||
|             _responder = responder; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
|         { | ||||
|             var downstreamRoute = GetDownstreamRouteFromOwinItems(context); | ||||
|             var downstreamRoute = _requestDataService.Get<DownstreamRoute>("DownstreamRoute"); | ||||
|  | ||||
|             var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute); | ||||
|  | ||||
|             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)) | ||||
|             if (downstreamRoute.IsError) | ||||
|             { | ||||
|                 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 Ocelot.Library.Infrastructure.Requester; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Infrastructure.Services; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| { | ||||
| @@ -10,38 +11,36 @@ namespace Ocelot.Library.Middleware | ||||
|         private readonly RequestDelegate _next; | ||||
|         private readonly IHttpRequester _requester; | ||||
|         private readonly IHttpResponder _responder; | ||||
|         private readonly IRequestDataService _requestDataService; | ||||
|  | ||||
|         public HttpRequesterMiddleware(RequestDelegate next,  | ||||
|             IHttpRequester requester,  | ||||
|             IHttpResponder responder) | ||||
|             IHttpResponder responder, | ||||
|             IRequestDataService requestDataService) | ||||
|         { | ||||
|             _next = next; | ||||
|             _requester = requester; | ||||
|             _responder = responder; | ||||
|             _requestDataService = requestDataService; | ||||
|         } | ||||
|  | ||||
|         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 | ||||
|                 .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); | ||||
|  | ||||
|             await _responder.CreateResponse(context, response); | ||||
|  | ||||
|             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.Hosting; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Requester; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Infrastructure.Services; | ||||
| using Ocelot.Library.Middleware; | ||||
|  | ||||
| namespace Ocelot | ||||
| @@ -42,6 +44,10 @@ namespace Ocelot | ||||
|             services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>(); | ||||
|             services.AddSingleton<IHttpRequester, HttpClientHttpRequester>(); | ||||
|             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. | ||||
|   | ||||
							
								
								
									
										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