Skip to content

Commit 80ba5d5

Browse files
committed
Route templating, sample remote API (Consul.io) RESTful, extensions, simple defaultheaders, perf.
1 parent 8463ca9 commit 80ba5d5

30 files changed

+307
-38
lines changed
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
using System.Collections.Generic;
1+
using Microsoft.Extensions.Options;
2+
using System.Collections.Generic;
23

34
namespace NetCoreStack.Proxy
45
{
56
public class DefaultHeaderProvider : IHeaderProvider
67
{
78
public IDictionary<string, string> Headers { get; set; }
89

9-
public DefaultHeaderProvider()
10+
public DefaultHeaderProvider(IOptions<HeaderValues> options)
1011
{
11-
Headers = new Dictionary<string, string>();
12+
Headers = options.Value.Headers;
1213
}
1314
}
1415
}

src/NetCoreStack.Proxy/DefaultProxyContentStreamProvider.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.AspNetCore.WebUtilities;
1+
using Microsoft.AspNetCore.Routing.Template;
2+
using Microsoft.AspNetCore.WebUtilities;
23
using NetCoreStack.Contracts;
34
using NetCoreStack.Proxy.Extensions;
45
using NetCoreStack.Proxy.Internal;
@@ -7,6 +8,7 @@
78
using System.Collections.Generic;
89
using System.IO;
910
using System.Linq;
11+
using System.Net;
1012
using System.Net.Http;
1113
using System.Text;
1214
using System.Threading.Tasks;
@@ -48,10 +50,11 @@ protected virtual HttpContent CreateHttpContent(object value)
4850
public async Task CreateRequestContentAsync(RequestContext requestContext,
4951
HttpRequestMessage request,
5052
ProxyMethodDescriptor descriptor,
51-
UriBuilder uriBuilder)
53+
ProxyUriDefinition proxyUriDefinition)
5254
{
5355
await Task.CompletedTask;
5456

57+
var uriBuilder = proxyUriDefinition.UriBuilder;
5558
var argsDic = descriptor.Resolve(requestContext.Args);
5659
var argsCount = argsDic.Count;
5760
var keys = new List<string>(argsDic.Keys);
@@ -87,6 +90,19 @@ public async Task CreateRequestContentAsync(RequestContext requestContext,
8790
}
8891
if (descriptor.HttpMethod == HttpMethod.Get || descriptor.HttpMethod == HttpMethod.Delete)
8992
{
93+
if (descriptor.Template.HasValue())
94+
{
95+
if (proxyUriDefinition.HasParameter)
96+
{
97+
for (int i = 0; i < proxyUriDefinition.ParameterParts.Count; i++)
98+
{
99+
var key = keys[i];
100+
uriBuilder.Path += ($"/{WebUtility.UrlEncode(requestContext.Args[i]?.ToString())}");
101+
argsDic.Remove(key);
102+
}
103+
}
104+
}
105+
90106
request.RequestUri = QueryStringResolver.Parse(uriBuilder, argsDic);
91107
}
92108
}
Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using Microsoft.AspNetCore.Routing.Template;
2+
using System;
23
using System.Net.Http;
34

45
namespace NetCoreStack.Proxy
@@ -12,24 +13,31 @@ public DefaultProxyEndpointManager(RoundRobinManager roundRobinManager)
1213
RoundRobinManager = roundRobinManager;
1314
}
1415

15-
public UriBuilder CreateUriBuilder(ProxyDescriptor descriptor, string regionKey, string targetMethodName)
16+
public ProxyUriDefinition CreateUriDefinition(ProxyDescriptor descriptor, string regionKey, string targetMethodName)
1617
{
1718
var uriBuilder = RoundRobinManager.RoundRobinUri(regionKey);
18-
1919
if (uriBuilder == null)
2020
{
2121
throw new ArgumentNullException(nameof(uriBuilder));
2222
}
2323

24+
var uriDefinition = new ProxyUriDefinition(uriBuilder);
25+
2426
if (!string.IsNullOrEmpty(descriptor.Route))
2527
{
2628
if (targetMethodName.ToLower() == HttpMethod.Get.Method.ToLower())
27-
uriBuilder.Path = $"{descriptor.Route}/";
29+
uriDefinition.UriBuilder.Path = $"{descriptor.Route}/";
2830
else
29-
uriBuilder.Path = $"{descriptor.Route}/{targetMethodName}";
31+
{
32+
if (targetMethodName.StartsWith("/"))
33+
targetMethodName = targetMethodName.Substring(1);
34+
35+
var routeTemplate = TemplateParser.Parse(targetMethodName);
36+
uriDefinition.ResolveTemplate(routeTemplate, descriptor.Route, targetMethodName);
37+
}
3038
}
3139

32-
return uriBuilder;
40+
return uriDefinition;
3341
}
3442
}
3543
}

