Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Microsoft Graph将C Asp.Net Core中的文件上载到Sharepoint/OneDrive,无需用户交互_C#_Asp.net Core_Sharepoint_Microsoft Graph Api_Onedrive - Fatal编程技术网

C# 使用Microsoft Graph将C Asp.Net Core中的文件上载到Sharepoint/OneDrive,无需用户交互

C# 使用Microsoft Graph将C Asp.Net Core中的文件上载到Sharepoint/OneDrive,无需用户交互,c#,asp.net-core,sharepoint,microsoft-graph-api,onedrive,C#,Asp.net Core,Sharepoint,Microsoft Graph Api,Onedrive,当我尝试使用Microsoft Graph API使用守护程序应用程序将文件上载到OneDrive时,收到错误400错误请求。我使用的是HttpClient,而不是GraphServiceClient,因为后者假定与DelegatedAuthenticationProvider进行交互并与DelegatedAuthenticationProvider一起工作 该应用程序已在AAD中注册,并具有正确的应用程序权限Microsoft Graph/File ReadWrite.All 该注册针对一个租

当我尝试使用Microsoft Graph API使用守护程序应用程序将文件上载到OneDrive时,收到错误400错误请求。我使用的是HttpClient,而不是GraphServiceClient,因为后者假定与DelegatedAuthenticationProvider进行交互并与DelegatedAuthenticationProvider一起工作

该应用程序已在AAD中注册,并具有正确的应用程序权限Microsoft Graph/File ReadWrite.All 该注册针对一个租户,按照说明,没有重定向url 主方法Upload通过Helper AuthenticationConfig获取AccessToken,并使用Helper ProtectedApiCallHelper将文件放入OneDrive/SharePoint

使用AccessToken、图形Url和要上载为Helper ProtectedApiCallHelper.PostWebApi的文件

public async Task PostWebApi(string webApiUrl, string accessToken, IFormFile fileToUpload)
    {
        Stream stream = fileToUpload.OpenReadStream();
        var x = stream.Length;
        HttpContent content = new StreamContent(stream);

        if (!string.IsNullOrEmpty(accessToken))
        {
            var defaultRequestHeaders = HttpClient.DefaultRequestHeaders;               
            HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/octet-stream"));             
            defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);

// Here the 400 Bad Request happens
            HttpResponseMessage response = await HttpClient.PutAsync(webApiUrl, content);

            if (response.IsSuccessStatusCode)
            {
                return;
            }
            else
            {
                 //error handling                   
                return;
            }
        }
    }
编辑


请参阅下面的工作解决方案。

您可以使用GraphServiceClient,而无需使用客户端id和客户端密码进行用户交互。首先,创建一个名为GraphAuthProvider的类:

    public class GraphAuthProvider
{
    public async Task<GraphServiceClient> AuthenticateViaAppIdAndSecret(
        string tenantId,
        string clientId, 
        string clientSecret)
    {
        var scopes = new string[] { "https://graph.microsoft.com/.default" };

        // Configure the MSAL client as a confidential client
        var confidentialClient = ConfidentialClientApplicationBuilder
            .Create(clientId)
            .WithAuthority($"https://login.microsoftonline.com/{tenantId}/v2.0")
            .WithClientSecret(clientSecret)
            .Build();

        // Build the Microsoft Graph client. As the authentication provider, set an async lambda
        // which uses the MSAL client to obtain an app-only access token to Microsoft Graph,
        // and inserts this access token in the Authorization header of each API request. 
        GraphServiceClient graphServiceClient =
            new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
            {

                // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
                var authResult = await confidentialClient
                    .AcquireTokenForClient(scopes)
                    .ExecuteAsync();

                // Add the access token in the Authorization header of the API request.
                requestMessage.Headers.Authorization =
                    new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
            })
        );

        return graphServiceClient;
    }
}
然后,您可以创建经过身份验证的GraphServiceClient,并使用它们上载文件,例如到SharePoint:

        GraphServiceClient _graphServiceClient = await _graphAuthProvider.AuthenticateViaAppIdAndSecret(
            tenantId,
            clientId,
            appSecret);


        using (Stream fileStream = new FileStream(
            fileLocation,
            FileMode.Open,
            FileAccess.Read))
        {
            resultDriveItem = await _graphServiceClient.Sites[sites[0]]
                    .Drives[driveId].Root.ItemWithPath(fileName).Content.Request().PutAsync<DriveItem>(fileStream);

       }

