Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 78 additions & 5 deletions dotnet/src/dotnetframework/GxClasses/Core/Web/HttpAjaxContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,67 @@ internal enum SessionType
RO_SESSION,
NO_SESSION,
}
internal interface IDynAjaxEventContext
{
void Clear();
void ClearParmsMetadata();
bool isInputParm(string key);
void SetParmHash(string fieldName, object value);
bool isParmModified(string fieldName, object value);
JArray inParmsMetadata { get; }
HashSet<string> inParmsMetadataHash { get; }
JArray outParmsMetadata { get; }
HashSet<string> outParmsMetadataHash { get; }
}
internal class DynAjaxEventContext: IDynAjaxEventContext
{
public JArray inParmsMetadata { get; set; }
public HashSet<string> inParmsMetadataHash { get; set; }
public JArray outParmsMetadata { get; set; }
public HashSet<string> outParmsMetadataHash { get; set; }
private StringDictionary inParmsHashValue = new StringDictionary();

public void ClearParmsMetadata()
{
inParmsMetadata = new JArray();
inParmsMetadataHash = new HashSet<string>();
outParmsMetadata = new JArray();
outParmsMetadataHash = new HashSet<string>();
}

public bool isInputParm(string key)
{
return inParmsMetadataHash.Contains(key);
}

public void Clear()
{
inParmsHashValue.Clear();
}
public void SetParmHash(string fieldName, object value)
{
IGxJSONSerializable jsonValue = value as IGxJSONSerializable;
if (jsonValue != null)
{
inParmsHashValue.Add(fieldName, GXUtil.GetHash(jsonValue.ToJSonString()));
}
}
public bool isParmModified(string fieldName, object value)
{
IGxJSONSerializable jsonValue = value as IGxJSONSerializable;
if (value != null)
{
if (!inParmsHashValue.ContainsKey(fieldName))
return true;
return GXUtil.GetHash(jsonValue.ToJSonString()) != inParmsHashValue[fieldName];
}
return true;
}
}

public class HttpAjaxContext : IHttpAjaxContext
{
private IGxContext _context;
private IGxContext _context;
static readonly ILog log = log4net.LogManager.GetLogger(typeof(HttpAjaxContext));
private Stack cmpContents = new Stack();
private GXAjaxCommandCollection commands = new GXAjaxCommandCollection();
Expand All @@ -73,15 +130,19 @@ public class HttpAjaxContext : IHttpAjaxContext
private JObject _Messages = new JObject();
private JArray _Grids = new JArray();
private JObject _ComponentObjects = new JObject();
private JArray _StylesheetsToLoad = new JArray();
private NameValueCollection _formVars;
private JArray _StylesheetsToLoad = new JArray();
private NameValueCollection _formVars;
private IDynAjaxEventContext _DynAjaxEventContext = new DynAjaxEventContext();

#if !NETCORE
private GXWebRow _currentGridRow;
#endif
private bool _isJsOutputEnabled = true;
private bool _isJsOutputEnabled = true;

internal SessionType SessionType { get; set; }

internal IDynAjaxEventContext DynAjaxEventContext { get { return _DynAjaxEventContext; } }

public string FormCaption { get; set; }

public JObject HiddenValues
Expand Down Expand Up @@ -266,6 +327,18 @@ public void ajax_rsp_assign_attri(String CmpContext, bool IsMasterPage, String A
}
}
}

