Skip to content

Commit 4ffc4f0

Browse files
Improve ajax deserialization performance at BeforeInvoke. (#960)
* Improve ajax deserialization performance at BeforeInvoke. * Revert changes in GxCollections.cs. Static variables must be defined in generated code. * Enhance the performance of getFromJSONObjectOrderIterator, particularly during the deserialization of SDT collections. * Maintain compatibility with SDTs generated without the TypeInfo method. * Remove GXCompatibilityTypeInfo class. Enhance the performance of BC dirties handling. Avoid performing 'ToLower' operations on 'GxUpload' attribute searches and instead utilize a case-insensitive dictionary
1 parent ec9cdd0 commit 4ffc4f0

File tree

5 files changed

+471
-37
lines changed

5 files changed

+471
-37
lines changed

dotnet/src/dotnetframework/GxClasses/Core/Web/HttpAjaxContext.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public void ClearParmsMetadata()
8585

8686
public bool isInputParm(string key)
8787
{
88-
return inParmsMetadataHash.Contains(key);
88+
return (inParmsMetadataHash!=null && inParmsMetadataHash.Contains(key));
8989
}
9090

9191
public void Clear()
@@ -105,7 +105,7 @@ public bool isParmModified(string fieldName, object value)
105105
IGxJSONSerializable jsonValue = value as IGxJSONSerializable;
106106
if (jsonValue!=null)
107107
{
108-
if (!inParmsHashValue.ContainsKey(fieldName))
108+
if (inParmsHashValue!=null && !inParmsHashValue.ContainsKey(fieldName))
109109
return true;
110110
return GXUtil.GetHash(jsonValue.ToJSonString()) != inParmsHashValue[fieldName];
111111
}
@@ -346,7 +346,7 @@ public void ajax_rsp_assign_sdt_attri(String CmpContext, bool IsMasterPage, Stri
346346
try
347347
{
348348
JObject obj = GetGxObject(AttValues, CmpContext, IsMasterPage);
349-
if (obj != null && (DynAjaxEventContext.isParmModified(AttName, SdtObj) || !isUndefinedOutParam( AttName, SdtObj)))
349+
if (obj != null && (!isUndefinedOutParam(AttName, SdtObj) || DynAjaxEventContext.isParmModified(AttName, SdtObj)))
350350
{
351351
IGxJSONAble SdtObjJson = SdtObj as IGxJSONAble;
352352
if (SdtObjJson != null)

dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace GeneXus.Utils
1919
using System.Xml.Serialization;
2020
using GeneXus.Application;
2121
using GeneXus.Configuration;
22+
using GeneXus.Data;
2223
using GeneXus.Http;
2324
using GeneXus.Metadata;
2425
using GeneXus.XML;
@@ -1044,8 +1045,8 @@ public string Name
10441045
public class GxUserType : IGxXMLSerializable, ICloneable, IGxJSONAble, IGxJSONSerializable, IGXAssigned
10451046
{
10461047
static readonly IGXLogger log = GXLoggerFactory.GetLogger<GxUserType>();
1047-
protected GXProperties dirties = new GXProperties();
1048-
1048+
protected ConcurrentDictionary<string,byte> dirties = new ConcurrentDictionary<string, byte>(StringComparer.OrdinalIgnoreCase);
1049+
private const string PROPERTY_PREFIX = "gxtpr_";
10491050
static object setupChannelObject = null;
10501051
static bool setupChannelInitialized;
10511052
[XmlIgnore]
@@ -1103,11 +1104,11 @@ public GxUserType()
11031104

11041105
public virtual void SetDirty(string fieldName)
11051106
{
1106-
dirties[fieldName.ToLower()] = "true";
1107+
dirties[fieldName] = 1;
11071108
}
11081109
public virtual bool IsDirty(string fieldName)
11091110
{
1110-
if (dirties.ContainsKey(fieldName.ToLower()))
1111+
if (dirties.ContainsKey(fieldName))
11111112
return true;
11121113
return false;
11131114
}
@@ -1605,24 +1606,27 @@ public Object GetJSONObject()
16051606

16061607
private ICollection getFromJSONObjectOrderIterator(ICollection it)
16071608
{
1608-
List<string> v = new List<string>();
1609+
if (GxUploadAttrs.IsEmpty && !typeof(GxSilentTrnSdt).IsAssignableFrom(this.GetType()))
1610+
{
1611+
return it;
1612+
}
1613+
List<string> _JsonObjectOrderIterator = new List<string>();
1614+
16091615
List<string> vAtEnd = new List<string>();
16101616
foreach (string name in it)
16111617
{
1612-
string map = JsonMap(name);
1613-
PropertyInfo objProperty = GetTypeProperty("gxtpr_" + (!string.IsNullOrEmpty(map) ? map : name).ToLower());
1614-
if (name.EndsWith("_N") || objProperty != null && IsGxUploadAttribute(objProperty))
1618+
if (name.EndsWith("_N") || IsGxUploadAttribute(name))
16151619
{
16161620
vAtEnd.Add(name);
16171621
}
16181622
else
16191623
{
1620-
v.Add(name);//keep the order of attributes that do not end with _N.
1624+
_JsonObjectOrderIterator.Add(name);//keep the order of attributes that do not end with _N.
16211625
}
16221626
}
16231627
if (vAtEnd.Count > 0)
1624-
v.AddRange(vAtEnd);
1625-
return v;
1628+
_JsonObjectOrderIterator.AddRange(vAtEnd);
1629+
return _JsonObjectOrderIterator;
16261630
}
16271631

16281632
public void FromJSONObject(dynamic obj)
@@ -1635,9 +1639,7 @@ public void FromJSONObject(dynamic obj)
16351639
foreach (string name in jsonIterator)
16361640
{
16371641
object currObj = jobj[name];
1638-
string map = JsonMap(name);
1639-
PropertyInfo objProperty = GetTypeProperty("gxtpr_" + (map != null ? map : name).ToLower());
1640-
1642+
PropertyInfo objProperty = GetTypeProperty(JsonNameToInternalName(name));
16411643
if (objProperty != null)
16421644
{
16431645
if (!JSONHelper.IsJsonNull(currObj))
@@ -1897,32 +1899,51 @@ private bool TryConvertValueToProperty(object Value, PropertyInfo property, out
18971899
return success;
18981900
}
18991901

1900-
[System.Diagnostics.CodeAnalysis.SuppressMessage("GxFxCopRules", "CR1000:EnforceThreadSafeType")]
1901-
private Dictionary<string, bool> gxuploadAttrs = new Dictionary<string, bool>();
1902-
private bool IsGxUploadAttribute(PropertyInfo property)
1902+
private GXTypeInfo _compatibilityGxuploadAttrs = null;
1903+
private bool IsGxUploadAttribute(string jsonPropertyName)
19031904
{
1904-
string key = property.Name;
1905-
if (!gxuploadAttrs.ContainsKey(key))
1906-
{
1907-
bool hasAtt = property.IsDefined(typeof(GxUpload), false);
1908-
gxuploadAttrs.Add(key, hasAtt);
1909-
}
1910-
return gxuploadAttrs[key];
1905+
return GxUploadAttrs.ContainsKey(JsonNameToInternalName(jsonPropertyName));
19111906
}
1912-
1913-
private Hashtable props;
1914-
1915-
private PropertyInfo GetTypeProperty(string propName)
1907+
private bool IsGxUploadAttribute(PropertyInfo propertyInfo)
1908+
{
1909+
return GxUploadAttrs.ContainsKey(propertyInfo.Name);
1910+
}
1911+
private string JsonNameToInternalName(string jsonPropertyName)
1912+
{
1913+
string map = JsonMap(jsonPropertyName);
1914+
if (!string.IsNullOrEmpty(map))
1915+
return $"{PROPERTY_PREFIX}{map}";
1916+
else
1917+
return $"{PROPERTY_PREFIX}{jsonPropertyName}";
1918+
}
1919+
protected virtual GXTypeInfo TypeInfo { get { return _compatibilityGxuploadAttrs; } set { _compatibilityGxuploadAttrs = value; } }
1920+
private ConcurrentDictionary<string, byte> GxUploadAttrs
19161921
{
1917-
if (props == null)
1922+
get
19181923
{
1919-
props = new Hashtable();
1920-
foreach (PropertyInfo prop in this.GetType().GetProperties())
1924+
if (TypeInfo == null)
19211925
{
1922-
props.Add(prop.Name.ToLower(), prop);
1926+
TypeInfo = new GXTypeInfo();
1927+
1928+
TypeInfo.UploadAttrs = new ConcurrentDictionary<string, byte>(StringComparer.OrdinalIgnoreCase);
1929+
foreach (PropertyInfo property in this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
1930+
{
1931+
if (property.Name.StartsWith(PROPERTY_PREFIX, StringComparison.OrdinalIgnoreCase))
1932+
{
1933+
bool hasAtt = property.IsDefined(typeof(GxUpload), false);
1934+
if (hasAtt)
1935+
{
1936+
TypeInfo.UploadAttrs.TryAdd(property.Name, 1);
1937+
}
1938+
}
1939+
}
19231940
}
1941+
return TypeInfo.UploadAttrs;
19241942
}
1925-
return (PropertyInfo)props[propName];
1943+
}
1944+
private PropertyInfo GetTypeProperty(string propName)
1945+
{
1946+
return this.GetType().GetProperty(propName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
19261947
}
19271948

19281949
private Hashtable methods;
@@ -2004,7 +2025,10 @@ public void SetPropertyValue(string propertyName, object propertyValue)
20042025
GetType().GetProperty($"gxTpr_{propertyName}").SetValue(this, propertyValue);
20052026
}
20062027
}
2007-
2028+
public class GXTypeInfo
2029+
{
2030+
public ConcurrentDictionary<string, byte> UploadAttrs { get; set; }
2031+
}
20082032
public interface IGxJSONAble
20092033
{
20102034
void AddObjectProperty(string name, object prop);

dotnet/test/DotNetCoreUnitTest/StringUtil/JsonUtilTest.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,19 @@ public void DeserializationTrailingCommasCompatibility()
190190
JArray array = JSONHelper.ReadJSON<JArray>(json);
191191
Assert.Equal(7, array.Count);
192192
}
193+
#if NETCORE
194+
[Fact]
195+
public void DeserializationTwoLevels()
196+
{
197+
string json = "{\"Name\":\"MainName\",\"Level\":[{\"LevelName\":\"LevelName1\"}, {\"LevelName\":\"LevelName2\"}]}";
198+
GxContext context = new GxContext();
199+
SdtSDTTwoLevels sdt = new SdtSDTTwoLevels(context);
200+
sdt.FromJSonString(json, null);
201+
Assert.Equal("MainName", sdt.gxTpr_Name);
202+
Assert.Equal("LevelName1",((SdtSDTTwoLevels_LevelItem)sdt.gxTpr_Level.Item(1)).gxTpr_Levelname);
203+
Assert.Equal("LevelName2", ((SdtSDTTwoLevels_LevelItem)sdt.gxTpr_Level.Item(2)).gxTpr_Levelname);
204+
}
205+
#endif
193206
}
194207

195208
[XmlSerializerFormat]

0 commit comments

Comments
 (0)