Skip to content

Commit 4cfa7bc

Browse files
authored
- Fix collection serialization for rest procedures and dataproviders (#956)
* - Fix collection serialization para rest procedures and dataproviders output 106797 * - Fix case when rest procedure has an empty output parameter or no output parameter. Reverts to default wrapped status for this case * - Support for custom serialization of collection in REST proc as well as API objects. Changed Attribute GxUnWrappedJson for GxJsonSerialization(type) * - minor code improvements * - fix default case for serialization of lists in dataproviders rest with Json response * - Fix serialization wrapped for Genexus.Message Lists * - Rename of the root element in API objects that returns SDT from DPs * - Change GetWrappedStatus function as private. - Change SetWrappedStatus function as internal. * - Add Dataprovider Flag. * - Ignore wrapped status of Lists for DPs * - isDataProvider property was not inherited in NET 4.X . Created a different one. * - Saco temporalmente la restriccion de no usar el wrappedstatus en DP * - remove the property isDataProvider. Issue 106797
1 parent 24903cd commit 4cfa7bc

File tree

7 files changed

+130
-32
lines changed

7 files changed

+130
-32
lines changed

dotnet/src/dotnetframework/GxClasses/Model/GXBaseObject.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class GXBaseObject
3737
protected IGxContext _Context;
3838
bool _isMain;
3939
protected bool _isApi;
40+
protected bool _isDP;
4041
#if NETCORE
4142
internal static ActivitySource ActivitySource {
4243
get {
@@ -176,6 +177,7 @@ public bool IsApiObject
176177
set { _isApi = value; }
177178
get { return _isApi; }
178179
}
180+
179181
public virtual void cleanup() { }
180182

181183
virtual public bool UploadEnabled() { return false; }

dotnet/src/dotnetframework/GxClasses/Model/GXSilentTrn.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ public GXBaseCollection<SdtMessages_Message> GetMessages()
583583
public interface IGxGenericCollectionWrapped
584584
{
585585
bool GetIsWrapped();
586+
string GetWrappedStatus();
586587
void SetIsWrapped(bool value);
587588
}
588589

@@ -608,6 +609,12 @@ public GxGenericCollection(IGxCollection x, bool wrapped):this(x)
608609
isWrapped = wrapped;
609610
}
610611

612+
public GxGenericCollection(IGxCollection x, bool wrapped, string wrappedstatus) : this(x)
613+
{
614+
isWrapped = wrapped;
615+
wrappedStatus = wrappedstatus;
616+
}
617+
611618
public void LoadCollection(IGxCollection x)
612619
{
613620
foreach (IGxGenericCollectionItem x1 in this)
@@ -628,13 +635,27 @@ public override string ToString()
628635

629636
public bool GetIsWrapped()
630637
{
638+
if (wrappedStatus.Equals("unwrapped"))
639+
isWrapped = false;
631640
return isWrapped;
632641
}
633642

634643
public void SetIsWrapped(bool value)
635644
{
636645
isWrapped = value;
637646
}
647+
648+
private string wrappedStatus = "";
649+
650+
public string GetWrappedStatus()
651+
{
652+
return wrappedStatus;
653+
}
654+
655+
internal void SetWrappedStatus(string value)
656+
{
657+
wrappedStatus = value;
658+
}
638659
}
639660
public interface IGxGenericCollectionItem
640661
{
@@ -649,6 +670,17 @@ public GxUnWrappedJson()
649670
}
650671
}
651672

