OneDrive upload files with REST API via resumable session - c#

Hi there currently I am trying to make files uploading to one drive trough REST API. But every time I am getting Exception with 401 code for non authorized
The remote server returned an error: (401) Unauthorized.
My code snippet
public async Task<string> UploadFileAsync(Account account, StorageFile file)
{
var publicClientApplication = PublicClientApplicationBuilder.Create(MicrosoftConstants.ClientId)
.WithRedirectUri(MicrosoftConstants.RedirectUri)
.Build();
var scopes = new string[]
{
"files.readwrite.all"
};
AuthenticationResult authToken = null;
try
{
authToken = await publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync();
}
catch (Exception)
{
}
if (authToken != null)
{
var postData = new
{
item = new
{
name = file.Name
}
};
var json = JsonConvert.SerializeObject(postData);
var request = (HttpWebRequest)WebRequest.Create($"https://graph.microsoft.com/v1.0/me/drive/items/root:/{file.Name}:/createUploadSession");
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength= json.Length;
request.Headers["Authorization"] = "bearer" + authToken.AccessToken;
using (var requestStream = await request.GetRequestStreamAsync())
using (var streamWriter = new StreamWriter(requestStream))
{
streamWriter.Write(json);
}
var response = (HttpWebResponse)await request.GetResponseAsync();
}
return string.Empty;
}
Do anybody know what am I doing wrong?

To make it work I had to change header with authorization to
request.Headers["Authorization"] = "Bearer " + authToken.AccessToken;

Related

You do not have permission to view this directory or page unauthorized 401

I have a web app running in Azure which has azure Active Directory authentication enabled. This is given below (I have configured this correctly there is no issue with this): -
Now I want to call one of the API of this web app. Code for getting access token based on the client credentials: -
public static string GetAccessToken()
{
string authContextURL = "https://login.microsoftonline.com/" + "TENANT_ID";
var authenticationContext = new AuthenticationContext(authContextURL);
var credential = new ClientCredential("CLIENT_ID", "CLIENT_SECRET");
var result = authenticationContext.AcquireTokenAsync("URL_FOR_MY_WEBAPP", credential).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the token");
}
string token = result.AccessToken;
return token;
}
Code for calling the desired API: -
private static string GET(string URI, string token)
{
Uri uri = new Uri(string.Format(URI));
// Create the request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
// Get the response
HttpWebResponse httpResponse;
try
{
httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
}
catch (Exception ex)
{
return ex.Message;
}
string result = null;
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
return result;
}
I am getting an unauthorized error while getting the response. Could anyone tell what is wrong here? The same service principal is working with graph client. Any help or suggestion will be appreciated.
The resource to acquire access token is not correct. You should use the same client id of your AD app.
var result = authenticationContext.AcquireTokenAsync("{CLIENT_ID}", credential).Result;

Wait for user to complete its Authentication C# asp.net MVC

So I Have A project in which I upload a video to daily motion with API and for uploading a video with api I need an authorized access token.
So the problem I am getting is that when my program starts the authorizing process it didn't wait for a user to complete its authorizing and exchange the token it goes to a new step.
hope you understand my problem
[HttpPost]
public ActionResult Add(Video Videos)
{
var accessToken = GetAccessToken();
Authorize(accessToken);//should wait here for user to complete the
// process and then move to the next step
var fileToUpload = #"C:\Users\Hassan\Downloads\SampleVideo_1280x720_1mb.mp4";
var uploadUrl = GetFileUploadUrl(accessToken);
var response = GetFileUploadResponse(fileToUpload, accessToken, uploadUrl);
var uploadedResponse = PublishVideo(response, accessToken,Videos.VideoName,Videos.Tags);
var TEST = Privateid(response, accessToken,uploadedResponse.id);
Videos.PrivateID = TEST.private_id;
Videos.VideoEmbeddedCode = TEST.embed_html;
_context.Videos.Add(Videos);
_context.SaveChanges();
return RedirectToAction("AddVideo", "Admin");
}
GetAccessToken and Authroize Method
private static string GetAccessToken()
{
var request = WebRequest.Create("https://api.dailymotion.com/oauth/token");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var requestString = String.Format("grant_type=password&client_id={0}&client_secret={1}&username={2}&password={3}",
HttpUtility.UrlEncode(ConfigurationManager.AppSettings["Key"]),
HttpUtility.UrlEncode(ConfigurationManager.AppSettings["secret"]),
HttpUtility.UrlEncode(ConfigurationManager.AppSettings["usernameAPI"]),
HttpUtility.UrlEncode(ConfigurationManager.AppSettings["passwordAPI"]));
var requestBytes = Encoding.UTF8.GetBytes(requestString);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
var response = request.GetResponse();
var responseStream = response.GetResponseStream();
string responseString;
using (var reader = new StreamReader(responseStream))
{
responseString = reader.ReadToEnd();
}
var oauthResponse = JsonConvert.DeserializeObject<OAuthResponse>(responseString);
return oauthResponse.access_token;
}
private static void Authorize(string accessToken)
{
var authorizeUrl = String.Format("https://api.dailymotion.com/oauth/authorize?response_type=code&client_id={0}&scope=read+write+manage_videos+delete&redirect_uri={1}",
HttpUtility.UrlEncode(ConfigurationManager.AppSettings["Key"]),
HttpUtility.UrlEncode(ConfigurationManager.AppSettings["callbackurl"]));
Process.Start(authorizeUrl);
var client = new WebClient();
client.Headers.Add("Authorization", "OAuth " + accessToken);
}
Make the Authorize method async like private static async Task Authorize(string accessToken) and insert an await operator like: await Authorize(accessToken);

