msgraph-sdk-dotnet icon indicating copy to clipboard operation
msgraph-sdk-dotnet copied to clipboard

Duplicate Fields Serialized to Request Body When Set Explicitly to Null

Open mslogriffi opened this issue 1 year ago • 4 comments

Describe the bug

I am using the GraphServiceClient class in some unit tests. Some unit tests populate fields on Graph contract objects with ternary statements (e.g. application.Description = condition ? "a description" : null). In the null cases here, I am observing the GraphServiceClient serialize the nulled field twice in the request body, which is causing JSON validation errors in my tests.

Expected behavior

Setting any field on the Application object explicitly to null and then using it in a GraphServiceClient request body serializes the object into valid JSON (without any duplicate fields).

How to reproduce

This code...

var appDisplayName = $"Application {guid}";

var application = new Application
{
    DisplayName = appDisplayName,
    Description = null,
    IdentifierUris = new List<string> { $"urn:{appDisplayName}" },
};

var createdApplication = await this.graphClient.Applications.PostAsync(application);

...Sends this request body to the Graph service the client is pointed to:

{
    "description":null,
    "description":null,
    "@odata.type":"#microsoft.graph.application",
    "displayName":"Application f5b18965-f282-455b-9d0f-cc9d816cebcf",
    "identifierUris":["urn:Application f5b18965-f282-455b-9d0f-cc9d816cebcf"]
}

This also happens with other fields in the Application class when set explicitly to null.

SDK Version

5.65.0

Latest version known to work for scenario above?

5.56.0

Known Workarounds

No response

Debug output

Click to expand log ```
</details>


### Configuration

- OS: Windows 11
- architecture: x64

### Other information

_No response_

mslogriffi avatar Dec 10 '24 00:12 mslogriffi

Thanks for raising this @mslogriffi

Out of curiosity, do you still get duplicate fields if you use the following the methods to serialize the object? https://learn.microsoft.com/en-us/openapi/kiota/serialization?tabs=csharp#serialization-helpers

andrueastman avatar Dec 10 '24 09:12 andrueastman

Thanks for raising this @mslogriffi

Out of curiosity, do you still get duplicate fields if you use the following the methods to serialize the object? https://learn.microsoft.com/en-us/openapi/kiota/serialization?tabs=csharp#serialization-helpers

It doesn't look like I do on 5.65.0. Running this code:

var guid = Guid.NewGuid().ToString("D");
var appDisplayName = $"Application {guid}";
testOutputHelper.WriteLine($"Create application '{appDisplayName}'.");

var application = new Application
{
    DisplayName = appDisplayName,
    Description = null,
    IdentifierUris = new List<string> { $"urn:{appDisplayName}" },
};

var applicationSerialized = await KiotaJsonSerializer.SerializeAsStringAsync(application);

testOutputHelper.WriteLine($"{nameof(applicationSerialized)}:{Environment.NewLine}{applicationSerialized}");

var applicationDeserialized = await KiotaJsonSerializer.DeserializeAsync(applicationSerialized, Application.CreateFromDiscriminatorValue);

testOutputHelper.WriteLine($"{nameof(applicationDeserialized)}:{Environment.NewLine}{applicationDeserialized.ToJson()}");

Gives this result (with 'testOutputHelper' being a ITestOutputHelper given by XUnit):

applicationSerialized:
{"description":null,"@odata.type":"#microsoft.graph.application","displayName":"Application 9d9bac23-fb27-432b-bb76-20d17bf59d73","identifierUris":["urn:Application 9d9bac23-fb27-432b-bb76-20d17bf59d73"]}
applicationDeserialized:
{"AddIns":null,"Api":null,"AppId":null,"ApplicationTemplateId":null,"AppManagementPolicies":null,"AppRoles":null,"Certification":null,"CreatedDateTime":null,"CreatedOnBehalfOf":null,"DefaultRedirectUri":null,"Description":null,"DisabledByMicrosoftStatus":null,"DisplayName":"Application 9d9bac23-fb27-432b-bb76-20d17bf59d73","ExtensionProperties":null,"FederatedIdentityCredentials":null,"GroupMembershipClaims":null,"HomeRealmDiscoveryPolicies":null,"IdentifierUris":["urn:Application 9d9bac23-fb27-432b-bb76-20d17bf59d73"],"Info":null,"IsDeviceOnlyAuthSupported":null,"IsFallbackPublicClient":null,"KeyCredentials":null,"Logo":null,"NativeAuthenticationApisEnabled":null,"Notes":null,"Oauth2RequirePostResponse":null,"OptionalClaims":null,"Owners":null,"ParentalControlSettings":null,"PasswordCredentials":null,"PublicClient":null,"PublisherDomain":null,"RequestSignatureVerification":null,"RequiredResourceAccess":null,"SamlMetadataUrl":null,"ServiceManagementReference":null,"ServicePrincipalLockConfiguration":null,"SignInAudience":null,"Spa":null,"Synchronization":null,"Tags":null,"TokenEncryptionKeyId":null,"TokenIssuancePolicies":null,"TokenLifetimePolicies":null,"UniqueName":null,"VerifiedPublisher":null,"Web":null,"DeletedDateTime":null,"AdditionalData":{},"BackingStore":{"ReturnOnlyChangedValues":false,"InitializationCompleted":true},"Id":null,"OdataType":"#microsoft.graph.application"}

I verified the same output is produced with version 5.56.0.

mslogriffi avatar Dec 11 '24 19:12 mslogriffi

@andrueastman I have verified this still repros with the latest release (version 5.69.0).

This code works and produces a correct request:

var application = new Application
{
    DisplayName = "My Test Application",
};

var createdApplication = await this.graphClient.Applications.PostAsync(application);

Above code produces this request body:

{"@odata.type":"#microsoft.graph.application","displayName":"My Test Application"}

However, this code reproduces the issue:

var application = new Application
{
    DisplayName = "My Test Application",
    Description = null,
};

var createdApplication = await this.graphClient.Applications.PostAsync(application);

Above code produces this request body:

{"description":null,"description":null,"@odata.type":"#microsoft.graph.application","displayName":"My Test Application"}

As you can see, the "description" field in the request body is duplicated.

Crazy find of a bug!

keystroke avatar Jan 30 '25 02:01 keystroke

Please fix before this behavior makes it into the next version of Azure PowerShell and other dotnet SDKs!

keystroke avatar Jan 30 '25 05:01 keystroke