673+
[AttributeUsage(AttributeTargets.Class)]
674+
public sealed class GxJsonSerialization : Attribute
675+
{
676+
string unwrapped = default;
677+
public GxJsonSerialization(string jsonunwrapped)
678+
{
679+
unwrapped = jsonunwrapped;
680+
}
681+
public string JsonUnwrapped { get => unwrapped; set => unwrapped = value; }
682+
}
683+
652684
[AttributeUsage(AttributeTargets.Class)]
653685
public sealed class GxOmitEmptyCollection : Attribute
654686
{
@@ -836,6 +868,7 @@ public GxUpload()
836868
[XmlRoot(ElementName = "Message")]
837869
[XmlType(TypeName = "Message", Namespace = "GeneXus")]
838870
[Serializable]
871+
[GxJsonSerialization("wrapped")]
839872
public class SdtMessages_Message : GxUserType
840873
{
841874
public SdtMessages_Message()
@@ -938,6 +971,7 @@ public void initialize()
938971

939972
[DataContract(Name = @"Messages.Message", Namespace = "GeneXus")]
940973
[GxOmitEmptyCollection]
974+
[GxJsonSerialization("wrapped")]
941975
public class SdtMessages_Message_RESTInterface : GxGenericCollectionItem<SdtMessages_Message>, System.Web.SessionState.IRequiresSessionState
942976
{
943977
public SdtMessages_Message_RESTInterface()

dotnet/src/dotnetframework/GxClasses/Model/GXWebProcedure.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected override void SetCompression(HttpContext httpContext)
5757
}
5858
}
5959
public void setContextReportHandler()
60-
{
60+
{
6161

6262
oldReportHandler = null;
6363
reportHandler = context.reportHandler;

dotnet/src/dotnetframework/GxClasses/Services/GxRestWrapper.cs

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
using System.Net.Http;
3131
using System.Diagnostics;
3232
using GeneXus.Diagnostics;
33+
using System.Xml.Linq;
34+
3335

3436
namespace GeneXus.Application
3537

@@ -346,38 +348,62 @@ public virtual Task MethodUrlExecute(object key)
346348
Cleanup();
347349
}
348350
}
349-
bool GetWrappedStatus(GXBaseObject worker, bool defaultWrapped, Dictionary<string, object> outputParameters, int parCount, int originalParCount)
351+
private bool GetWrappedStatus(GXBaseObject worker, bool defaultWrapped, Dictionary<string, object> outputParameters, int parCount, int originalParCount)
350352
{
351353
bool wrapped = defaultWrapped;
354+
352355
if (worker.IsApiObject)
353356
{
354357
if (outputParameters.Count == 1)
355358
{
356359
if ((originalParCount == 1) || (originalParCount > 1 && !Preferences.WrapSingleApiOutput))
357360
{
358-
wrapped = false;
359-
Object v = outputParameters.First().Value;
360-
361-
if (v.GetType().GetInterfaces().Contains(typeof(IGxGenericCollectionWrapped)))
362-
{
363-
IGxGenericCollectionWrapped icollwrapped = v as IGxGenericCollectionWrapped;
364-
if (icollwrapped != null)
365-
wrapped = icollwrapped.GetIsWrapped();
366-
}
367-
if (v is IGxGenericCollectionItem item)
368-
{
369-
if (item.Sdt is GxSilentTrnSdt)
370-
{
371-
wrapped = (parCount > 1) ? true : false;
372-
}
373-
}
361+
wrapped = GetCollectionWrappedStatus(outputParameters, parCount, false, true);
374362
}
375363
if (originalParCount > 1 && Preferences.WrapSingleApiOutput)
376364
{
377365
wrapped = true; //Ignore defaultWrapped parameter.
378366
}
379367
}
380368
}
369+
else
370+
{
371+
if (originalParCount == 1)
372+
wrapped = GetCollectionWrappedStatus(outputParameters, parCount, wrapped, false);
373+
}
374+
return wrapped;
375+
}
376+
377+
378+
private bool GetCollectionWrappedStatus(Dictionary<string, object> outputParameters , int parCount, bool defaultWrapped, bool isAPI)
379+
{
380+
bool wrapped = defaultWrapped;
381+
if (outputParameters.Count > 0)
382+
{
383+
Object v = outputParameters.First().Value;
384+
if (v.GetType().GetInterfaces().Contains(typeof(IGxGenericCollectionWrapped)))
385+
{
386+
IGxGenericCollectionWrapped icollwrapped = v as IGxGenericCollectionWrapped;
387+
if (icollwrapped != null)
388+
{
389+
if (icollwrapped.GetWrappedStatus().Equals("default"))
390+
wrapped = defaultWrapped;
391+
else
392+
wrapped = icollwrapped.GetIsWrapped();
393+
}
394+
}
395+
396+
if (isAPI)
397+
{
398+
if (v is IGxGenericCollectionItem item)
399+
{
400+
if (item.Sdt is GxSilentTrnSdt)
401+
{
402+
wrapped = (parCount > 1) ? true : false;
403+
}
404+
}
405+
}
406+
}
381407
return wrapped;
382408
}
383409

@@ -806,8 +832,10 @@ protected Task Serialize(object value)
806832
#else
807833
var responseStream = _httpContext.Response.OutputStream;
808834
#endif
809-
var knownTypes = new List<Type>();
810-
knownTypes.Add(value.GetType());
835+
var knownTypes = new List<Type>
836+
{
837+
value.GetType()
838+
};
811839

812840
JSONHelper.WCFSerialize(value, Encoding.UTF8, knownTypes, responseStream);
813841
return Task.CompletedTask;
@@ -845,14 +873,17 @@ private static void RestProcess(GXBaseObject worker, Dictionary<string, object>
845873
}
846874
}
847875

