diff --git a/src/ServiceStack.Text/JsConfig.cs b/src/ServiceStack.Text/JsConfig.cs index e18c4c186..ef125a8e6 100644 --- a/src/ServiceStack.Text/JsConfig.cs +++ b/src/ServiceStack.Text/JsConfig.cs @@ -23,6 +23,11 @@ static JsConfig() Reset(); } + public static JsConfigScope BeginScope() + { + return new JsConfigScope(); + } + [ThreadStatic] private static bool? tsConvertObjectTypesIntoStringDictionary; private static bool? sConvertObjectTypesIntoStringDictionary; @@ -30,7 +35,10 @@ public static bool ConvertObjectTypesIntoStringDictionary { get { - return tsConvertObjectTypesIntoStringDictionary ?? sConvertObjectTypesIntoStringDictionary ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.ConvertObjectTypesIntoStringDictionary: null) + ?? tsConvertObjectTypesIntoStringDictionary + ?? sConvertObjectTypesIntoStringDictionary + ?? false; } set { @@ -46,7 +54,10 @@ public static bool TryToParsePrimitiveTypeValues { get { - return tsTryToParsePrimitiveTypeValues ?? sTryToParsePrimitiveTypeValues ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.TryToParsePrimitiveTypeValues: null) + ?? tsTryToParsePrimitiveTypeValues + ?? sTryToParsePrimitiveTypeValues + ?? false; } set { @@ -62,7 +73,10 @@ public static bool IncludeNullValues { get { - return tsIncludeNullValues ?? sIncludeNullValues ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeNullValues: null) + ?? tsIncludeNullValues + ?? sIncludeNullValues + ?? false; } set { @@ -78,7 +92,10 @@ public static bool TreatEnumAsInteger { get { - return tsTreatEnumAsInteger ?? sTreatEnumAsInteger ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.TreatEnumAsInteger: null) + ?? tsTreatEnumAsInteger + ?? sTreatEnumAsInteger + ?? false; } set { @@ -94,7 +111,10 @@ public static bool ExcludeTypeInfo { get { - return tsExcludeTypeInfo ?? sExcludeTypeInfo ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.ExcludeTypeInfo: null) + ?? tsExcludeTypeInfo + ?? sExcludeTypeInfo + ?? false; } set { @@ -110,7 +130,10 @@ public static bool IncludeTypeInfo { get { - return tsForceTypeInfo ?? sForceTypeInfo ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.IncludeTypeInfo: null) + ?? tsForceTypeInfo + ?? sForceTypeInfo + ?? false; } set { @@ -126,7 +149,10 @@ public static string TypeAttr { get { - return tsTypeAttr ?? sTypeAttr ?? JsWriter.TypeAttr; + return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeAttr: null) + ?? tsTypeAttr + ?? sTypeAttr + ?? JsWriter.TypeAttr; } set { @@ -145,7 +171,10 @@ internal static string JsonTypeAttrInObject { get { - return tsJsonTypeAttrInObject ?? sJsonTypeAttrInObject ?? defaultJsonTypeAttrInObject; + return (JsConfigScope.Current != null ? JsConfigScope.Current.JsonTypeAttrInObject: null) + ?? tsJsonTypeAttrInObject + ?? sJsonTypeAttrInObject + ?? defaultJsonTypeAttrInObject; } set { @@ -162,7 +191,10 @@ internal static string JsvTypeAttrInObject { get { - return tsJsvTypeAttrInObject ?? sJsvTypeAttrInObject ?? defaultJsvTypeAttrInObject; + return (JsConfigScope.Current != null ? JsConfigScope.Current.JsvTypeAttrInObject: null) + ?? tsJsvTypeAttrInObject + ?? sJsvTypeAttrInObject + ?? defaultJsvTypeAttrInObject; } set { @@ -178,7 +210,10 @@ public static Func TypeWriter { get { - return tsTypeWriter ?? sTypeWriter ?? AssemblyUtils.WriteType; + return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeWriter: null) + ?? tsTypeWriter + ?? sTypeWriter + ?? AssemblyUtils.WriteType; } set { @@ -194,7 +229,10 @@ public static Func TypeFinder { get { - return tsTypeFinder ?? sTypeFinder ?? AssemblyUtils.FindType; + return (JsConfigScope.Current != null ? JsConfigScope.Current.TypeFinder: null) + ?? tsTypeFinder + ?? sTypeFinder + ?? AssemblyUtils.FindType; } set { @@ -210,7 +248,10 @@ public static JsonDateHandler DateHandler { get { - return tsDateHandler ?? sDateHandler ?? JsonDateHandler.TimestampOffset; + return (JsConfigScope.Current != null ? JsConfigScope.Current.DateHandler: null) + ?? tsDateHandler + ?? sDateHandler + ?? JsonDateHandler.TimestampOffset; } set { @@ -238,7 +279,10 @@ public static bool EmitCamelCaseNames // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { - return tsEmitCamelCaseNames ?? sEmitCamelCaseNames ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.EmitCamelCaseNames: null) + ?? tsEmitCamelCaseNames + ?? sEmitCamelCaseNames + ?? false; } set { @@ -259,7 +303,10 @@ public static bool EmitLowercaseUnderscoreNames // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { - return tsEmitLowercaseUnderscoreNames ?? sEmitLowercaseUnderscoreNames ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.EmitLowercaseUnderscoreNames: null) + ?? tsEmitLowercaseUnderscoreNames + ?? sEmitLowercaseUnderscoreNames + ?? false; } set { @@ -304,7 +351,10 @@ public static bool ThrowOnDeserializationError // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { - return tsThrowOnDeserializationError ?? sThrowOnDeserializationError ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.ThrowOnDeserializationError: null) + ?? tsThrowOnDeserializationError + ?? sThrowOnDeserializationError + ?? false; } set { @@ -324,7 +374,10 @@ public static bool AlwaysUseUtc // obeying the use of ThreadStatic, but allowing for setting JsConfig once as is the normal case get { - return tsAlwaysUseUtc ?? sAlwaysUseUtc ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.AlwaysUseUtc: null) + ?? tsAlwaysUseUtc + ?? sAlwaysUseUtc + ?? false; } set { @@ -347,7 +400,10 @@ public static bool PreferInterfaces { get { - return tsPreferInterfaces ?? sPreferInterfaces ?? false; + return (JsConfigScope.Current != null ? JsConfigScope.Current.PreferInterfaces: null) + ?? tsPreferInterfaces + ?? sPreferInterfaces + ?? false; } set { diff --git a/src/ServiceStack.Text/JsConfigScope.cs b/src/ServiceStack.Text/JsConfigScope.cs new file mode 100644 index 000000000..770d7ece1 --- /dev/null +++ b/src/ServiceStack.Text/JsConfigScope.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Diagnostics; + +namespace ServiceStack.Text +{ + public sealed class JsConfigScope : IDisposable + { + bool disposed; + JsConfigScope parent; + + [ThreadStatic] + private static JsConfigScope head; + + internal JsConfigScope() + { + Thread.BeginThreadAffinity(); + parent = head; + head = this; + } + + internal static JsConfigScope Current + { + get + { + return head; + } + } + + public static void DisposeCurrent() + { + if (head != null) + { + head.Dispose(); + } + } + + public void Dispose() + { + if (!disposed) + { + disposed = true; + + Debug.Assert(this == head, "Disposed out of order."); + + head = parent; + + Thread.EndThreadAffinity(); + } + } + + public bool? ConvertObjectTypesIntoStringDictionary { get; set; } + public bool? TryToParsePrimitiveTypeValues { get; set; } + public bool? IncludeNullValues { get; set; } + public bool? TreatEnumAsInteger { get; set; } + public bool? ExcludeTypeInfo { get; set; } + public bool? IncludeTypeInfo { get; set; } + public string TypeAttr { get; set; } + internal string JsonTypeAttrInObject { get; set; } + internal string JsvTypeAttrInObject { get; set; } + public Func TypeWriter { get; set; } + public Func TypeFinder { get; set; } + public JsonDateHandler? DateHandler { get; set; } + public bool? EmitCamelCaseNames { get; set; } + public bool? EmitLowercaseUnderscoreNames { get; set; } + public bool? ThrowOnDeserializationError { get; set; } + public bool? AlwaysUseUtc { get; set; } + public bool? PreferInterfaces { get; set; } + } +} diff --git a/src/ServiceStack.Text/ServiceStack.Text.csproj b/src/ServiceStack.Text/ServiceStack.Text.csproj index 33dce8553..d1b95a193 100644 --- a/src/ServiceStack.Text/ServiceStack.Text.csproj +++ b/src/ServiceStack.Text/ServiceStack.Text.csproj @@ -185,6 +185,7 @@ Code + Code