How to POST data in Dynamics 365 using HttpWebRequest

I have requirement to read data from Dynamics 365 online and to write data as well.
Since my application Target Framework is .Net Core 2.1 so I am unable to use Microsoft.Xrm.Sdk and decided to use Web api instead.
In my code I am using HttpWebRequest with "GET" and "POST" methods, the GET operation works fine and am able to retrieve records from D365 using web api.
When I use the POST operation the code executes properly without any error but when I navigate to D365 entity I do not see any newly created record.
Below is my code
The GetContactDetailsAsync function works fine and returns result but the CreateCaseAsync function is not working
public static async Task<string> GetContactDetailsAsync()
{
string organizationUrl = "https://xxxxx.crmX.dynamics.com";
string clientId = "xxxxxxxx-73aa-xxxx-94cc-8dc7941f6600";
string appKey = "Xxxx81H/7TUFErt5C/xxxxxxxxxxxxxxxxxxxxxxx=";
string aadInstance = "https://login.microsoftonline.com/";
string tenantID = "xxxxxxxx.onmicrosoft.com";
try
{
ClientCredential clientcred = new ClientCredential(clientId, appKey);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
var requestedToken = authenticationResult.AccessToken;
var webRequest = (HttpWebRequest)WebRequest.Create(new Uri("https://xxxxxxxxxx.api.crmx.dynamics.com/api/data/v9.1/contacts()?$select=fullname,contactid,emailaddress1&$filter=mobilephone eq '"+History.userMobile+"'"));
webRequest.KeepAlive = false;
webRequest.ServicePoint.ConnectionLimit = 1;
webRequest.Method = "GET";
webRequest.ContentLength = 0;
webRequest.Headers.Add("Authorization", String.Format("Bearer {0}", requestedToken));
webRequest.Headers.Add("OData-MaxVersion", "4.0");
webRequest.Headers.Add("OData-Version", "4.0");
webRequest.Accept = "application/json";
webRequest.ContentType = "application/json";
//if contact with user provided phone number found, ask for problem description
try
{
using (var response1 = webRequest.GetResponse() as System.Net.HttpWebResponse)
{
using (var reader = new System.IO.StreamReader(response1.GetResponseStream()))
{
var response = reader.ReadToEnd();
}
}
}
catch (Exception ex)
{
History.isUserFound = false;
string error = ex.Message;
return "Sorry, I found that you are not using any of our services...";
}
}
catch (Exception ex) { return ex.ToString(); }
}
public static async void CreateCaseAsync()
{
string organizationUrl = "https://xxxxx.crmX.dynamics.com";
string clientId = "xxxxxxxx-73aa-xxxx-94cc-8dc7941f6600";
string appKey = "Xxxx81H/7TUFErt5C/xxxxxxxxxxxxxxxxxxxxxxx=";
string aadInstance = "https://login.microsoftonline.com/";
string tenantID = "xxxxxxxx.onmicrosoft.com";
//trying to establish connection with D365 here
try
{
ClientCredential clientcred = new ClientCredential(clientId, appKey);
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID);
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
var requestedToken = authenticationResult.AccessToken;
var webRequest = (HttpWebRequest)WebRequest.Create(new Uri("https://xxxxxxxx.api.crmx.dynamics.com/api/data/v9.1/incidents"));
webRequest.KeepAlive = false;
webRequest.ServicePoint.ConnectionLimit = 1;
webRequest.Method = "POST";
webRequest.Headers.Add("Authorization", String.Format("Bearer {0}", requestedToken));
webRequest.Headers.Add("OData-MaxVersion", "4.0");
webRequest.Headers.Add("OData-Version", "4.0");
webRequest.Accept = "application/json";
webRequest.ContentType = "application/json";
string json = "{\"title\":\"title by chat bot\"}";
byte[] byteArray;
byteArray = Encoding.UTF8.GetBytes(json);
webRequest.ContentLength = byteArray.Length;
try
{
Stream requestDataStream = await webRequest.GetRequestStreamAsync();
requestDataStream.Write(byteArray, 0, byteArray.Length);
requestDataStream.Close();
}
catch (Exception ex) { }
}
catch (Exception ex) { }
}
I have tried changing
string json = "{\"title\":\"title by chat bot\"}" to
"{'title':'title by chat bot'}" and "{title:title by chat bot}" as well.
Also I have tried changing
Stream requestDataStream = await webRequest.GetRequestStreamAsync(); to
Stream requestDataStream = webRequest.GetRequestStream(); as well
but nothing worked.
Unable to figure out what I am missing in my code. Any help is highly appriciated.
Actually code looks fine but you should get 400 Bad request exception. Because the json is missing customerid and the basic payload for creating incident should be like below:
{
"title": "title by chat bot",
"customerid_account#odata.bind": "/accounts(f686f062-e542-e811-a955-000d3ab27a43)"
}
You can refer this SO thread for clarity.
Here is the Code for Webapi using Javascript. I just tried below code in my Org and it worked for me.
var entity = {};
entity.title = "CCCCAAAASSSEEEE";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v9.1/incidents(BA8BC3CD-D94F-E911-A82F-000D3A385A1C)", true);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function() {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 204) {
//Success - No Return Data - Do Something
} else {
Xrm.Utility.alertDialog(this.statusText);
}
}
};
req.send(JSON.stringify(entity));
and Below is the link where you could find exactly how to use PATCH method for CRM using c#
https://learn.microsoft.com/en-us/dynamics365/customer-engagement/developer/webapi/web-api-functions-actions-sample-csharp

