Skip to content

Commit d9770f0

Browse files
committed
content resolver parameters, ensure template, offset params
1 parent 5c579f9 commit d9770f0

25 files changed

+176
-140
lines changed

src/NetCoreStack.Proxy/Binders/HttpDeleteContentBinder.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
using NetCoreStack.Proxy.Extensions;
2-
using System.Collections.Generic;
3-
using System.Linq;
42
using System.Net.Http;
53

64
namespace NetCoreStack.Proxy
@@ -11,9 +9,13 @@ public class HttpDeleteContentBinder : ContentModelBinder
119

1210
public override void BindContent(ContentModelBindingContext bindingContext)
1311
{
14-
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters, bindingContext.Args);
15-
List<string> keys = result.Dictionary.Keys.ToList();
16-
EnsureTemplate(bindingContext, result.Dictionary, keys);
12+
EnsureTemplateResult ensureTemplateResult = EnsureTemplate(bindingContext);
13+
if (ensureTemplateResult.BindingCompleted)
14+
return;
15+
16+
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters,
17+
bindingContext.Args,
18+
ensureTemplateResult.ParameterOffset);
1719

1820
bindingContext.TryUpdateUri(result.Dictionary);
1921
}

src/NetCoreStack.Proxy/Binders/HttpGetContentBinder.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
using NetCoreStack.Proxy.Extensions;
2-
using System.Collections.Generic;
3-
using System.Linq;
42
using System.Net.Http;
53

64
namespace NetCoreStack.Proxy
@@ -11,10 +9,15 @@ public class HttpGetContentBinder : ContentModelBinder
119

1210
public override void BindContent(ContentModelBindingContext bindingContext)
1311
{
14-
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters, bindingContext.Args);
15-
List<string> keys = result.Dictionary.Keys.ToList();
16-
EnsureTemplate(bindingContext, result.Dictionary, keys);
12+
EnsureTemplateResult ensureTemplateResult = EnsureTemplate(bindingContext);
13+
if (ensureTemplateResult.BindingCompleted)
14+
return;
1715

16+
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters,
17+
bindingContext.Args,
18+
ensureTemplateResult.ParameterOffset,
19+
ensureTemplateResult.IgnoreModelPrefix);
20+
1821
bindingContext.TryUpdateUri(result.Dictionary);
1922
}
2023
}

src/NetCoreStack.Proxy/Binders/HttpPostContentBinder.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,18 @@ public class HttpPostContentBinder : BodyContentBinder
88

99
public override void BindContent(ContentModelBindingContext bindingContext)
1010
{
11+
EnsureTemplateResult ensureTemplateResult = EnsureTemplate(bindingContext);
12+
if (ensureTemplateResult.BindingCompleted)
13+
return;
14+
15+
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters,
16+
bindingContext.Args,
17+
ensureTemplateResult.ParameterOffset,
18+
ensureTemplateResult.IgnoreModelPrefix);
19+
1120
var isMultiPartFormData = bindingContext.IsMultiPartFormData;
1221
if (isMultiPartFormData)
1322
{
14-
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters, bindingContext.Args);
1523
var content = GetMultipartFormDataContent(result);
1624
bindingContext.ContentResult = ContentModelBindingResult.Success(content);
1725
return;

src/NetCoreStack.Proxy/Binders/HttpPutContentBinder.cs

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System.Collections.Generic;
2-
using System.Linq;
3-
using System.Net.Http;
1+
using System.Net.Http;
42

