如何限制Microsoft Search API范围至Word/PDF及解决DriveItem无DriveId问题
问题描述
背景
我正在编写基于Microsoft Search API的逻辑,用于查找匹配查询条件的SharePoint文档(支持短语搜索与关键词搜索)。
存在的问题
- 返回结果不仅包含SharePoint/OneDrive文档,还包含Teams消息记录等内容,需要将搜索范围限定为Word文档或PDF等指定类型。
- 部分返回的DriveItem缺失DriveId,而后续调用Graph API获取文件内容需要该ID。
环境/配置
使用MS Graph 1.0,csproj文件中的引用如下:
<PackageReference Include="AutoMapper" Version="12.0.1" /> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" /> <PackageReference Include="Azure.Identity" Version="1.9.0" /> <PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" /> <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.1.1" /> <PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.0" /> <PackageReference Include="Microsoft.Graph" Version="5.18.0" /> <PackageReference Include="Microsoft.Graph.Core" Version="3.0.9" /> <PackageReference Include="Microsoft.Identity.Client" Version="4.54.1" />
代码
函数应用核心逻辑:
public async Task<string> Search() { var ApplicationClientID = Environment.GetEnvironmentVariable("CLIENT_ID"); var ApplicationClientSecret = Environment.GetEnvironmentVariable("CLIENT_SECRET"); var AzureTenantID = Environment.GetEnvironmentVariable("TENANT_ID"); string[] scopes = new[] { "https://graph.microsoft.com/.default" }; // using Azure.Identity; var options = new ClientSecretCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud, }; try { var clientSecretCredential = new ClientSecretCredential( AzureTenantID, ApplicationClientID, ApplicationClientSecret, options); var graphClient = new GraphServiceClient(clientSecretCredential, scopes, "https://graph.microsoft.com/v1.0"); Console.WriteLine($"searchQuery :{searchQuery}"); var requestBody = new Microsoft.Graph.Search.Query.QueryPostRequestBody { Requests = new List<SearchRequest> { new SearchRequest { EntityTypes = new List<EntityType?> { EntityType.DriveItem, }, Query = new SearchQuery { QueryString = this.searchQuery, }, Fields = new List<string> { "driveId", "listItemId", "author", "title", "url", "rank" }, QueryAlterationOptions = new SearchAlterationOptions { EnableSuggestion = true, EnableModification = true, } , Region ="US" }, }, }; var searchResults = await graphClient.Search.Query.PostAsync(requestBody).ConfigureAwait(false); //return searchResults; var jsonResults = ExtractDriveItemDetails(searchResults); return jsonResults; } catch (Exception ex) { log.LogError(ex.Message); return null; } }
提取结果的方法:
private static string ExtractDriveItemDetails(Microsoft.Graph.Search.Query.QueryResponse searchResults) { List<System.Collections.Generic.Dictionary<string, string?>> listOfDriveItems = new List<System.Collections.Generic.Dictionary<string, string?>>(); // Iterate through all the items in searchResults foreach (var hitContainer in searchResults.Value.SelectMany(result => result.HitsContainers)) { foreach (var hit in hitContainer.Hits) { // Check if the resource is a DriveItem if (hit.Resource is DriveItem driveItem) { var driveItemDetails = new Dictionary<string, string?>(); // Get the AdditionalData dictionary from the driveItem var additionalData = driveItem.ListItem.Fields.AdditionalData; // Use TryGetValue to safely access the values and handle null or missing keys string? driveId; if (additionalData.TryGetValue("driveId", out var driveIdValue) && driveIdValue is string driveIdString) { driveId = driveIdString; } else { driveId = null; } driveItemDetails.Add("itemId", driveItem.ListItem.Id.ToString()); driveItemDetails.Add("title", additionalData["title"] as string); driveItemDetails.Add("author", additionalData["author"] as string); driveItemDetails.Add("url", additionalData["url"] as string); listOfDriveItems.Add(driveItemDetails); } } } string json = JsonConvert.SerializeObject(listOfDriveItems); return json; }
解决方案
1. 限定搜索结果为指定文件类型
在搜索查询字符串中添加filetype:筛选运算符,精准指定要返回的文件格式。比如要只返回Word和PDF文档,修改QueryString部分的代码:
Query = new SearchQuery { QueryString = $"{this.searchQuery} filetype:docx OR filetype:pdf", },
如果需要支持更多格式,直接追加OR filetype:xxx即可,例如filetype:xlsx对应Excel文件、filetype:pptx对应PPT文件。
注:你当前代码已经将EntityTypes设置为DriveItem,这能排除非文档类实体,结合filetype筛选可进一步缩小范围到目标格式。
2. 解决DriveId缺失问题
当前从driveItem.ListItem.Fields.AdditionalData取driveId的方式不可靠,可通过以下两种方案获取稳定的DriveId:
方案一:直接从DriveItem的ParentReference属性获取
DriveItem自带的ParentReference.DriveId是官方推荐的可靠来源,修改提取逻辑:
string? driveId = driveItem.ParentReference?.DriveId;
方案二:从文件URL解析
如果ParentReference也无DriveId,可从文件的WebUrl中提取,SharePoint/OneDrive文件URL通常包含/drives/{driveId}/片段,用正则解析:
string? driveId = null; if (!string.IsNullOrEmpty(driveItem.WebUrl)) { var match = Regex.Match(driveItem.WebUrl, @"drives/([^/]+)/"); if (match.Success) { driveId = match.Groups[1].Value; } }
最后记得把获取到的driveId加入返回字典:
driveItemDetails.Add("driveId", driveId);
内容的提问来源于stack exchange,提问作者dot
相关产品推荐
相关产品推荐