848-
protected static object MakeRestType( object v, bool isApiObject)
876+
protected static object MakeRestType( object collectionValue, bool isApiObject)
849877
{
850-
Type vType = v.GetType();
878+
Type vType = collectionValue.GetType();
851879
Type itemType;
852880
if (vType.IsConstructedGenericType && typeof(IGxCollection).IsAssignableFrom(vType))
853-
{
881+
{
882+
bool isWrapped = (isApiObject)?false:true;
883+
object collectionObject = null;
884+
string wrappedStatus = "";
854885
Type restItemType=null;
855-
itemType = v.GetType().GetGenericArguments()[0];
886+
itemType = collectionValue.GetType().GetGenericArguments()[0];
856887
if ((typeof(IGXBCCollection).IsAssignableFrom(vType)) && !isApiObject)//Collection<BCType> convert to GxGenericCollection<BCType_RESTLInterface>
857888
{
858889
restItemType = ClassLoader.FindType(Config.CommonAssemblyName, itemType.FullName + "_RESTLInterface", null);
@@ -861,24 +892,31 @@ protected static object MakeRestType( object v, bool isApiObject)
861892
{
862893
restItemType = ClassLoader.FindType(Config.CommonAssemblyName, itemType.FullName + "_RESTInterface", null);
863894
}
864-
bool isWrapped = !restItemType.IsDefined(typeof(GxUnWrappedJson), false);
895+
object[] attributes = restItemType.GetCustomAttributes(typeof(GxJsonSerialization), false);
896+
IEnumerable<object> serializationAttributes = attributes.Where(a => a.GetType() == typeof(GxJsonSerialization));
897+
if (serializationAttributes != null && serializationAttributes.Any<object>())
898+
{
899+
GxJsonSerialization attFmt = (GxJsonSerialization)serializationAttributes.FirstOrDefault();
900+
wrappedStatus = attFmt.JsonUnwrapped;
901+
isWrapped = (isApiObject)? ((wrappedStatus == "wrapped")? true: false): ((wrappedStatus == "unwrapped") ? false : true);
902+
}
865903
bool isEmpty = !restItemType.IsDefined(typeof(GxOmitEmptyCollection), false);
866904
Type genericListItemType = typeof(GxGenericCollection<>).MakeGenericType(restItemType);
867-
object c = Activator.CreateInstance(genericListItemType, new object[] { v, isWrapped});
905+
collectionObject = Activator.CreateInstance(genericListItemType, new object[] { collectionValue, isWrapped , wrappedStatus});
868906
// Empty collection serialized w/ noproperty
869-
if (c is IList restList)
907+
if (collectionObject is IList restList)
870908
{
871909
if (restList.Count == 0 && !isEmpty)
872910
return null;
873911
}
874-
return c;
912+
return collectionObject;
875913
}
876914
else if (typeof(GxUserType).IsAssignableFrom(vType)) //SDTType convert to SDTType_RESTInterface
877915
{
878916
Type restItemType = ClassLoader.FindType(Config.CommonAssemblyName, vType.FullName + "_RESTInterface", null);
879-
return Activator.CreateInstance(restItemType, new object[] { v });
917+
return Activator.CreateInstance(restItemType, new object[] { collectionValue });
880918
}
881-
return v;
919+
return collectionValue;
882920
}
883921

884922
#if !NETCORE

dotnet/src/dotnetframework/GxClasses/Services/ReflectionHelper.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ private static Dictionary<string, object> ProcessParametersAfterInvoke(MethodInf
235235
int idx = 0;
236236
foreach (var methodParameter in methodParameters)
237237
{
238-
string gxParameterName = GxParameterName(methodParameter.Name);
238+
string gxParameterName = GxParameterName(methodParameter);
239239
if (IsByRefParameter(methodParameter))
240240
{
241241
outputParameters.Add(gxParameterName, parametersForInvocation[idx]);
@@ -320,12 +320,34 @@ internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IList
320320
return parametersForInvocation;
321321
}
322322
private static Regex attVar = new Regex(@"^AV?\d{1,}", RegexOptions.Compiled);
323+
324+
private static string GxParameterName(ParameterInfo methodParameter)
325+
{
326+
int idx = methodParameter.Name.IndexOf('_');
327+
if (idx >= 0)
328+
{
329+
string mparm = methodParameter.Name.Substring(idx + 1);
330+
string PName = methodParameter.ParameterType.FullName;
331+
// The root element name should be in the metadata of the SDT
332+
if (mparm.StartsWith("Gx") && mparm.EndsWith("rootcol") && PName.Contains("_"))
333+
{
334+
int Pos = PName.IndexOf("Sdt") + 3;
335+
mparm = PName.Substring(Pos, PName.IndexOf("_") - Pos);
336+
}
337+
return mparm;
338+
}
339+
else
340+
{
341+
return attVar.Replace(methodParameter.Name, string.Empty);
342+
}
343+
}
344+
323345
private static string GxParameterName(string methodParameterName)
324346
{
325347
int idx = methodParameterName.IndexOf('_');
326348
if (idx >= 0)
327349
{
328-
return methodParameterName.Substring(idx + 1);
350+
return methodParameterName.Substring(idx + 1);
329351
}
330352
else
331353
{

dotnet/src/extensions/Azure/test/GeneXus.Programs.Common/type_SdtEventMessageProperty.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public void initialize( )
138138
}
139139
#region Rest interface
140140
[GxUnWrappedJson()]
141+
[GxJsonSerialization("default")]
141142
[DataContract(Name=@"EventMessageProperty", Namespace="ServerlessAPI")]
142143
public class SdtEventMessageProperty_RESTInterface : GxGenericCollectionItem<SdtEventMessageProperty>, System.Web.SessionState.IRequiresSessionState
143144
{

dotnet/src/extensions/Azure/test/GeneXus.Programs.Common/type_SdtEventMessageResponse.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public void initialize()
131131
}
132132
#region Rest interface
133133
[GxUnWrappedJson()]
134+
[GxJsonSerialization("default")]
134135
[DataContract(Name = @"EventMessageResponse", Namespace = "GeneXus")]
135136
public class SdtEventMessageResponse_RESTInterface : GxGenericCollectionItem<SdtEventMessageResponse>, System.Web.SessionState.IRequiresSessionState
136137
{

0 commit comments

Comments
 (0)