53
namespace NetCoreStack.Proxy
64
{
@@ -10,44 +8,23 @@ public class HttpPutContentBinder : BodyContentBinder
108

119
public override void BindContent(ContentModelBindingContext bindingContext)
1210
{
13-
var isMultiPartFormData = bindingContext.IsMultiPartFormData;
14-
var hasAnyTemplateParameterKey = bindingContext.HasAnyTemplateParameterKey;
15-
if (bindingContext.ArgsLength == 1 && hasAnyTemplateParameterKey)
16-
{
17-
ModelDictionaryResult mdr = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters, bindingContext.Args);
18-
List<string> mdrKeys = mdr.Dictionary.Keys.ToList();
19-
EnsureTemplate(bindingContext, mdr.Dictionary, mdrKeys);
11+
EnsureTemplateResult ensureTemplateResult = EnsureTemplate(bindingContext);
12+
if (ensureTemplateResult.BindingCompleted)
2013
return;
21-
}
22-
23-
//List<ProxyModelMetadata> modelMetadataKeyList = new List<ProxyModelMetadata>();
24-
//int parameterOffset = 0;
25-
//foreach (var key in templateParameterKeys)
26-
//{
27-
// // Key template must be top level object property or parameter
28-
// ProxyModelMetadata keyModelMetadata = bindingContext.Parameters.FirstOrDefault(p => p.PropertyName == key);
29-
// if (keyModelMetadata != null)
30-
// {
31-
// modelMetadataKeyList.Add(keyModelMetadata);
32-
// bindingContext.Parameters.Remove(keyModelMetadata);
33-
// parameterOffset++;
34-
// }
35-
//}
3614

15+
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters,
16+
bindingContext.Args,
17+
ensureTemplateResult.ParameterOffset,
18+
ensureTemplateResult.IgnoreModelPrefix);
3719

38-
ModelDictionaryResult result = bindingContext.ModelContentResolver.Resolve(bindingContext.Parameters, bindingContext.Args);
39-
List<string> keys = result.Dictionary.Keys.ToList();
40-
EnsureTemplate(bindingContext, result.Dictionary, keys);
41-
20+
var isMultiPartFormData = bindingContext.IsMultiPartFormData;
4221
if (isMultiPartFormData)
4322
{
4423
var content = GetMultipartFormDataContent(result);
4524
bindingContext.ContentResult = ContentModelBindingResult.Success(content);
4625
return;
4726
}
4827

49-
// PUT Request first parameter should be Id or Key then will be removed from the result dictionary
50-
// The remaining parameters belong to the body
5128
bindingContext.ContentResult = ContentModelBindingResult.Success(SerializeToString(result.Dictionary));
5229
}
5330
}

src/NetCoreStack.Proxy/DefaultModelContentResolver.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System;
33
using System.Collections;
44
using System.Collections.Generic;
5-
using System.Linq;
65
using System.Reflection;
76

87
namespace NetCoreStack.Proxy
@@ -224,24 +223,44 @@ private void ResolveInternal(ProxyModelMetadata modelMetadata, ModelDictionaryRe
224223
}
225224

226225
// Per request parameter context resolver
227-
public ModelDictionaryResult Resolve(List<ProxyModelMetadata> parameters, object[] args)
226+
public ModelDictionaryResult Resolve(List<ProxyModelMetadata> parameters, object[] args, int parameterOffset = 0, bool ignoreModelPrefix = false)
228227
{
229228
var result = new ModelDictionaryResult(new Dictionary<string, string>(StringComparer.Ordinal),
230229
new Dictionary<string, IFormFile>(StringComparer.Ordinal));
231230

232-
for (int i = 0; i < parameters.Count; i++)
231+
for (int i = parameterOffset; i < parameters.Count; i++)
233232
{
234233
var modelMetadata = parameters[i];
235-
string prefix = string.Empty;
236-
if (modelMetadata.ContainerType == null && !string.IsNullOrEmpty(modelMetadata.PropertyName))
234+
var modelPrefix = string.Empty;
235+
if (!ignoreModelPrefix)
237236
{
238-
prefix = modelMetadata.PropertyName;
237+
if (modelMetadata.ContainerType == null && !string.IsNullOrEmpty(modelMetadata.PropertyName))
238+
{
239+
modelPrefix = modelMetadata.PropertyName;
240+
}
239241
}
240-
241-
ResolveInternal(modelMetadata, result, args[i], isTopLevelObject: true, prefix: prefix);
242+
ResolveInternal(modelMetadata, result, args[i], isTopLevelObject: true, prefix: modelPrefix);
242243
}
243244

244245
return result;
245246
}
247+
248+
public string ResolveParameter(ProxyModelMetadata modelMetadata, object value, bool isTopLevelObject, string prefix = "")
249+
{
250+
var result = new ModelDictionaryResult(new Dictionary<string, string>(StringComparer.Ordinal),
251+
new Dictionary<string, IFormFile>(StringComparer.Ordinal));
252+
253+
ResolveInternal(modelMetadata, result, value, isTopLevelObject: isTopLevelObject, prefix: prefix);
254+
255+
if(result.Dictionary.TryGetValue(modelMetadata.PropertyName, out string propValue))
256+
{
257+
return propValue;
258+
}
259+
else
260+
{
261+
throw new InvalidOperationException($"The parameter does not found in resolver dictionary! " +
262+
$"Name: \"{modelMetadata.PropertyName}\", Type: \"{modelMetadata.ModelType.Name}\"");
263+
}
264+
}
246265
}
247266
}

