Using the MS Graph SDK for .NET is convenient but I find the documentation and examples pretty lacking. So when wanted to use the Search endpoint it took me quite a while to figure out how to make it work. Here is an example showing how to search for SharePoint list items:
var q = new SearchRequestObject() { EntityTypes = new[] { EntityType.ListItem }, Query = new SearchQuery() { QueryString = "isDocument:true" // Keyword Query Language (KQL) is supported }, Fields = new List<string>() // You must specify all fields you want to return { "filename", "modifiedBy", "size", "originalPath" }, From = 0, Size = 25 }; var result = new List<ListItem>(); var moreAvailable = true; while (moreAvailable) { var request = await _graphClient .Search .Query(new List<SearchRequestObject> { q }) .Request() .Header("User-Agent", "NONISV|RLVision|Blog/Prod") .PostAsync(); moreAvailable = (bool)request.CurrentPage[0].HitsContainers.First().MoreResultsAvailable!; if (request.CurrentPage[0].HitsContainers.First().Total > 0) { foreach (var searchHit in request.CurrentPage[0].HitsContainers.First().Hits) { result.Add((Microsoft.Graph.ListItem)searchHit.Resource); } } q.From = q.From + q.Size; q.Size = 200; }
Notable gotchas:
- You must specify all fields you want to return. For custom fields you must use the Managed Property names (ending with OWS*) for custom fields. Tip: Use the SharePoint Search Query Tool to see all available fields you can use in a query
- Search returns
SearchHit
objects. You need to cast the SearchHit results to the correct type, in this caseListItems
. Note though that the casted ListItem will only contain data in the dynamic AdditionalData/Fields structure, everything else will be empty. PageIterator
does not work with Search, so you need to do pagination manually.- You can specify the number of items to return with the
Size
property. Default is 25, max is 1000. 200 is “reasonable” according to docs. Docs also says that best practice is to start small and increase subsequent requests. - In the response, fields will retain their casing from the request – EXCEPT for the first letter which is always lower case…