Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 9efca8b

Browse files
committed
implement more of .NET Standard 1.3 API
1 parent d7eb8d1 commit 9efca8b

File tree

1 file changed

+275
-8
lines changed

1 file changed

+275
-8
lines changed

src/ServiceStack.Text/PclExport.NetStandard.cs

Lines changed: 275 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
using ServiceStack.Text.Json;
1313
using System.Globalization;
1414
using System.Reflection.Emit;
15+
1516
#if NETSTANDARD1_3
1617
using System.Collections.Specialized;
18+
using System.Net;
19+
using System.Linq.Expressions;
20+
using System.Runtime.Serialization;
1721
#endif
1822

1923
namespace ServiceStack
@@ -74,7 +78,7 @@ public override bool FileExists(string filePath)
7478
return File.Exists(filePath);
7579
}
7680

77-
public override bool DirectoryExists(string dirPath)
81+
public override bool DirectoryExists(string dirPath)
7882
{
7983
return Directory.Exists(dirPath);
8084
}
@@ -112,23 +116,22 @@ public override string MapAbsolutePath(string relativePath, string appendPartial
112116

113117
// Escape the assembly bin directory to the hostname directory
114118
var hostDirectoryPath = appendPartialPathModifier != null
115-
? assemblyDirectoryPath + appendPartialPathModifier
116-
: assemblyDirectoryPath;
119+
? assemblyDirectoryPath + appendPartialPathModifier
120+
: assemblyDirectoryPath;
117121

118122
return Path.GetFullPath(relativePath.Replace("~", hostDirectoryPath));
119123
}
120124
return relativePath;
121125
}
126+
122127
#elif NETSTANDARD1_1
123128
public string BinPath = null;
124129

