Skip to content

Fix request body serialization issues caused by property tracking logic #3301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
10b3033
Added implementation for late bound properties
timayabi2020 Apr 29, 2025
7165132
Merge branch 'dev' into delayed_loading_of_body_params
timayabi2020 Apr 29, 2025
42ab614
Updated regex
timayabi2020 Apr 29, 2025
fe68e7a
Merge branch 'delayed_loading_of_body_params' of https://github.com/m…
timayabi2020 Apr 29, 2025
d3aa131
Updated directive
timayabi2020 Apr 29, 2025
ed503d0
Added delay time
timayabi2020 Apr 29, 2025
7526d46
Rolled back everything
timayabi2020 Apr 29, 2025
30bef79
Added another module for tests
timayabi2020 Apr 30, 2025
c870224
Updated directive
timayabi2020 Apr 30, 2025
d8c3e3b
Still troubleshooting
timayabi2020 Apr 30, 2025
25d43cd
updated directive
timayabi2020 Apr 30, 2025
07f0a50
Fixed reflection error
timayabi2020 Apr 30, 2025
219a288
updates
timayabi2020 Apr 30, 2025
9f71f32
rolled back
timayabi2020 May 1, 2025
315ea12
Update Model extensions class
timayabi2020 May 6, 2025
b95107c
Merge branch 'dev' into delayed_loading_of_body_params
timayabi2020 May 7, 2025
112d4cb
Changed property tracker logic
timayabi2020 May 7, 2025
0cf2c80
Updated directive to extend check to the api class
timayabi2020 May 7, 2025
c5d95d6
Removed syntax error
timayabi2020 May 7, 2025
7abc9f9
Updated directive
timayabi2020 May 7, 2025
1dd63e6
Updated regex to comment out Json Extensions
timayabi2020 May 7, 2025
fbe6fe5
Removed property tracker implementation
timayabi2020 May 7, 2025
6307627
Found the issue. Uncommented users.Actions for one more test
timayabi2020 May 8, 2025
5d71629
Rolled back module mapping and module metadata
timayabi2020 May 8, 2025
9adbb0f
Rolled back education file
timayabi2020 May 8, 2025
e7e4e5f
Removed faulty property tracking related files
timayabi2020 May 8, 2025
e0b11c2
Removed property tracker implementation from custom modules
timayabi2020 May 8, 2025
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
6 changes: 3 additions & 3 deletions config/ModulesMapping.jsonc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"Applications": "^applicationTemplates\\.|^applications\\.|^servicePrincipals\\.|^onPremisesPublishingProfiles\\.|^users.appRoleAssignment$|^groups.appRoleAssignment$",
"Bookings": "^bookingBusinesses\\.|^bookingCurrencies\\.|^solutions.booking.*.Actions$|^solutions.bookingBusiness$|^solutions.bookingCurrency$|^solutions.virtualEventsRoot$|^solutions.booking.*.Functions$|^solutions.solutionsRoot$",
"BusinessScenario": "^solutions.businessScenario$|^solutions.BusinessScenario.*.Actions$|^solutions.BusinessScenario.*.Functions$",
Expand All @@ -21,7 +21,7 @@
"Financials": "^financials\\.",
"Groups": "^groups.group$|^groups.directoryObject$|^groups.conversation$|^groups.endpoint$|^groups.extension$|^groups.groupLifecyclePolicy$|^groups.resourceSpecificPermissionGrant$|^groups.profilePhoto$|^groups.conversationThread$|^groupLifecyclePolicies\\.|^users.group$|^groups.directorySetting$|^groups.*.Actions$|^groups.*.Functions$|^groupSettings\\.|^groups.groupSetting$|^groupSettingTemplates\\.",
"Identity.DirectoryManagement": "^administrativeUnits\\.|^contacts\\.|^devices\\.|^domains\\.|^directoryRoles\\.|^directoryRoleTemplates\\.|^directorySettingTemplates\\.|^settings\\.|^subscribedSkus\\.|^contracts\\.|^directory\\.|^users.scopedRoleMembership$|^organization.organization$|^organization.organizationalBranding$|^organization.organizationSettings$|^organization.*.Actions$|^organization.extension$|^tenantRelationships.*.Actions$|^tenantRelationships.*.Functions$|admin.peopleAdminSettings$|^organization\\.partnerInformation$",
"Identity.Governance": "^accessReviews\\.|^businessFlowTemplates\\.|^programs\\.|^programControls\\.|^programControlTypes\\.|^privilegedRoles\\.|^privilegedRoleAssignments\\.|^privilegedRoleAssignmentRequests\\.|^privilegedApproval\\.|^privilegedOperationEvents\\.|^privilegedAccess\\.|^agreements\\.|^users.agreementAcceptance$|^identityGovernance\\.|^roleManagement.rbacApplication$|^roleManagement.*.Functions$|roleManagement.*.Actions$",
"Identity.Governance": "^accessReviews\\.|^businessFlowTemplates\\.|^programs\\.|^programControls\\.|^programControlTypes\\.|^privilegedRoles\\.|^privilegedRoleAssignments\\.|^privilegedRoleAssignmentRequests\\.|^privilegedApproval\\.|^privilegedOperationEvents\\.|^privilegedAccess\\.|^agreements\\.|^users.agreementAcceptance$|^identityGovernance\\.|^roleManagement.rbacApplication$|^roleManagement.*.Functions$|roleManagement.*.Actions$",
"Identity.SignIns": "^organization.certificateBasedAuthConfiguration$|^invitations\\.|^identityProviders\\.|^oauth2PermissionGrants\\.|^identityProtection\\.|^dataPolicyOperations\\.|^identity\\.|^trustFramework\\.|^informationProtection\\.|^policies\\.|^users.authentication$|^users.informationProtection$|^tenantRelationships.multiTenantOrganization$|^policies.deviceRegistrationPolicy$|^policies.deviceRegistrationPolicy$",
"Identity.Partner": "^tenantRelationships.delegatedAdminRelationship$|^tenantRelationships.delegatedAdminCustomer$",
"Mail": "^users.inferenceClassification$|^users.mailFolder$|^users.message$",
Expand All @@ -41,4 +41,4 @@
"Users.Actions": "^users.*.Actions$",
"Users.Functions": "^users.*.Functions$",
"WindowsUpdates": "^admin.adminWindows$"
}
}
2 changes: 1 addition & 1 deletion openApiDocs/v1.0/Education.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31508,4 +31508,4 @@ components:
tokenUrl: https://login.microsoftonline.com/common/oauth2/v2.0/token
scopes: { }
security:
- azureaadv2: [ ]
- azureaadv2: [ ]
4 changes: 0 additions & 4 deletions src/Teams/beta/custom/MicrosoftGraphRscConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ public partial class MicrosoftGraphRscConfiguration :
IMicrosoftGraphRscConfigurationInternal,
Runtime.IValidates
{
private readonly PropertyTracker _propertyTracker = new PropertyTracker();
public void TrackProperty(string propertyName) => _propertyTracker.TrackProperty(propertyName);
public bool IsPropertySet(string propertyName) =>_propertyTracker.IsPropertySet(propertyName);
public T SanitizeValue<T>(object value) => PropertyTracker.SanitizeValue<T>(value);
/// <summary>
/// Backing field for Inherited model <see cref= "Microsoft.Graph.Beta.PowerShell.Models.IMicrosoftGraphEntity" />
/// </summary>
Expand Down
4 changes: 0 additions & 4 deletions src/Teams/beta/custom/MicrosoftGraphTeamsAppPreApproval.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ public partial class MicrosoftGraphTeamsAppPreApproval :
IMicrosoftGraphTeamsAppPreApprovalInternal,
Runtime.IValidates
{
private readonly PropertyTracker _propertyTracker = new PropertyTracker();
public void TrackProperty(string propertyName) => _propertyTracker.TrackProperty(propertyName);
public bool IsPropertySet(string propertyName) =>_propertyTracker.IsPropertySet(propertyName);
public T SanitizeValue<T>(object value) => PropertyTracker.SanitizeValue<T>(value);

/// <summary>
/// Backing field for Inherited model <see cref= "Microsoft.Graph.Beta.PowerShell.Models.IMicrosoftGraphEntity" />
Expand Down
44 changes: 2 additions & 42 deletions src/readme.graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,25 +334,6 @@ directive:
let dateTimeToJsonRegex = /(\.Json\.JsonString\()(.*)\?(\.ToString\(@"yyyy'-'MM'-'dd'T'HH':'mm':'ss\.fffffffK")/gm
$ = $.replace(dateTimeToJsonRegex, '$1System.DateTime.SpecifyKind($2.Value.ToUniversalTime(), System.DateTimeKind.Utc)$3');

//The following regex below adds a property tracker to ensure that users can also pass $Null as an alternative to the current "null" string which gets inferred to null.

const regexP = /AddIf\(\s*null\s*!=\s*\(\(\(object\)this\._(\w+).*?(\(Microsoft.*.PowerShell\.Runtime\.Json\.JsonNode\)).*?"(\w+)".*?container\.Add\s*\);/gm
$ = $.replace(regexP, (match, p1, p2, p3) => {
let capitalizedP1 = p1.charAt(0).toUpperCase() + p1.slice(1); // Capitalize first letter
return `if(this.IsPropertySet("${p1}"))\n\t\t{\n\t\t\tvar propertyInfo = this.GetType().GetProperty("${capitalizedP1}");\n\t\t\tif (propertyInfo != null)\n\t\t\t{\n\t\t\tSystem.Type propertyType = propertyInfo.PropertyType;\n\t\t\t\t\tAddIf(${p2}PropertyTracker.ConvertToJsonNode(propertyType, this._${p1}),"${p1}",container.Add);\n\t\t\t}\n\t\t}`;
});

$ = $.replace(/if\s*\(\s*null\s*!=\s*this\._(\w+)\s*\)/gm, 'if(this.IsPropertySet("$1"))')

let nameSpacePrefixRegex = /(Microsoft(?:\.\w+)*?\.PowerShell)/gm
let nameSpacePrefix = 'Microsoft.Graph.PowerShell';
if($.match(nameSpacePrefixRegex)){
let prefixMatch = nameSpacePrefixRegex.exec($);
nameSpacePrefix = prefixMatch[1];
}
$ = $.replace(/container\.Add\("(\w+)",\s*(__\w+)\);/gm, 'var nullFlag = ('+nameSpacePrefix+'.Runtime.Json.JsonNode)new '+nameSpacePrefix+'.Runtime.Json.JsonString("nullarray");\n\t\tif($2.Count == 0)\n\t\t{\n\t\t\t$2.Add(nullFlag);\n\t\t}\n\t\tcontainer.Add("$1", $2);');

$ =$.replace(/AddIf\(\s+null\s+!=\s+(this\._\w+)\s+\?\s+\((Microsoft\.Graph\..*?)\)\s+this\._(\w+)\.ToJson\(null,serializationMode\)\s+:\s+null,\s+"\w+"\s+,container.Add\s+\);/gm, 'if (this.IsPropertySet("$3")) \n{\n if ($1 != null)\n{\n container.Add("$3", ($2)$1.ToJson(null, serializationMode)); \n}\nelse\n{\n container.Add("$3", "null"); \n}\n}');

return $;
}
Expand Down Expand Up @@ -419,28 +400,6 @@ directive:
if($.match(additionalPropertiesRegex)) {
$ = $.replace(additionalPropertiesRegex, '$1$2 new $3');
}
//The following regex below adds a property tracker to ensure that users can also pass $Null as an alternative to the current "null" string which gets inferred to null.
$ = $.replace(/\bpublic\s+(\w+\??)\s+(\w+)\s*{\s*get\s*=>\s*this\.(\w+);\s*set\s*=>\s*this\.\3\s*=\s*value;\s*}/gmi,'public $1 $2\n\t{\n\t\tget=>this.$3;\n\t\tset\n\t\t{\n\t\t\tthis.$3=SanitizeValue<$1>(value);\n\t\t\tTrackProperty(nameof($2));\n\t\t}\n\t}')

$ = $.replace(/\bpublic\s+(\w+\[\])\s+(\w+)\s*{\s*get\s*=>\s*this\.(\w+);\s*set\s*=>\s*this\.\3\s*=\s*value;\s*}/gm,'public $1 $2\n\t{\n\t\tget=>this.$3;\n\t\tset\n\t\t{\n\t\t\tthis.$3=value;\n\t\t\tTrackProperty(nameof($2));\n\t\t}\n\t}')

$ = $.replace(/\bpublic\s+(Microsoft\.Graph\.[\w.]+\[\])\s+(\w+)\s*{\s*get\s*=>\s*this\.(\w+);\s*set\s*=>\s*this\.\3\s*=\s*value;\s*}/gm,'public $1 $2\n\t{\n\t\tget=>this.$3;\n\t\tset\n\t\t{\n\t\t\tthis.$3=value;\n\t\t\tTrackProperty(nameof($2));\n\t\t}\n\t}')

const match = $documentPath.match(/generated%2Fapi%2FModels%2F([\w]*[\w\d]*)\.cs/gm);
if (match) {
let fileName = match[0];
fileName = fileName.replace('generated%2Fapi%2FModels%2F','')
fileName = fileName.replace('.cs','')
const interfaceName = 'I'+fileName
$ = $.replace('interface '+interfaceName+' :', 'interface '+interfaceName+' : IPropertyTracker,')
const className = fileName
const regexP = new RegExp(`public\\s+partial\\s+class\\s+${className}\\s*:\\s*[\\s\\S]*?{`, "gm");
var matches = regexP.exec($);
let originalMatch = matches[0];
$ = $.replace(regexP, originalMatch+'\n\t\tprivate readonly PropertyTracker _propertyTracker = new PropertyTracker();\n\t\tpublic void TrackProperty(string propertyName) => _propertyTracker.TrackProperty(propertyName);\n\t\tpublic bool IsPropertySet(string propertyName) =>_propertyTracker.IsPropertySet(propertyName);\n\t\tpublic T SanitizeValue<T>(object value) => PropertyTracker.SanitizeValue<T>(value);');
}

$ = $.replace(/public\s+(Microsoft\.Graph\..*?)\s+(\w+)\s+{\s+get\s+=>\s+\(\s*this\.(\w+)\s+=\s*this\.\3\s+\?\?\s+new\s+(Microsoft\.Graph\..*?)\s+set\s+=>\s+this._\w+\s+=\s+value;\s+}/gm, 'public $1 $2 { \n get => (this.$3 = this.$3 ?? new $4\n set\n {\n this.$3 = value;\n TrackProperty(nameof($2));\n }\n}')

return $;

Expand Down Expand Up @@ -495,7 +454,7 @@ directive:
}
});
}

return $;
}

Expand Down Expand Up @@ -697,6 +656,7 @@ directive:
$ = $.replace(/request\.Content\s*=\s*new\s+global::System\.Net\.Http\.StringContent\(\s*null\s*!=\s*body\s*\?\s*new\s+Microsoft\.Graph\.Beta\.PowerShell\.Runtime\.Json\.XNodeArray\(.*?\)\s*:\s*null,\s*global::System\.Text\.Encoding\.UTF8\);/g,'request.Content = new global::System.Net.Http.StringContent(cleanedBody, global::System.Text.Encoding.UTF8);');

$ = $.replace(/cleanedBody = Microsoft.*.ReplaceAndRemoveSlashes\(cleanedBody\);/gm,'')

return $
}

Expand Down
9 changes: 0 additions & 9 deletions tools/Custom/IPropertyTracker.cs

This file was deleted.

72 changes: 0 additions & 72 deletions tools/Custom/PropertyTracker.cs

This file was deleted.

Loading