关于权限:您可能需要的权限不仅仅是Files.ReadWrite.All。据我所知,应用程序需要应用程序权限Sites.ReadWrite.All才能将文档上载到SharePoint。

您可以使用GraphServiceClient,而无需使用客户端id和客户端密码进行用户交互。首先,创建一个名为GraphAuthProvider的类:

    public class GraphAuthProvider
{
    public async Task<GraphServiceClient> AuthenticateViaAppIdAndSecret(
        string tenantId,
        string clientId, 
        string clientSecret)
    {
        var scopes = new string[] { "https://graph.microsoft.com/.default" };

        // Configure the MSAL client as a confidential client
        var confidentialClient = ConfidentialClientApplicationBuilder
            .Create(clientId)
            .WithAuthority($"https://login.microsoftonline.com/{tenantId}/v2.0")
            .WithClientSecret(clientSecret)
            .Build();

        // Build the Microsoft Graph client. As the authentication provider, set an async lambda
        // which uses the MSAL client to obtain an app-only access token to Microsoft Graph,
        // and inserts this access token in the Authorization header of each API request. 
        GraphServiceClient graphServiceClient =
            new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
            {

                // Retrieve an access token for Microsoft Graph (gets a fresh token if needed).
                var authResult = await confidentialClient
                    .AcquireTokenForClient(scopes)
                    .ExecuteAsync();

                // Add the access token in the Authorization header of the API request.
                requestMessage.Headers.Authorization =
                    new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
            })
        );

        return graphServiceClient;
    }
}
然后,您可以创建经过身份验证的GraphServiceClient,并使用它们上载文件,例如到SharePoint:

        GraphServiceClient _graphServiceClient = await _graphAuthProvider.AuthenticateViaAppIdAndSecret(
            tenantId,
            clientId,
            appSecret);


        using (Stream fileStream = new FileStream(
            fileLocation,
            FileMode.Open,
            FileAccess.Read))
        {
            resultDriveItem = await _graphServiceClient.Sites[sites[0]]
                    .Drives[driveId].Root.ItemWithPath(fileName).Content.Request().PutAsync<DriveItem>(fileStream);

       }
关于权限:您可能需要的权限不仅仅是Files.ReadWrite.All。据我所知,应用程序需要应用程序权限Sites.ReadWrite.All才能将文档上载到SharePoint。

根据文档:

如果在没有用户的情况下使用客户端凭据流M2M流,则应使用以下请求:

PUT /drives/{drive-id}/items/{parent-id}:/{filename}:/content
而不是:

https://graph.microsoft.com/v1.0/drive/items/{Id_Of_Specific_Folder}/proefdocument.txt/content
根据文件:

如果在没有用户的情况下使用客户端凭据流M2M流,则应使用以下请求:

PUT /drives/{drive-id}/items/{parent-id}:/{filename}:/content
而不是:

https://graph.microsoft.com/v1.0/drive/items/{Id_Of_Specific_Folder}/proefdocument.txt/content

这是使用GraphServiceClient的最后一个工作示例

