-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathModelManager.cs
More file actions
213 lines (161 loc) · 6.31 KB
/
Copy pathModelManager.cs
File metadata and controls
213 lines (161 loc) · 6.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
using JSONAPI.Attributes;
using JSONAPI.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace JSONAPI.Core
{
public class ModelManager : IModelManager
{
public ModelManager(IPluralizationService pluralizationService)
{
_pluralizationService = pluralizationService;
}
protected IPluralizationService _pluralizationService = null;
public IPluralizationService PluralizationService
{
get
{
return _pluralizationService;
}
}
#region Cache storage
protected Lazy<Dictionary<Type, PropertyInfo>> _idProperties
= new Lazy<Dictionary<Type,PropertyInfo>>(
() => new Dictionary<Type, PropertyInfo>()
);
protected Lazy<Dictionary<Type, Dictionary<string, PropertyInfo>>> _propertyMaps
= new Lazy<Dictionary<Type, Dictionary<string, PropertyInfo>>>(
() => new Dictionary<Type, Dictionary<string, PropertyInfo>>()
);
protected Lazy<Dictionary<Type, string>> _jsonKeysForType
= new Lazy<Dictionary<Type, string>>(
() => new Dictionary<Type, string>()
);
protected Lazy<Dictionary<Type, bool>> _isSerializedAsMany
= new Lazy<Dictionary<Type, bool>>(
() => new Dictionary<Type, bool>()
);
protected Lazy<Dictionary<Type, Type>> _getElementType
= new Lazy<Dictionary<Type, Type>>(
() => new Dictionary<Type, Type>()
);
#endregion
#region Id property determination
public PropertyInfo GetIdProperty(Type type)
{
PropertyInfo idprop = null;
var idPropCache = _idProperties.Value;
lock (idPropCache)
{
if (idPropCache.TryGetValue(type, out idprop)) return idprop;
// First, look for UseAsIdAttribute
idprop = type.GetProperties()
.Where(p => p.CustomAttributes.Any(attr => attr.AttributeType == typeof(UseAsIdAttribute)))
.FirstOrDefault();
if (idprop == null)
{
idprop = type.GetProperty("Id");
}
if (idprop == null)
throw new InvalidOperationException(String.Format("Unable to determine Id property for type {0}", type));
idPropCache.Add(type, idprop);
}
return idprop;
}
#endregion
#region Property Maps
protected IDictionary<string, PropertyInfo> GetPropertyMap(Type type)
{
Dictionary<string, PropertyInfo> propMap = null;
var propMapCache = _propertyMaps.Value;
lock (propMapCache)
{
if (propMapCache.TryGetValue(type, out propMap)) return propMap;
propMap = new Dictionary<string, PropertyInfo>();
PropertyInfo[] props = type.GetProperties();
foreach (PropertyInfo prop in props)
{
propMap[GetJsonKeyForProperty(prop)] = prop;
}
propMapCache.Add(type, propMap);
}
return propMap;
}
public PropertyInfo[] GetProperties(Type type)
{
return GetPropertyMap(type).Values.ToArray();
}
public PropertyInfo GetPropertyForJsonKey(Type type, string jsonKey)
{
PropertyInfo propInfo;
if (GetPropertyMap(type).TryGetValue(jsonKey, out propInfo)) return propInfo;
else return null; // Or, throw an exception here??
}
#endregion
public string GetJsonKeyForType(Type type)
{
string key = null;
var keyCache = _jsonKeysForType.Value;
lock (keyCache)
{
if (IsSerializedAsMany(type))
type = GetElementType(type);
if (keyCache.TryGetValue(type, out key)) return key;
var attrs = type.CustomAttributes.Where(x => x.AttributeType == typeof(Newtonsoft.Json.JsonObjectAttribute)).ToList();
string title = type.Name;
if (attrs.Any())
{
var titles = attrs.First().NamedArguments.Where(arg => arg.MemberName == "Title")
.Select(arg => arg.TypedValue.Value.ToString()).ToList();
if (titles.Any()) title = titles.First();
}
key = FormatPropertyName(PluralizationService.Pluralize(title));
keyCache.Add(type, key);
}
return key;
}
public string GetJsonKeyForProperty(PropertyInfo propInfo)
{
return FormatPropertyName(propInfo.Name);
//TODO: Respect [JsonProperty(PropertyName = "FooBar")], and probably cache the result.
}
protected static string FormatPropertyName(string propertyName)
{
string result = propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
return result;
}
public bool IsSerializedAsMany(Type type)
{
bool isMany;
var isManyCache = _isSerializedAsMany.Value;
lock (isManyCache)
{
if (isManyCache.TryGetValue(type, out isMany)) return isMany;
isMany =
type.IsArray ||
(type.GetInterfaces().Contains(typeof(System.Collections.IEnumerable)) && type.IsGenericType);
isManyCache.Add(type, isMany);
}
return isMany;
}
public Type GetElementType(Type manyType)
{
Type etype = null;
var etypeCache = _getElementType.Value;
lock (etypeCache)
{
if (etypeCache.TryGetValue(manyType, out etype)) return etype;
if (manyType.IsGenericType)
etype = manyType.GetGenericArguments()[0];
else
etype = manyType.GetElementType();
etypeCache.Add(manyType, etype);
}
return etype;
}
}
}