Rest Post call with Authentication Token

I'm trying to send a Post request to SharePoint Online (Claims Based Auth Site) from my client application (WPF application). In this case it should be an update to a ListItem to change the 'Title' to 'Test'.
I'm retrieving the CookieContainer via MsOnlineClaimsHelper Class
which successfully returns me an auth token.
But when i try to send the request the response is The remote server returned an error: (403) Forbidden.
WebRequest Code
try
{
var claimshelper = new MsOnlineClaimsHelper(baseUrl, _userName, _password);
var request = (HttpWebRequest)WebRequest.Create(baseUrl + "/" + url);
request.CookieContainer = claimshelper.CookieContainer;
request.Method = "POST";
request.Headers.Add("X-HTTP-Method", "MERGE");
request.Headers.Add("If-Match", "*");
request.Accept = "application/json;odata=verbose";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
}
var webResp = request.GetResponse() as HttpWebResponse;
var theData = new StreamReader(webResp.GetResponseStream(), true);
string payload = theData.ReadToEnd();
}
catch (Exception ex)
{
}
Rest Url:
/_api/lists/getbytitle('SampleList')/items(1)
Json Payload:
string json = "{ '__metadata': { 'type': 'SP.Data.SampleListListItem' }, 'Title': 'Test'}";
Error:
The remote server returned an error: (403) Forbidden.
This error occurs since SharePoint 2013 REST service requires the user to include a Request Digest value with each create, update and delete operation. This value is then used by SharePoint to identify non-genuine requests.
How to provide Request Digest value
In MsOnlineClaimsHelper class (MsOnlineClaimsHelper.cs file) add the following method to request Form Digest value:
/// <summary>
/// Request Form Digest value
/// </summary>
/// <returns></returns>
private string GetFormDigest()
{
var endpoint = "/_api/contextinfo";
var request = (HttpWebRequest) WebRequest.Create(_host.AbsoluteUri + endpoint);
request.CookieContainer = new CookieContainer();
request.Method = "POST";
//request.Accept = "application/json;odata=verbose";
request.ContentLength = 0;
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
var result = reader.ReadToEnd();
// parse the ContextInfo response
var resultXml = XDocument.Parse(result);
// get the form digest value
var e = from e in resultXml.Descendants()
where e.Name == XName.Get("FormDigestValue", "http://schemas.microsoft.com/ado/2007/08/dataservices")
select e;
_formDigest = e.First().Value;
}
}
return _formDigest;
}
and FormDigest property:
private string _formDigest;
public string FormDigest
{
get
{
if (_formDigest == null || DateTime.Now > _expires)
{
return GetFormDigest();
}
return _formDigest;
}
}
How to perform an update operation for a ListItem using SharePoint 2013 REST API
The following example demonstrates how to perform an update of a list item using the provided implementation for requesting a Form Digest
Key Points:
X-RequestDigest header is used to specify Form Digest value
Request Content Type have to be specified
Example:
var userName = "username#contoso.onmicrosoft.com";
var password = "password";
var payload = "{ '__metadata': { 'type': 'SP.Data.TasksListItem' }, 'Title': 'New Tasl'}"; //for a Task Item
try
{
var claimshelper = new MsOnlineClaimsHelper(baseUrl, _userName, _password);
var request = (HttpWebRequest)WebRequest.Create(baseUrl + "/" + endpointUrl);
request.CookieContainer = claimshelper.CookieContainer;
request.Headers.Add("X-RequestDigest", claimshelper.FormDigest);
request.Method = "POST";
request.Headers.Add("X-HTTP-Method", "MERGE");
request.Headers.Add("If-Match", "*");
request.Accept = "application/json;odata=verbose";
request.ContentType = "application/json;odata=verbose";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
writer.Write(payload);
writer.Flush();
}
var response = request.GetResponse() as HttpWebResponse;
//...
}
catch (Exception ex)
{
//Error handling goes here..
}

