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

"Invalid property 'businessPhones' specified in $select." on querying for a user's membership of a group in v5

Open Bellarmine-Head opened this issue 2 years ago • 9 comments

Describe the bug In v4 the following request was allowed (i.e. it was not a bad request):-

// v4 - this works
await _graphClient.Groups[targetGroup.Id].Members[user.Id].Request().GetAsync();

If this request succeeded, you could count on the indicated user being a member of the indicated group.

Removing Request() from the above results in code that doesn't compile, so I used:-

// v5 - this doesn't work
await _graphClient.Groups[targetGroup.Id].Members[user.Id].GraphUser.GetAsync();

but this code throws an ODataError exception (so it really should be called ODataErrorException but that's another story) with a bad request error message:-

"Invalid property 'businessPhones' specified in $select."

What is strange is that the v5 request to determine if a group (as opposed to a user) is a member of a group is fine, and doesn't result in a bad request:-

// v5 - this works
await _graphClient.Groups[targetGroup.Id].Members[group.Id].GraphGroup.GetAsync();

To Reproduce In version 5.7.0 of Microsoft.Graph package, execute:-

await _graphClient.Groups[targetGroup.Id].Members[user.Id].GraphUser.GetAsync();

Expected behavior No exception thrown, and certainly not an OData exception indicating a bad request with error message "Invalid property 'businessPhones' specified in $select.".

Screenshots

Desktop (please complete the following information):

  • OS: Windows 10
  • Browser: Edge

Bellarmine-Head avatar Apr 24 '23 14:04 Bellarmine-Head

Thanks for raising this @Bellarmine-Head

The error seems to suggest that the request made to the service has the $select parameter in it.

Any chance you can share the request url when you do the following?

        var requestInfo = _graphClient.Groups[""].Members[""].GraphUser.ToGetRequestInformation();
        var requestUrl = requestInfo.URI.OriginalString;

andrueastman avatar Apr 25 '23 07:04 andrueastman

Hi @andrueastman - thanks for looking into this.

I executed

var requestInfo = _graphClient.Groups[targetGroup.Id].Members[user.Id].GraphUser.ToGetRequestInformation();
var requestUrl = requestInfo.URI.OriginalString;

and got...

https://graph.microsoft.com/v1.0/groups/<guid here>/members/<another guid here>/graph.user

Bellarmine-Head avatar Apr 25 '23 10:04 Bellarmine-Head

This looks suspiciously similar:-

https://learn.microsoft.com/en-us/answers/questions/664588/administrative-unit-user-id-specific-filter-return?orderby=oldest

Bellarmine-Head avatar Apr 25 '23 15:04 Bellarmine-Head

Thanks for this @Bellarmine-Head

I believe you should not specify the type segment on a specific id but on the collection unless you are sure of the type.

This will return a collection of users in the group by API side filtering.

var users = await graphClient.Groups["id"].Members.GraphUser.GetAsync();

However, this will fail if the specified member is not a user. This is because if the member is a group it won't have the properties of a user(e.g businessPhones) and the API will throw the error.

var user = await graphClient.Groups["id"].Members["member-id"].GraphUser.GetAsync();

If you wish to simple verify if the result is a user, you can simply do verify the type as below.

var member = await graphClient.Groups["id"].Members["member-id"].GetAsync();
if(member is User user)
{
// do something with the user. 
}

andrueastman avatar Apr 26 '23 11:04 andrueastman

@andrueastman

If you wish to simple verify if the result is a user, you can simply do verify the type as below. var member = await graphClient.Groups["id"].Members["member-id"].GetAsync();

Unfortunately not. As I indicated when I opened the issue, this doesn't compile.

image

It seems to me that what we need is a DirectoryObject cast...

await _graphClient.Groups[targetGroup.Id].Members[user.Id].DirectoryObject.GetAsync();

Bellarmine-Head avatar Apr 26 '23 13:04 Bellarmine-Head

Or we need this to be valid, and not need a cast...

var member = await graphClient.Groups["id"].Members["member-id"].GetAsync();

Bellarmine-Head avatar Apr 27 '23 06:04 Bellarmine-Head

I agree there's a path definitely missing in the metadata.

We would need to add a GET path to the metadata to '/groups/{group-id}/members/{directoryObject-id}/ which is missing at the moment.

andrueastman avatar Apr 27 '23 07:04 andrueastman