src/NetCoreStack.Proxy/DefaultProxyEndpointManager.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Microsoft.AspNetCore.Routing.Template;
2-
using System;
1+
using System;
32
using System.Net.Http;
43

54
namespace NetCoreStack.Proxy

src/NetCoreStack.Proxy/Extensions/ObjectExtensions.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,6 @@ namespace NetCoreStack.Proxy.Extensions
66
{
77
internal static class ObjectExtensions
88
{
9-
//public static string ToQueryString(this object obj)
10-
//{
11-
// var properties = from p in obj.GetType().GetProperties()
12-
// where p.GetValue(obj, null) != null
13-
// select p.Name + "=" + WebUtility.UrlEncode(p.GetValue(obj, null).ToString());
14-
15-
// return string.Join("&", properties.ToArray());
16-
//}
17-
189
public static IDictionary<string, object> ToDictionary(this object value)
1910
{
2011
Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);

src/NetCoreStack.Proxy/HttpDispatchProxy.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private async Task<ResponseContext> InternalInvokeAsync(MethodInfo targetMethod,
6868
responseContext = await ProxyResultExecutor.ExecuteAsync(response,
6969
requestContext,
7070
genericReturnType);
71+
7172
}
7273
catch (Exception ex)
7374
{

src/NetCoreStack.Proxy/Interfaces/IModelContentResolver.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace NetCoreStack.Proxy
44
{
55
public interface IModelContentResolver
66
{
7-
ModelDictionaryResult Resolve(List<ProxyModelMetadata> parameters, object[] args);
7+
ModelDictionaryResult Resolve(List<ProxyModelMetadata> parameters, object[] args, int parameterOffset = 0, bool ignoreModelPrefix = false);
8+
9+
string ResolveParameter(ProxyModelMetadata parameter, object value, bool isTopLevelObject, string prefix = "");
810
}
911
}

src/NetCoreStack.Proxy/Internal/DefaultProxyTypeManager.cs

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,25 @@ private IList<ProxyDescriptor> GetProxyDescriptors()
6060
foreach (var method in methods)
6161
{
6262
var proxyMethodDescriptor = new ProxyMethodDescriptor(method);
63+
bool isMultipartFormData = false;
64+
foreach (var parameter in method.GetParameters())
65+
{
66+
var modelMetadata = MetadataProvider.GetMetadataForParameter(parameter);
67+
if (modelMetadata.IsFormFile)
68+
{
69+
isMultipartFormData = true;
70+
if (parameter.CustomAttributes
71+
.Any(a => a.AttributeType.Name == "FromBodyAttribute"))
72+
{
73+
throw new ProxyException($"Parameter: \"{parameter.ParameterType.Name} as {parameter.Name}\" " +
74+
"contains IFormFile type property. " +
75+
"Remove FromBody attribute to proper model binding.");
76+
}
77+
}
78+
79+
proxyMethodDescriptor.Parameters.Add(modelMetadata);
80+
}
81+
proxyMethodDescriptor.IsMultiPartFormData = isMultipartFormData;
6382

6483
var timeoutAttr = method.GetCustomAttribute<ApiTimeoutAttribute>();
6584
if (timeoutAttr != null)
@@ -91,7 +110,7 @@ private IList<ProxyDescriptor> GetProxyDescriptors()
91110
if (routeTemplate != null)
92111
{
93112
proxyMethodDescriptor.RouteTemplate = routeTemplate;
94-
proxyMethodDescriptor.ParameterParts = new List<TemplatePart>(routeTemplate.Parameters);
113+
proxyMethodDescriptor.TemplateParts = new List<TemplatePart>(routeTemplate.Parameters);
95114

96115
proxyMethodDescriptor.TemplateKeys = routeTemplate.Segments
97116
.SelectMany(s => s.Parts.Where(p => p.IsLiteral)
@@ -104,40 +123,46 @@ private IList<ProxyDescriptor> GetProxyDescriptors()
104123
}
105124

106125
if (httpMethodAttribute is HttpGetMarkerAttribute)
126+
{
107127
proxyMethodDescriptor.HttpMethod = HttpMethod.Get;
128+
}
108129
else if (httpMethodAttribute is HttpPostMarkerAttribute)
130+
{
109131
proxyMethodDescriptor.HttpMethod = HttpMethod.Post;
132+
}
110133
else if (httpMethodAttribute is HttpPutMarkerAttribute)
134+
{
111135
proxyMethodDescriptor.HttpMethod = HttpMethod.Put;
136+
if(proxyMethodDescriptor.HasAnyTemplateParameterKey)
137+
{
138+
for (int i = 0; i < proxyMethodDescriptor.TemplateParameterKeys.Count; i++)
139+
{
140+
var key = proxyMethodDescriptor.TemplateParameterKeys[i];
141+
var templatePartParameterOrderedModel = proxyMethodDescriptor.Parameters[i];
142+
if (templatePartParameterOrderedModel == null || templatePartParameterOrderedModel.PropertyName != key)
143+
{
144+
throw new ProxyException($"Key parameter: \"{key}\" does not match on the corresponding method parameter order.");
145+
}
146+
147+
if (!templatePartParameterOrderedModel.IsSimpleType)
148+
{
149+
throw new ProxyException($"Key parameter: \"{key}\" type: \"{ templatePartParameterOrderedModel.ModelType.Name }\" " +
150+
$"must be ProxyModelMetadata.IsSimpleType to proper HTTP PUT Uri-Key (Url) model binding.");
151+
}
152+
}
153+
}
154+
}
112155
else if (httpMethodAttribute is HttpDeleteMarkerAttribute)
156+
{
113157
proxyMethodDescriptor.HttpMethod = HttpMethod.Delete;
158+
}
114159
}
115160
else
116161
{
117162
// Default GET
118163
proxyMethodDescriptor.HttpMethod = HttpMethod.Get;
119164
}
120165

121-
bool isMultipartFormData = false;
122-
foreach (var parameter in method.GetParameters())
123-
{
124-
var modelMetadata = MetadataProvider.GetMetadataForParameter(parameter);
125-
if (modelMetadata.IsFormFile)
126-
{
127-
isMultipartFormData = true;
128-
if (parameter.CustomAttributes
129-
.Any(a => a.AttributeType.Name == "FromBodyAttribute"))
130-
{
131-
throw new ProxyException($"Parameter: \"{parameter.ParameterType.Name} as {parameter.Name}\" " +
132-
"contains IFormFile type property. " +
133-
"Remove FromBody attribute to proper model binding.");
134-
}
135-
}
136-
137-
proxyMethodDescriptor.Parameters.Add(modelMetadata);
138-
}
139-
140-
proxyMethodDescriptor.IsMultiPartFormData = isMultipartFormData;
141166
descriptor.Methods.Add(method, proxyMethodDescriptor);
142167
}
143168

0 commit comments

Comments
 (0)