oauth/token returns empty body

I am encountering a problem getting the access_token in client application using oauth.
The returned response has empty body though in API I can see the response is not empty.
tokenresponse = {
"access_token":"[ACCESSTOKENVALUE]",
"token_type":"bearer",
"expires_in":"1200",
"refresh_token":"[REFRESHTOKENVALUE]",
"scope":"[SCOPEVALUE]"
}
The method from API that returns the token http://api.sample.com/OAuth/Token:
public ActionResult Token()
{
OutgoingWebResponse response =
this.AuthorizationServer.HandleTokenRequest(this.Request);
string tokenresponse = string.Format("Token({0})", response!=null?response.Body:""));
return response.AsActionResult();
}
The client method that requests the token is:
public string GetAuthorizationToken(string code)
{
string Url = ServerPath + "OAuth/Token";
string redirect_uri_encode = UrlEncode(ClientPath);
string param = string.Format("code={0}&client_id={1}&client_secret={2}&redirect_uri={3}&grant_type=authorization_code",code, ClientId, ClientSecret, redirect_uri_encode);
HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
string result = null;
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = 10000;
request.Headers.Remove(HttpRequestHeader.Cookie);
var bs = Encoding.UTF8.GetBytes(param);
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (WebResponse response = request.GetResponse())
{
var sr = new StreamReader(response.GetResponseStream());
result = sr.ReadToEnd();
sr.Close();
}
if (!string.IsNullOrEmpty(result))
{
TokenData tokendata = JsonConvert.DeserializeObject<TokenData>(result);
return UpdateAuthorizotionFromToken(tokendata);
}
return null;
}
The result variable is empty.
Please let me know if you have any idea what could cause this. Initially I assumed is because of the cookies so I tried to remove them from request.
Thanks in advance.
Dear just create webclient using following code and you will get json info in tokeninfo.I used it and simply its working perfect.
WebClient client = new WebClient();
string postData = "client_id=" + ""
+ "&client_secret=" + ""
+ "&grant_type=password&username=" + "" //your username
+ "&password=" + "";//your password :)
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
string tokenInfo = client.UploadString(soundCloudTokenRes, postData);
You can then use substring that contains only token from tokeninfo.
To upload tracks on sound cloud.
private void TestSoundCloudupload()
{
System.Net.ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create("https://api.soundcloud.com/tracks") as HttpWebRequest;
//some default headers
request.Accept = "*/*";
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
request.Headers.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
//file array
var files = new UploadFile[] { new UploadFile(Server.MapPath("Downloads//0.mp3"), "track[asset_data]", "application/octet-stream") };
//other form data
var form = new NameValueCollection();
form.Add("track[title]", "Some title");
form.Add("track[sharing]", "public");
form.Add("oauth_token", "");
form.Add("format", "json");
form.Add("Filename", "0.mp3");
form.Add("Upload", "Submit Query");
try
{
using (var response = HttpUploadHelper.Upload(request, files, form))
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
Response.Write(reader.ReadToEnd());
}
}
}
catch (Exception ex)
{
Response.Write(ex.ToString());
}
}

Categories