![](/img/trans.png)
[英]Upload new file to onedrive using microsoft graph c# asp.net
[英]Upload a file in C# Asp.Net Core to Sharepoint/OneDrive using Microsoft Graph without user interaction
当我尝试使用 Microsoft Graph API 通过守护程序应用程序将文件上传到我的 OneDrive 时,我收到错误 400 Bad Request。 我使用 HttpClient,而不是 GraphServiceClient,因为后者假设交互并与 DelegatedAuthenticationProvider(?) 一起工作。
主要方法Upload
通过 Helper AuthenticationConfig
获取 AccessToken 并使用 Helper ProtectedApiCallHelper
将文件放入 OneDrive/SharePoint。
[HttpPost]
public async Task<IActionResult> Upload(IFormFile file)
{
var toegang = new AuthenticationConfig();
var token = toegang.GetAccessTokenAsync().GetAwaiter().GetResult();
var httpClient = new HttpClient();
string bestandsnaam = file.FileName;
var serviceEndPoint = "https://graph.microsoft.com/v1.0/drive/items/{Id_Of_Specific_Folder}/";
var wurl = serviceEndPoint + bestandsnaam + "/content";
// The variable wurl looks as follows: "https://graph.microsoft.com/v1.0/drive/items/{Id_Of_Specific_Folder}/proefdocument.txt/content"
var apicaller = new ProtectedApiCallHelper(httpClient);
apicaller.PostWebApi(wurl, token.AccessToken, file).GetAwaiter();
return View();
}
我使用以下标准帮助程序AuthenticationConfig.GetAccessToken()
获得正确的访问令牌
public async Task<AuthenticationResult> GetAccessTokenAsync()
{
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithClientSecret(config.ClientSecret)
.WithAuthority(new Uri(config.Authority))
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
return result;
}
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
{
...
return result;
}
}
使用 AccessToken、Graph-Url 和要上传的文件(作为 IFormFile),调用 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;
}
}
然后,您可以创建经过身份验证的 GraphServiceClients 并使用它们上传文件,例如上传到 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。
根据文档: 上传或替换 DriveItem 的内容
如果使用客户端凭证流(没有用户的 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.
}
}
您也可以使用 HttpClient
public async Task PostWebApi(string webApiUrl, string accessToken, IFormFile fileToUpload)
{
//Create a Stream and convert it to a required HttpContent-stream (StreamContent).
// Important is the using{...}. This keeps the stream open until processed
using (MemoryStream data = new MemoryStream())
{
await fileToUpload.CopyToAsync(data);
data.Seek(0, SeekOrigin.Begin);
var buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
data.Position = 0;
HttpContent content = new StreamContent(data);
if (!string.IsNullOrEmpty(accessToken))
{
// NO Headers other than the AccessToken should be added. If you do
// an Error 406 is returned (cannot process). So, no Content-Types, no Conentent-Dispositions
var defaultRequestHeaders = HttpClient.DefaultRequestHeaders;
defaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
HttpResponseMessage response = await HttpClient.PutAsync(webApiUrl, content);
if (response.IsSuccessStatusCode)
{
return;
}
else
{
// do something else
return;
}
}
content.Dispose();
data.Dispose();
} //einde using memorystream
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.