125130
public override string MapAbsolutePath(string relativePath, string appendPartialPathModifier)
126131
{
127132
if (BinPath == null)
128133
{
129-
var dll = typeof(PclExport).GetAssembly();
130-
var pi = dll.GetType().GetProperty("CodeBase");
131-
var codeBase = pi?.GetProperty(dll).ToString();
134+
var codeBase = GetAssemblyCodeBase(typeof(PclExport).GetTypeInfo().Assembly);
132135
if (codeBase == null)
133136
throw new Exception("NetStandardPclExport.BinPath must be initialized");
134137

@@ -140,32 +143,256 @@ public override string MapAbsolutePath(string relativePath, string appendPartial
140143
: relativePath;
141144
}
142145
#endif
143-
144146
public static PclExport Configure()
145147
{
146148
Configure(Provider);
147149
return Provider;
148150
}
149151

152+
public override string GetEnvironmentVariable(string name)
153+
{
154+
#if NETSTANDARD1_3
155+
return Environment.GetEnvironmentVariable(name);
156+
#else
157+
return null;
158+
#endif
159+
}
160+
150161
public override void WriteLine(string line)
151162
{
163+
#if NETSTANDARD1_3
164+
Console.WriteLine(line);
165+
#else
152166
System.Diagnostics.Debug.WriteLine(line);
167+
#endif
153168
}
154169

155170
public override void WriteLine(string format, params object[] args)
156171
{
172+
#if NETSTANDARD1_3
173+
Console.WriteLine(format, args);
174+
#else
157175
System.Diagnostics.Debug.WriteLine(format, args);
176+
#endif
177+
}
178+
179+
#if NETSTANDARD1_3
180+
public override void AddCompression(WebRequest webReq)
181+
{
182+
var httpReq = (HttpWebRequest)webReq;
183+
//TODO: Restore when AutomaticDecompression added to WebRequest
184+
//httpReq.Headers[HttpRequestHeader.AcceptEncoding] = "gzip,deflate";
185+
//httpReq.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
158186
}
159187

188+
public override void AddHeader(WebRequest webReq, string name, string value)
189+
{
190+
webReq.Headers[name] = value;
191+
}
192+
#endif
193+
160194
public override Assembly[] GetAllAssemblies()
161195
{
162196
return new Assembly[0];
163197
}
164198

165199
public override string GetAssemblyCodeBase(Assembly assembly)
166200
{
167-
return assembly.GetName().FullName;
201+
var dll = typeof(PclExport).GetAssembly();
202+
var pi = dll.GetType().GetProperty("CodeBase");
203+
var codeBase = pi?.GetProperty(dll).ToString();
204+
return codeBase;
205+
}
206+
207+
#if NETSTANDARD1_3
208+
public override string GetAssemblyPath(Type source)
209+
{
210+
var codeBase = GetAssemblyCodeBase(source.GetTypeInfo().Assembly);
211+
if (codeBase == null)
212+
return null;
213+
214+
var assemblyUri = new Uri(codeBase);
215+
return assemblyUri.LocalPath;
216+
}
217+
218+
public override string GetAsciiString(byte[] bytes, int index, int count)
219+
{
220+
return System.Text.Encoding.ASCII.GetString(bytes, index, count);
221+
}
222+
223+
public override byte[] GetAsciiBytes(string str)
224+
{
225+
return System.Text.Encoding.ASCII.GetBytes(str);
226+
}
227+
#endif
228+
229+
public override bool InSameAssembly(Type t1, Type t2)
230+
{
231+
return t1.GetAssembly() == t2.GetAssembly();
232+
}
233+
234+
public override Type GetGenericCollectionType(Type type)
235+
{
236+
return type.GetTypeInfo().ImplementedInterfaces.FirstOrDefault(t =>
237+
t.IsGenericType()
238+
&& t.GetGenericTypeDefinition() == typeof(ICollection<>));
239+
}
240+
241+
#if NETSTANDARD1_3
242+
243+
public override PropertySetterDelegate GetPropertySetterFn(PropertyInfo propertyInfo)
244+
{
245+
var propertySetMethod = propertyInfo.SetMethod();
246+
if (propertySetMethod == null) return null;
247+
248+
if (!SupportsExpression)
249+
{
250+
return (o, convertedValue) =>
251+
propertySetMethod.Invoke(o, new[] { convertedValue });
252+
}
253+
254+
try
255+
{
256+
var instance = Expression.Parameter(typeof(object), "i");
257+
var argument = Expression.Parameter(typeof(object), "a");
258+
259+
var instanceParam = Expression.Convert(instance, propertyInfo.ReflectedType());
260+
var valueParam = Expression.Convert(argument, propertyInfo.PropertyType);
261+
262+
var setterCall = Expression.Call(instanceParam, propertySetMethod, valueParam);
263+
264+
return Expression.Lambda<PropertySetterDelegate>(setterCall, instance, argument).Compile();
265+
}
266+
catch //fallback for Android
267+
{
268+
return (o, convertedValue) =>
269+
propertySetMethod.Invoke(o, new[] { convertedValue });
270+
}
271+
}
272+
273+
public override PropertyGetterDelegate GetPropertyGetterFn(PropertyInfo propertyInfo)
274+
{
275+
if (!SupportsExpression)
276+
return base.GetPropertyGetterFn(propertyInfo);
277+
278+
var getMethodInfo = propertyInfo.GetMethodInfo();
279+
if (getMethodInfo == null) return null;
280+
try
281+
{
282+
var oInstanceParam = Expression.Parameter(typeof(object), "oInstanceParam");
283+
var instanceParam = Expression.Convert(oInstanceParam, propertyInfo.ReflectedType()); //propertyInfo.DeclaringType doesn't work on Proxy types
284+
285+
var exprCallPropertyGetFn = Expression.Call(instanceParam, getMethodInfo);
286+
var oExprCallPropertyGetFn = Expression.Convert(exprCallPropertyGetFn, typeof(object));
287+
288+
var propertyGetFn = Expression.Lambda<PropertyGetterDelegate>
289+
(
290+
oExprCallPropertyGetFn,
291+
oInstanceParam
292+
).Compile();
293+
294+
return propertyGetFn;
295+
296+
}
297+
catch (Exception ex)
298+
{
299+
Tracer.Instance.WriteError(ex);
300+
throw;
301+
}
302+
}
303+
304+
private static readonly MethodInfo setFieldMethod =
305+
typeof(NetStandardPclExport).GetStaticMethod("SetField");
306+
307+
internal static void SetField<TValue>(ref TValue field, TValue newValue)
308+
{
309+
field = newValue;
310+
}
311+
312+
public override PropertySetterDelegate GetFieldSetterFn(FieldInfo fieldInfo)
313+
{
314+
if (!SupportsExpression)
315+
return base.GetFieldSetterFn(fieldInfo);
316+
317+
var fieldDeclaringType = fieldInfo.DeclaringType;
318+
319+
var sourceParameter = Expression.Parameter(typeof(object), "source");
320+
var valueParameter = Expression.Parameter(typeof(object), "value");
321+
322+
var sourceExpression = this.GetCastOrConvertExpression(sourceParameter, fieldDeclaringType);
323+
324+
var fieldExpression = Expression.Field(sourceExpression, fieldInfo);
325+
326+
var valueExpression = this.GetCastOrConvertExpression(valueParameter, fieldExpression.Type);
327+
328+
var genericSetFieldMethodInfo = setFieldMethod.MakeGenericMethod(fieldExpression.Type);
329+
330+
var setFieldMethodCallExpression = Expression.Call(
331+
null, genericSetFieldMethodInfo, fieldExpression, valueExpression);
332+
333+
var setterFn = Expression.Lambda<PropertySetterDelegate>(
334+
setFieldMethodCallExpression, sourceParameter, valueParameter).Compile();
335+
336+
return setterFn;
337+
}
338+
339+
public override PropertyGetterDelegate GetFieldGetterFn(FieldInfo fieldInfo)
340+
{
341+
if (!SupportsExpression)
342+
return base.GetFieldGetterFn(fieldInfo);
343+
344+
try
345+
{
346+
var fieldDeclaringType = fieldInfo.DeclaringType;
347+
348+
var oInstanceParam = Expression.Parameter(typeof(object), "source");
349+
var instanceParam = this.GetCastOrConvertExpression(oInstanceParam, fieldDeclaringType);
350+
351+
var exprCallFieldGetFn = Expression.Field(instanceParam, fieldInfo);
352+
//var oExprCallFieldGetFn = this.GetCastOrConvertExpression(exprCallFieldGetFn, typeof(object));
353+
var oExprCallFieldGetFn = Expression.Convert(exprCallFieldGetFn, typeof(object));
354+
355+
var fieldGetterFn = Expression.Lambda<PropertyGetterDelegate>
356+
(
357+
oExprCallFieldGetFn,
358+
oInstanceParam
359+
)
360+
.Compile();
361+
362+
return fieldGetterFn;
363+
}
364+
catch (Exception ex)
365+
{
366+
Tracer.Instance.WriteError(ex);
367+
throw;
368+
}
369+
}
370+
371+
private Expression GetCastOrConvertExpression(Expression expression, Type targetType)
372+
{
373+
Expression result;
374+
var expressionType = expression.Type;
375+
376+
if (targetType.IsAssignableFromType(expressionType))
377+
{
378+
result = expression;
379+
}
380+
else
381+
{
382+
// Check if we can use the as operator for casting or if we must use the convert method
383+
if (targetType.IsValueType() && !targetType.IsNullableType())
384+
{
385+
result = Expression.Convert(expression, targetType);
386+
}
387+
else
388+
{
389+
result = Expression.TypeAs(expression, targetType);
390+
}
391+
}
392+
393+
return result;
168394
}
395+
#endif
169396

170397
public override string ToXsdDateTimeString(DateTime dateTime)
171398
{
@@ -233,6 +460,46 @@ public override ParseStringDelegate GetJsReaderParseMethod<TSerializer>(Type typ
233460
return null;
234461
}
235462

463+
#if NETSTANDARD1_3
464+
public override void InitHttpWebRequest(HttpWebRequest httpReq,
465+
long? contentLength = null, bool allowAutoRedirect = true, bool keepAlive = true)
466+
{
467+
httpReq.Headers[HttpRequestHeader.UserAgent] = Env.ServerUserAgent;
468+
//httpReq.AllowAutoRedirect = allowAutoRedirect;
469+
//httpReq.KeepAlive = keepAlive;
470+
471+
if (contentLength != null)
472+
{
473+
httpReq.Headers[HttpRequestHeader.ContentLength] = contentLength.Value.ToString();
474+
}
475+
}
476+
477+
public override void Config(HttpWebRequest req,
478+
bool? allowAutoRedirect = null,
479+
TimeSpan? timeout = null,
480+
TimeSpan? readWriteTimeout = null,
481+
string userAgent = null,
482+
bool? preAuthenticate = null)
483+
{
484+
//req.MaximumResponseHeadersLength = int.MaxValue; //throws "The message length limit was exceeded" exception
485+
//if (allowAutoRedirect.HasValue) req.AllowAutoRedirect = allowAutoRedirect.Value;
486+
//if (readWriteTimeout.HasValue) req.ReadWriteTimeout = (int)readWriteTimeout.Value.TotalMilliseconds;
487+
//if (timeout.HasValue) req.Timeout = (int)timeout.Value.TotalMilliseconds;
488+
if (userAgent != null) req.Headers[HttpRequestHeader.UserAgent] = userAgent;
489+
//if (preAuthenticate.HasValue) req.PreAuthenticate = preAuthenticate.Value;
490+
}
491+
492+
public override string GetStackTrace()
493+
{
494+
return Environment.StackTrace;
495+
}
496+
#endif
497+
498+
public override void CloseStream(Stream stream)
499+
{
500+
stream.Close();
501+
}
502+
236503
public static void InitForAot()
237504
{
238505
}

0 commit comments

Comments
 (0)