public async Task<DriveItem> UploadSmallFile(IFormFile file, bool uploadToSharePoint)
    {
        IFormFile fileToUpload = file;
        Stream ms = new MemoryStream();

        using (ms = new MemoryStream()) //this keeps the stream open
        {
            await fileToUpload.CopyToAsync(ms);
            ms.Seek(0, SeekOrigin.Begin);
            var buf2 = new byte[ms.Length];
            ms.Read(buf2, 0, buf2.Length);

            ms.Position = 0; // Very important!! to set the position at the beginning of the stream
            GraphServiceClient _graphServiceClient = await AuthenticateViaAppIdAndSecret();

            DriveItem uploadedFile = null;
            if (uploadToSharePoint == true)
            {
                uploadedFile = (_graphServiceClient
                .Sites["root"]
                .Drives["{DriveId}"]
                .Items["{Id_of_Targetfolder}"]
                .ItemWithPath(fileToUpload.FileName)
                .Content.Request()
                .PutAsync<DriveItem>(ms)).Result;
            }
            else
            {
                // Upload to OneDrive (for Business)
                uploadedFile = await _graphServiceClient
                .Users["{Your_EmailAdress}"]
                .Drive
                .Root
                .ItemWithPath(fileToUpload.FileName)
                .Content.Request()
                .PutAsync<DriveItem>(ms);
            }

            ms.Dispose(); //clears memory
            return uploadedFile; //returns a DriveItem. 
        }
    }

这是使用GraphServiceClient的最后一个工作示例

public async Task<DriveItem> UploadSmallFile(IFormFile file, bool uploadToSharePoint)
    {
        IFormFile fileToUpload = file;
        Stream ms = new MemoryStream();

        using (ms = new MemoryStream()) //this keeps the stream open
        {
            await fileToUpload.CopyToAsync(ms);
            ms.Seek(0, SeekOrigin.Begin);
            var buf2 = new byte[ms.Length];
            ms.Read(buf2, 0, buf2.Length);

            ms.Position = 0; // Very important!! to set the position at the beginning of the stream
            GraphServiceClient _graphServiceClient = await AuthenticateViaAppIdAndSecret();

            DriveItem uploadedFile = null;
            if (uploadToSharePoint == true)
            {
                uploadedFile = (_graphServiceClient
                .Sites["root"]
                .Drives["{DriveId}"]
                .Items["{Id_of_Targetfolder}"]
                .ItemWithPath(fileToUpload.FileName)
                .Content.Request()
                .PutAsync<DriveItem>(ms)).Result;
            }
            else
            {
                // Upload to OneDrive (for Business)
                uploadedFile = await _graphServiceClient
                .Users["{Your_EmailAdress}"]
                .Drive
                .Root
                .ItemWithPath(fileToUpload.FileName)
                .Content.Request()
                .PutAsync<DriveItem>(ms);
            }

            ms.Dispose(); //clears memory
            return uploadedFile; //returns a DriveItem. 
        }
    }

@问题1991谢谢你的明确指示。resultDriveItem是什么类型的变量?这是否应该是一个HttpResponseMessage?@QuestionPS1991您的解决方案也同样有效!非常感谢你的帮助。我现在面临另一个挑战,那就是让这条流正常工作。到目前为止,在这两种解决方案中,Memorystream都保持为空0字节。由于我没有得到任何错误,一切都“正常”,但没有结果。结果的类型是DriveItem。至于流,ifformFile.OpenReadStream只是打开流,您仍然需要读取该文件。这应该让你开始:我已经解决了。我将把解决方案添加到此讨论中。非常感谢much@QuestionPS1991谢谢你的明确指示。resultDriveItem是什么类型的变量?这应该是HttpResponseMessage吗?@QuestionPS1991您的解决方案同样有效!非常感谢你的帮助。我现在面临另一个挑战,那就是让这条流正常工作。到目前为止,在这两种解决方案中,Memorystream都保持为空0字节。由于我没有得到任何错误,一切都“正常”,但没有结果。结果的类型是DriveItem。至于流,ifformFile.OpenReadStream只是打开流,您仍然需要读取该文件。这应该让你开始:我已经解决了。我将把解决方案添加到此讨论中。非常感谢