src/NetCoreStack.Proxy/Extensions/ServiceCollectionExtensions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
using Microsoft.Extensions.Configuration;
33
using Microsoft.Extensions.DependencyInjection;
44
using Microsoft.Extensions.DependencyInjection.Extensions;
5+
using Microsoft.Extensions.Options;
56
using NetCoreStack.Contracts;
67
using NetCoreStack.Proxy.Internal;
78
using System;
9+
using System.Collections;
10+
using System.Collections.Generic;
811
using System.Reflection;
912

1013
namespace NetCoreStack.Proxy
@@ -18,6 +21,8 @@ public static void AddNetCoreProxy(this IServiceCollection services,
1821
IConfigurationRoot configuration,
1922
Action<ProxyBuilderOptions> setup)
2023
{
24+
services.AddOptions();
25+
2126
if (services == null)
2227
{
2328
throw new ArgumentNullException(nameof(services));
@@ -54,6 +59,8 @@ public static void AddNetCoreProxy(this IServiceCollection services,
5459
genericRegistry.Invoke(null, new object[] { services });
5560
}
5661

62+
var headerValues = new HeaderValues { Headers = proxyBuilderOptions.DefaultHeaders };
63+
services.AddSingleton(Options.Create(headerValues));
5764
services.AddSingleton(proxyBuilderOptions);
5865
}
5966

src/NetCoreStack.Proxy/Extensions/StringExtensions.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,34 @@
33

44
namespace NetCoreStack.Proxy.Extensions
55
{
6-
public static class StringExtensions
6+
internal static class StringExtensions
77
{
88
const string rawControllerDefinition = "[Controller]";
99
const string regexForApi = "^I(.*)Api$";
10-
const string ApiRootPath = "api/";
10+
11+
private static string regexControllerDefinition => rawControllerDefinition.Replace("[", "\\[")
12+
.Replace("]", "\\]");
1113

1214
public static bool HasValue(this string value)
1315
{
1416
return !string.IsNullOrEmpty(value);
1517
}
1618

17-
public static string GetApiRawName(this string name, string path)
19+
public static string GetApiRootPath(this string name, string template)
1820
{
19-
var apiPath = Regex.Match(name, regexForApi);
20-
if (!apiPath.Success)
21-
throw new InvalidOperationException($"API - Proxy name format is invalid." +
22-
$"The valid format for API - Proxy Regex is: \"{regexForApi}\"!");
21+
var defaultRootPath = $"api/{rawControllerDefinition}";
22+
if (template.Equals(defaultRootPath, StringComparison.OrdinalIgnoreCase))
23+
{
24+
var apiPath = Regex.Match(name, regexForApi);
25+
if (!apiPath.Success)
26+
throw new InvalidOperationException($"API - Proxy name format is invalid." +
27+
$"The valid format for API - Proxy Regex is: \"{regexForApi}\"!");
28+
29+
var rootName = apiPath.Groups[1].Value;
30+
return Regex.Replace(template, regexControllerDefinition, rootName, RegexOptions.IgnoreCase);
31+
}
2332

24-
return ApiRootPath + apiPath.Groups[1].Value;
33+
return template;
2534
}
2635

2736
public static bool IsJson(this string input)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Collections.Generic;
2+
3+
namespace NetCoreStack.Proxy
4+
{
5+
public class HeaderValues
6+
{
7+
public IDictionary<string, string> Headers { get; set; }
8+
9+
public HeaderValues()
10+
{
11+
Headers = new Dictionary<string, string>();
12+
}
13+
}
14+
}

src/NetCoreStack.Proxy/Interfaces/IProxyContentStreamProvider.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ namespace NetCoreStack.Proxy
66
{
77
public interface IProxyContentStreamProvider
88
{
9-
Task CreateRequestContentAsync(RequestContext requestContext, HttpRequestMessage request, ProxyMethodDescriptor descriptor, UriBuilder uriBuilder);
9+
Task CreateRequestContentAsync(RequestContext requestContext,
10+
HttpRequestMessage request,
11+
ProxyMethodDescriptor descriptor,
12+
ProxyUriDefinition proxyUriDefinition);
1013
}
1114
}
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using System;
2-
3-
namespace NetCoreStack.Proxy
1+
namespace NetCoreStack.Proxy
42
{
53
public interface IProxyEndpointManager
64
{
7-
UriBuilder CreateUriBuilder(ProxyDescriptor descriptor, string regionKey, string targetMethodName);
5+
ProxyUriDefinition CreateUriDefinition(ProxyDescriptor descriptor, string regionKey, string targetMethodName);
86
}
97
}

src/NetCoreStack.Proxy/Internal/DefaultProxyTypeManager.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ private IList<ProxyDescriptor> GetProxyDescriptors()
3636
if (!pathAttr.RegionKey.HasValue())
3737
throw new ArgumentOutOfRangeException($"Specify the \"{nameof(pathAttr.RegionKey)}\"!");
3838

39-
var route = proxyType.Name.GetApiRawName(pathAttr.RouteTemplate);
39+
var route = proxyType.Name.GetApiRootPath(pathAttr.RouteTemplate);
4040

4141
ProxyDescriptor descriptor = new ProxyDescriptor(proxyType, pathAttr.RegionKey, route);
4242

@@ -70,7 +70,12 @@ private IList<ProxyDescriptor> GetProxyDescriptors()
7070

7171
if (httpMethodAttribute != null)
7272
{
73-
if (httpMethodAttribute is HttpPostMarkerAttribute)
73+
if (httpMethodAttribute.Template.HasValue())
74+
proxyMethodDescriptor.Template = httpMethodAttribute.Template;
75+
76+
if (httpMethodAttribute is HttpGetMarkerAttribute)
77+
proxyMethodDescriptor.HttpMethod = HttpMethod.Get;
78+
else if (httpMethodAttribute is HttpPostMarkerAttribute)
7479
proxyMethodDescriptor.HttpMethod = HttpMethod.Post;
7580
else if(httpMethodAttribute is HttpPutMarkerAttribute)
7681
proxyMethodDescriptor.HttpMethod = HttpMethod.Put;

src/NetCoreStack.Proxy/Internal/ProxyManager.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.AspNetCore.Http;
22
using Microsoft.Extensions.Options;
3+
using NetCoreStack.Proxy.Extensions;
34
using NetCoreStack.Proxy.Internal;
45
using System;
56
using System.Collections.Generic;
@@ -114,12 +115,15 @@ public async Task<RequestDescriptor> CreateDescriptorAsync(RequestContext contex
114115
throw new ArgumentOutOfRangeException("Method (Action) info could not be found!");
115116

116117
request.Method = methodDescriptor.HttpMethod;
117-
UriBuilder proxyUriBuilder = _endpointManager.CreateUriBuilder(proxyDescriptor, regionKey, context.TargetMethod.Name);
118+
var methodPath = context.TargetMethod.Name;
119+
if (methodDescriptor.Template.HasValue())
120+
methodPath = methodDescriptor.Template;
118121

122+
ProxyUriDefinition proxyUriDefinition = _endpointManager.CreateUriDefinition(proxyDescriptor, regionKey, methodPath);
119123
TimeSpan? timeout = methodDescriptor.Timeout;
120124

121-
request.RequestUri = proxyUriBuilder.Uri;
122-
await _streamProvider.CreateRequestContentAsync(context, request, methodDescriptor, proxyUriBuilder);
125+
request.RequestUri = proxyUriDefinition.UriBuilder.Uri;
126+
await _streamProvider.CreateRequestContentAsync(context, request, methodDescriptor, proxyUriDefinition);
123127

124128
return new RequestDescriptor(request,
125129
methodDescriptor,

0 commit comments

Comments
 (0)