Search code examples
c#asp.net-coremicrosoft-graph-apimicrosoft-graph-sdks

How do I get content (text) from a searched file using the Microsoft Graph API?


Firstly, I using sdk 4.x version.

I want to create search function from onedrive with graph api.

In the Teams(app) search function case, when I use search function, the apps return info with file's contents and show stress searching keyword.

I want to show that file's contents(Not full text, only including search keyword)

But, the search response are't including content.

So, How can I replace this function? Or Do I wrong use this api?

That is a my search request code.

 var searchResults = await graphServiceClient
     .Drives[driveId2]
     .Root
     .Search(searchQuery)
     .Request()
     .GetAsync();

In graph explorer case(Http request)

https://graph.microsoft.com/v1.0/me/drives/{drive-id}/root/search(q='')

And also, content request case to reponse including ReadTimeout and WriteTimeout


var searchResults = await graphServiceClient
        .Drives[driveId]
        .Items[fileId]
        .Content
        .Request()                   
        .GetAsync();

Solution

  • At first, we have Search API right now to meet your requirement, you might have a look at the link, to see the request content and the response. Then the current document only shows us a sample with SDK v5. Don't forget to add required permission File.Read.All Sites.Read.All or Files.ReadWrite.All Sites.ReadWrite.All if necessary. Here's the codes.

    using Microsoft.Graph.Search.Query;
    using Microsoft.Graph.Models;
    
    var requestBody = new QueryPostRequestBody
    {
        Requests = new List<SearchRequest>
        {
            new SearchRequest
            {
                EntityTypes = new List<EntityType?>
                {
                    EntityType.ExternalItem,
                },
                ContentSources = new List<string>
                {
                    "/external/connections/connectionfriendlyname",
                },
                Region = "US",
                Query = new SearchQuery
                {
                    QueryString = "contoso product",
                },
                From = 0,
                Size = 25,
                Fields = new List<string>
                {
                    "title",
                    "description",
                },
            },
        },
    };
    
    var result = await graphClient.Search.Query.PostAsQueryPostResponseAsync(requestBody);
    

    But since you are trying to use V4 SDK, while I didn't find official sample or other samples for V4 SDK, I think we could have a workaround which sending http request directly instead of using SDK. Since you already used GraphClient in your code, I trust you also have codes similar to codes below which containing EnableTokenAcquisitionToCallDownstreamApi.

    builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)        .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi()
        .AddInMemoryTokenCaches();
    

    Then we can inject ITokenAcquisition in the Controller to generate access token, and use that to call the query API.

    public class HomeController : Controller
    {
        private readonly ITokenAcquisition _tokenAcquisition;
        public HomeController(ITokenAcquisition tokenAcquisition)
        {
            _tokenAcquisition = tokenAcquisition;
        }
        
        public async Task IndexAsync(){
            var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "File.Read.All", "Sites.Read.All" });
            var request ="{{\"requests\": [{{\"entityTypes\": [\"driveItem\", \"listItem\", \"list\"],\"query\": {{\"queryString\": \"contoso\"}]}}";
            var content = new StringContent(request, Encoding.UTF8, "application/json");
            var httpReqMesg = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/search/query")
            {
                Headers =
                {
                    { HeaderNames.Authorization, "Bearer "+ accessToken}
                },
                Content = content
            };
            var httpClient = _httpClientFactory.CreateClient();
            var response = await httpClient.SendAsync(httpReqMesg);
            var res = "";
            if (response.StatusCode == HttpStatusCode.OK)
            {
                res = await response.Content.ReadAsStringAsync();
            }
        }
    
    }
    

    By the way, if you are using Client Credential Flow which doesn't have ITokenAcquisition. We might use code below to generate access token.

    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var tenantId = "tenantId";
    var clientId = "clientId";
    var clientSecret = "clientSecret";
    var clientSecretCredential = new ClientSecretCredential(
                    tenantId, clientId, clientSecret);
    var token = clientSecretCredential.GetTokenAsync(tokenRequestContext).Result.Token;