private bool isUndefinedOutParam(string key, Object SdtObj) {

if (!DynAjaxEventContext.isInputParm(key))
{
if (SdtObj is IGXAssigned parm)
{
return !parm.IsAssigned;
}
}
return false;
}
public void ajax_rsp_assign_sdt_attri(String CmpContext, bool IsMasterPage, String AttName, Object SdtObj)
{
if (isJsOutputEnabled)
Expand All @@ -275,7 +348,7 @@ public void ajax_rsp_assign_sdt_attri(String CmpContext, bool IsMasterPage, Stri
try
{
JObject obj = GetGxObject(AttValues, CmpContext, IsMasterPage);
if (obj != null)
if (obj != null && (DynAjaxEventContext.isParmModified(AttName, SdtObj) || !isUndefinedOutParam( AttName, SdtObj)))
{
IGxJSONAble SdtObjJson = SdtObj as IGxJSONAble;
if (SdtObjJson != null)
Expand Down
11 changes: 7 additions & 4 deletions dotnet/src/dotnetframework/GxClasses/Domain/GxCollections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public bool FromJSonFile(GxFile file, GXBaseCollection<SdtMessages_Message> Mess

[Serializable]
[CollectionDataContract(Name = "GxSimpleCollection")]
public class GxSimpleCollection<T> : List<T>, IGxXMLSerializable, ICloneable, IGxJSONAble, IGxCollection<T>, IGxJSONSerializable
public class GxSimpleCollection<T> : GXBaseList<T>, IGxXMLSerializable, ICloneable, IGxJSONAble, IGxCollection<T>, IGxJSONSerializable
{

protected CollectionBase _jsonArr;
Expand Down Expand Up @@ -1030,14 +1030,16 @@ public string Name

[Serializable]
[XmlType(IncludeInSchema = false)]
public class GxUserType : IGxXMLSerializable, ICloneable, IGxJSONAble, IGxJSONSerializable
public class GxUserType : IGxXMLSerializable, ICloneable, IGxJSONAble, IGxJSONSerializable, IGXAssigned
{
static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.Utils.GxUserType));
protected GXProperties dirties = new GXProperties();

static object setupChannelObject = null;
static bool setupChannelInitialized;

[XmlIgnore]
public bool IsAssigned { get; set; }

static void loadConfigurator()
{
if (GxUserType.setupChannelObject == null && !GxUserType.setupChannelInitialized)
Expand Down Expand Up @@ -1085,9 +1087,10 @@ JObject JsonObj

public GxUserType()
{
IsAssigned = true;
}

public virtual void SetDirty(string fieldName)
public virtual void SetDirty(string fieldName)
{
dirties[fieldName.ToLower()] = "true";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,43 @@

namespace GeneXus.Utils
{
internal interface IGXAssigned
{
bool IsAssigned { get; set; }
}

public class GXBaseList<T> : List<T>, IGXAssigned
{
public GXBaseList()
{
IsAssigned = true;
}
[XmlIgnore]
public bool IsAssigned { get; set; }

public new void Clear() {
base.Clear();
IsAssigned = true;
}
public new void RemoveAt(int idx)
{
base.RemoveAt(idx);
IsAssigned = true;
}
public new void Add(T TObject)
{
base.Add(TObject);
IsAssigned = true;
}
public new void Insert(int idx, T TObject)
{
base.Insert(idx, TObject);
IsAssigned = true;
}
}

[Serializable]
public class GXBaseCollection<T> : List<T>, IGxXMLSerializable, IGxJSONAble, IGxCollection<T>, IGxJSONSerializable where T : GxUserType, IGxXMLSerializable, IGxJSONAble, new()
public class GXBaseCollection<T> : GXBaseList<T>, IGxXMLSerializable, IGxJSONAble, IGxCollection<T>, IGxJSONSerializable where T : GxUserType, IGxXMLSerializable, IGxJSONAble, new()
{

static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.Utils.GXBaseCollection<T>));
Expand Down Expand Up @@ -364,7 +398,7 @@ public IList ExternalInstance
{
get
{
return this;
return (IList) this;
}
set
{
Expand Down
70 changes: 44 additions & 26 deletions dotnet/src/dotnetframework/GxClasses/Middleware/GXHttp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ private static bool IsNumericType(Type t)
}

#if !NETCORE
protected IGxContext _Context;
protected IGxContext _Context;
bool _isMain;
#endif
bool _isStatic;
Expand Down Expand Up @@ -308,7 +308,7 @@ public DataIntegrityException(string message) : base(message)
}
}

public class DynAjaxEvent
internal class DynAjaxEvent
{
JArray inParmsValues;
JArray inHashValues;
Expand All @@ -319,9 +319,13 @@ public class DynAjaxEvent
string cmpContext = string.Empty;
int grid;
string row, pRow = string.Empty;
JArray inParmsMetadata;
private HashSet<string> inParmsMetadataHash;
bool anyError;
internal IDynAjaxEventContext DynAjaxEventContext;

internal DynAjaxEvent(IDynAjaxEventContext DynAjaxEventContext)
{
this.DynAjaxEventContext = DynAjaxEventContext;
}

private void ParseInputJSonMessage(JObject objMessage, GXHttpHandler targetObj)
{
Expand Down Expand Up @@ -373,10 +377,10 @@ private void ParseInputJSonMessage(JObject objMessage, GXHttpHandler targetObj)
pRow = (string)objMessage["pRow"];
if (objMessage.Contains("gxstate"))
{
ParseGXStateParms((JObject)objMessage["gxstate"]);
}
if (objMessage.Contains("fullPost"))
{
ParseGXStateParms((JObject)objMessage["gxstate"]);
}
if (objMessage.Contains("fullPost"))
{
this.targetObj._Context.httpAjaxContext.ParseGXState((Jayrock.Json.JObject)objMessage["fullPost"]);
}
}
Expand Down Expand Up @@ -411,18 +415,12 @@ private string BuildOutputJSonMessage()
return ((GxContext)(targetObj._Context)).getJSONResponse(this.cmpContext);
}

private void ClearInputParmsMetadata()
{
inParmsMetadata = new JArray();
inParmsMetadataHash = new HashSet<string>();
}

private bool IsInternalParm(JObject parm)
{
return parm.Contains("sPrefix") || parm.Contains("sSFPrefix") || parm.Contains("sCompEvt");
}

private void AddInputParmsMetadata(JObject inputParm)
private void AddParmsMetadata(JObject inputParm, JArray ParmsList, HashSet<string> ParmsListHash)
{
string key = string.Empty;

Expand All @@ -443,12 +441,12 @@ private void AddInputParmsMetadata(JObject inputParm)
key = (string)inputParm["ctrl"];
}

if (String.IsNullOrEmpty(key) || !inParmsMetadataHash.Contains(key))
if (String.IsNullOrEmpty(key) || !ParmsListHash.Contains(key))
{
inParmsMetadata.Add(inputParm);
ParmsList.Add(inputParm);
if (!String.IsNullOrEmpty(key))
{
inParmsMetadataHash.Add(key);
ParmsListHash.Add(key);
}
}
}
Expand All @@ -457,7 +455,7 @@ private void ParseMetadata()
{
try
{
ClearInputParmsMetadata();
DynAjaxEventContext.ClearParmsMetadata();
eventHandlers = new string[events.Length];
eventUseInternalParms = new bool[events.Length];
int eventCount = 0;
Expand All @@ -468,9 +466,14 @@ private void ParseMetadata()
JArray eventInputParms = (JArray)eventMetadata["iparms"];
foreach (JObject inputParm in eventInputParms)
{
AddInputParmsMetadata(inputParm);
AddParmsMetadata(inputParm, DynAjaxEventContext.inParmsMetadata, DynAjaxEventContext.inParmsMetadataHash);
eventUseInternalParms[eventCount] = eventUseInternalParms[eventCount] || IsInternalParm(inputParm);
}
JArray eventOutputParms = (JArray)eventMetadata["oparms"];
foreach (JObject outputParm in eventOutputParms)
{
AddParmsMetadata(outputParm, DynAjaxEventContext.outParmsMetadata, DynAjaxEventContext.outParmsMetadataHash);
}
eventCount++;
}
}
Expand Down Expand Up @@ -527,7 +530,7 @@ private void SetScalarOrCollectionValue(string fieldName, object value, JArray v
FieldInfo fieldInfo = getfieldInfo(targetObj, fieldName);
if (fieldInfo != null)
{
if (typeof(IGxCollection).IsAssignableFrom(fieldInfo.FieldType))
if (typeof(IGxCollection).IsAssignableFrom(fieldInfo.FieldType))
SetCollectionFieldValue(fieldInfo, values);
else
SetFieldValue(fieldInfo, value);
Expand Down Expand Up @@ -674,7 +677,21 @@ private Array GetArrayFieldValue(FieldInfo fieldInfo, object value)

return null;
}

private void initializeOutParms() {
DynAjaxEventContext.Clear();
foreach (JObject parm in DynAjaxEventContext.outParmsMetadata) {
string parmName = (string)parm["av"];
if (!String.IsNullOrEmpty(parmName))
{
object TypedValue = getFieldValue(targetObj, parmName);
DynAjaxEventContext.SetParmHash(parmName, TypedValue);
if (!DynAjaxEventContext.isInputParm(parmName) && TypedValue is IGXAssigned param)
{
param.IsAssigned = false;
}
}
}
}
private object[] BeforeInvoke()
{
List<object> MethodParms = new List<object>();
Expand All @@ -684,7 +701,7 @@ private object[] BeforeInvoke()
bool multipart = targetObj.context.IsMultipartRequest;
int hash_i = 0;
int parm_i = 0;
foreach (JObject parm in inParmsMetadata)
foreach (JObject parm in DynAjaxEventContext.inParmsMetadata)
{

if (parm["postForm"] != null)
Expand Down Expand Up @@ -756,7 +773,7 @@ private object[] BeforeInvoke()
{
SetScalarOrCollectionValue((string)parm["av"], columnValues[rowIdx - 1], columnValues);
object TypedValue = getFieldValue(targetObj, (string)parm["av"]);
CheckParmIntegrity(TypedValue, (string)columnHash, sRow, inParmsMetadata[parm_i], hash_i, Picture);
CheckParmIntegrity(TypedValue, (string)columnHash, sRow, DynAjaxEventContext.inParmsMetadata[parm_i], hash_i, Picture);
}
rowIdx++;
}
Expand Down Expand Up @@ -809,7 +826,7 @@ private object[] BeforeInvoke()
string hash = hashObj.Contains("hsh") ? (string)hashObj["hsh"] : string.Empty;
SetScalarOrCollectionValue((string)parm["av"], inParmsValues[parm_i], columnValues);
object TypedValue = getFieldValue(targetObj, (string)parm["av"]);
CheckParmIntegrity(TypedValue, hash, sRow, inParmsMetadata[parm_i], hash_i, Picture);
CheckParmIntegrity(TypedValue, hash, sRow, DynAjaxEventContext.inParmsMetadata[parm_i], hash_i, Picture);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -851,6 +868,7 @@ private object[] BeforeInvoke()
}
SetFieldValue("wbLoad", true);
}
initializeOutParms();
return MethodParms.ToArray();
}

Expand Down Expand Up @@ -963,7 +981,7 @@ public virtual void webAjaxEvent()
}
setAjaxCallMode();
context.setFullAjaxMode();
DynAjaxEvent dynAjaxEvent = new DynAjaxEvent();
DynAjaxEvent dynAjaxEvent = new DynAjaxEvent( context.httpAjaxContext.DynAjaxEventContext);
string jsonRequest;
if (context.IsMultipartRequest)
jsonRequest = cgiGet(GX_AJAX_MULTIPART_ID);
Expand Down