Skip to content

Commit e270f60

Browse files
committed
content model binder, complex type, collection resolver
1 parent 54e9d94 commit e270f60

40 files changed

+806
-525
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using Microsoft.AspNetCore.Http;
2+
using Newtonsoft.Json;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Net.Http;
6+
using System.Net.Http.Headers;
7+
using System.Text;
8+
9+
namespace NetCoreStack.Proxy
10+
{
11+
public abstract class BodyContentBinder : ContentModelBinder
12+
{
13+
protected virtual void AddFile(string key, MultipartFormDataContent multipartFormDataContent, IFormFile formFile)
14+
{
15+
using (var ms = new MemoryStream())
16+
{
17+
formFile.CopyTo(ms);
18+
var fileContent = new ByteArrayContent(ms.ToArray());
19+
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(formFile.ContentType);
20+
fileContent.Headers.ContentDisposition = ContentDispositionHeaderValue.Parse(formFile.ContentDisposition);
21+
multipartFormDataContent.Add(fileContent, key, formFile.FileName);
22+
}
23+
}
24+
25+
protected virtual byte[] Serialize(object value)
26+
{
27+
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(value));
28+
}
29+
30+
protected virtual StringContent SerializeToString(object value)
31+
{
32+
return new StringContent(JsonConvert.SerializeObject(value), Encoding.UTF8, "application/json");
33+
}
34+
35+
protected virtual MultipartFormDataContent GetMultipartFormDataContent(ResolvedContentResult contentResult)
36+
{
37+
MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent();
38+
foreach (KeyValuePair<string, string> entry in contentResult.Dictionary)
39+
{
40+
multipartFormDataContent.Add(new StringContent(entry.Value), entry.Key);
41+
}
42+
43+
if (contentResult.Files != null)
44+
{
45+
foreach (KeyValuePair<string, IFormFile> entry in contentResult.Files)
46+
{
47+
AddFile(entry.Key, multipartFormDataContent, entry.Value);
48+
}
49+
}
50+
51+
return multipartFormDataContent;
52+
}
53+
54+
}
55+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Net.Http;
3+
4+
namespace NetCoreStack.Proxy
5+
{
6+
public static class ContentBinderFactory
7+
{
8+
static ContentBinderFactory()
9+
{
10+
11+
}
12+
13+
public static IContentModelBinder GetContentModelBinder(HttpMethod httpMethod)
14+
{
15+
if (httpMethod == HttpMethod.Get)
16+
{
17+
return new HttpGetContentBinder();
18+
}
19+
20+
if (httpMethod == HttpMethod.Post)
21+
{
22+
return new HttpPostContentBinder();
23+
}
24+
25+
if (httpMethod == HttpMethod.Put)
26+
{
27+
return new HttpPutContentBinder();
28+
}
29+
30+
if (httpMethod == HttpMethod.Delete)
31+
{
32+
return new HttpDeleteContentBinder();
33+
}
34+
35+
throw new NotImplementedException($"{httpMethod.Method} is not supported or not implemented yet.");
36+
}
37+
}
38+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace NetCoreStack.Proxy
2+
{
3+
public class HttpDeleteContentBinder : ContentModelBinder
4+
{
5+
public override void BindContent(ContentModelBindingContext bindingContext)
6+
{
7+
}
8+
}
9+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using NetCoreStack.Proxy.Extensions;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Net.Http;
6+
7+
namespace NetCoreStack.Proxy
8+
{
9+
public class HttpGetContentBinder : ContentModelBinder
10+
{
11+
HttpMethod HttpMethod => HttpMethod.Get;
12+
13+
public override void BindContent(ContentModelBindingContext bindingContext)
14+
{
15+
ResolvedContentResult result = bindingContext.GetResolvedContentResult(HttpMethod);
16+
List<string> keys = result.Dictionary.Keys.ToList();
17+
EnsureTemplate(bindingContext.MethodMarkerTemplate, bindingContext.Args, bindingContext.UriDefinition, result.Dictionary, keys);
18+
19+
bindingContext.TryUpdateUri(result.Dictionary);
20+
}
21+
}
22+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using NetCoreStack.Proxy.Extensions;
2+
using System.Net.Http;
3+
4+
namespace NetCoreStack.Proxy
5+
{
6+
public class HttpPostContentBinder : BodyContentBinder
7+
{
8+
HttpMethod HttpMethod => HttpMethod.Post;
9+
10+
public override void BindContent(ContentModelBindingContext bindingContext)
11+
{
12+
var isMultiPartFormData = bindingContext.IsMultiPartFormData;
13+
if (isMultiPartFormData)
14+
{
15+
ResolvedContentResult result = bindingContext.GetResolvedContentResult(HttpMethod);
16+
var content = GetMultipartFormDataContent(result);
17+
bindingContext.ContentResult = ContentModelBindingResult.Success(content);
18+
return;
19+
}
20+
21+
if (bindingContext.ArgsLength == 1)
22+
{
23+
bindingContext.ContentResult = ContentModelBindingResult.Success(SerializeToString(bindingContext.Args[0]));
24+
return;
25+
// request.Content = SerializeToString(argsDic.First().Value);
26+
}
27+
28+
bindingContext.ContentResult = ContentModelBindingResult.Success(SerializeToString(bindingContext.Args));
29+
// request.Content = SerializeToString(argsDic);
30+
}
31+
}
32+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using NetCoreStack.Proxy.Extensions;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net.Http;
5+
using NetCoreStack.Contracts;
6+
7+
namespace NetCoreStack.Proxy
8+
{
9+
public class HttpPutContentBinder : BodyContentBinder
10+
{
11+
HttpMethod HttpMethod => HttpMethod.Put;
12+
13+
public override void BindContent(ContentModelBindingContext bindingContext)
14+
{
15+
ResolvedContentResult result = bindingContext.GetResolvedContentResult(HttpMethod);
16+
List<string> keys = result.Dictionary.Keys.ToList();
17+
EnsureTemplate(bindingContext.MethodMarkerTemplate, bindingContext.Args, bindingContext.UriDefinition, result.Dictionary, keys);
18+
if (bindingContext.ArgsLength == 1)
19+
{
20+
bindingContext.ContentResult = ContentModelBindingResult.Success(SerializeToString(bindingContext.Args[0]));
21+
return;
22+
// request.Content = SerializeToString(argsDic.First().Value);
23+
}
24+
else if (bindingContext.ArgsLength == 2)
25+
{
26+
var firstParameter = result.Dictionary[keys[0]];
27+
var secondParameter = result.Dictionary[keys[1]];
28+
29+
// PUT Request first parameter should be Id or Key
30+
if (firstParameter.GetType().IsPrimitive())
31+
{
32+
bindingContext.UriBuilder.Query += string.Format("&{0}={1}", keys[0], firstParameter);
33+
}
34+
35+
// request.RequestUri = uriBuilder.Uri;
36+
// request.Content = SerializeToString(secondParameter);
37+
bindingContext.ContentResult = ContentModelBindingResult.Success(SerializeToString(secondParameter));
38+
return;
39+
}
40+
}
41+
}
42+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace NetCoreStack.Proxy
2+
{
3+
public class DefaultContentModelBinder : ContentModelBinder
4+
{
5+
public override void BindContent(ContentModelBindingContext bindingContext)
6+
{
7+
8+
}
9+
}
10+
}

src/NetCoreStack.Proxy/DefaultModelContentResolver.cs

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,36 @@ private void TrySetValue(string prefix, ProxyModelMetadata modelMetadata, Dictio
3939

4040
if (modelMetadata.IsSimpleType)
4141
{
42-
if (modelMetadata.PropertyInfo != null)
43-
{
44-
dictionary.Add(key, Convert.ToString(value));
45-
return;
46-
}
42+
dictionary.Add(key, Convert.ToString(value));
43+
return;
4744
}
4845

4946
if (modelMetadata.IsEnumerableType)
5047
{
51-
if (modelMetadata.IsElementTypeSimple)
48+
if (modelMetadata.ElementType.IsSimpleType)
5249
{
5350
SetSimpleEnumerable(key, dictionary, value);
5451
}
5552
else
5653
{
57-
if (TypeDescriptor.GetConverter(value.GetType()).CanConvertTo(typeof(string)))
54+
var count = modelMetadata.ElementType.Properties.Count;
55+
var elementProperties = modelMetadata.ElementType.Properties;
56+
for (int i = 0; i < count; i++)
5857
{
59-
SetSimpleEnumerable(key, dictionary, value);
58+
var elementModelMetadata = elementProperties[i];
59+
var propertyInfo = elementModelMetadata.PropertyInfo;
60+
var values = value as IEnumerable;
61+
if (values != null)
62+
{
63+
var index = 0;
64+
foreach (var v in values)
65+
{
66+
var propKey = $"{key}[{index}]";
67+
var propValue = propertyInfo?.GetValue(v);
68+
ResolveInternal(elementModelMetadata, dictionary, propValue, propKey);
69+
index++;
70+
}
71+
}
6072
}
6173
}
6274
}
@@ -89,10 +101,13 @@ private void ResolveInternal(ProxyModelMetadata modelMetadata, Dictionary<string
89101
}
90102
}
91103

92-
var v = metadata.PropertyInfo.GetValue(value);
93-
if (v != null)
104+
if (value != null)
94105
{
95-
ResolveInternal(metadata, dictionary, v, parent);
106+
var v = metadata.PropertyInfo.GetValue(value);
107+
if (v != null)
108+
{
109+
ResolveInternal(metadata, dictionary, v, parent);
110+
}
96111
}
97112
}
98113
else
@@ -103,8 +118,8 @@ private void ResolveInternal(ProxyModelMetadata modelMetadata, Dictionary<string
103118
}
104119

105120
// Per request parameter context resolver
106-
public ResolvedContentResult Resolve(List<ProxyModelMetadata> parameters,
107-
HttpMethod httpMethod,
121+
public ResolvedContentResult Resolve(HttpMethod httpMethod,
122+
List<ProxyModelMetadata> parameters,
108123
bool isMultiPartFormData,
109124
object[] args)
110125
{
@@ -117,30 +132,6 @@ public ResolvedContentResult Resolve(List<ProxyModelMetadata> parameters,
117132
ResolveInternal(modelMetadata, dictionary, args[i]);
118133
}
119134

120-
if (httpMethod == HttpMethod.Get)
121-
{
122-
// Ref type parameter resolver
123-
if (parameters.Count == 1 && parameters[0].IsReferenceType)
124-
{
125-
var modelMetadata = MetadataProvider.GetMetadataForType(args[0].GetType());
126-
127-
var obj = args[0].ToDictionary();
128-
129-
// TODO Gencebay
130-
// values.Merge(obj, true);
131-
// return values;
132-
}
133-
134-
if (parameters.Count > 1 && parameters.Any(x => x.IsReferenceType))
135-
{
136-
throw new ArgumentOutOfRangeException($"Methods marked with HTTP GET can take only one reference type parameter at the same time.");
137-
}
138-
}
139-
140-
// TODO Gencebay
141-
// values.MergeArgs(args, parameters, isMultiPartFormData);
142-
// return values;
143-
144135
return new ResolvedContentResult(dictionary);
145136
}
146137
}

0 commit comments

Comments
 (0)