I am trying to send an email with an attachment using Microsoft Graph Client API. I am getting the below exception:
{"error":{"code":"RequestBodyRead","message":"Cannot read the value '0' as a quoted JSON string value."}}
My code:
public bool SendWithAttachment(string emailSubject, string emailBody, string toEmail, string toName)
{
var token = AcquireToken(AppConstants.TenantId, AppConstants.EmailClientId, AppConstants.EmailClientSecret, AppConstants.UserId, AppConstants.Password);
try
{
byte[] contentBytes = System.IO.File.ReadAllBytes(#"C:\Users\user\Downloads\test\test.png");
string contentType = "image/png";
MessageAttachmentsCollectionPage attachments = new MessageAttachmentsCollectionPage();
attachments.Add(new FileAttachment
{
ODataType = "#microsoft.graph.fileAttachment",
ContentBytes = contentBytes,
ContentType = contentType,
ContentId = "testing",
Name = "testing.png"
});
var recipient = new Recipient
{
EmailAddress = new EmailAddress
{
Address = toEmail,
Name = toName
},
};
var message = new Message
{
Subject = emailSubject,
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = emailBody
},
Attachments = attachments,
ToRecipients = new List<Recipient>() { recipient },
BccRecipients= new List<Recipient>()
};
var body = JsonConvert.SerializeObject(new { message = message });
var client = new RestClient();
var request = new RestRequest($"https://graph.microsoft.com/v1.0/users/{AppConstants.UserId}/sendMail", Method.Post);
request.AddHeader("Content-Type", $"application/json");
request.AddHeader("Authorization", $"Bearer {token}");
request.AddHeader("Cache-Control", $"no-cache");
request.AddParameter("application/json", body, ParameterType.RequestBody);
var restResponse = client.Execute(request);
return restResponse.StatusCode == HttpStatusCode.Accepted;
}
catch (Exception ex)
{
return false;
}
}
The exception seems very irrelevant to me. I think it's pointing to email body content type. Any suggestion would be very helpful.
Using graph SDK may help narrow down the issue like Eric said, since you already had the Bearer token, I think you can try my code below, I can use it to query user information, that why I set a User.ReadWrite permission for access token, but you already had the access token, so just using your token into the code:
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "User.ReadWrite.All" });
var authProvider = new DelegateAuthenticationProvider(async (request) => {
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
});
var graphClient = new GraphServiceClient(authProvider);
var user = await graphClient.Me.Request().GetAsync();
//use this line to send email
await graphClient.Me.SendMail(message, null).Request().PostAsync();
By the way, I used this code to send email without the attachment before, not sure if it could help you...
var jsonStr = JsonSerializer.Serialize(temp);
string token = "your_token";
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await httpClient.PostAsync("https://graph.microsoft.com/v1.0/me/sendMail", new StringContent(jsonStr, Encoding.UTF8, "application/json"));
Related
I have a problem where my POST request returns back a token but when I change my code to use the token and try a GET request, it gives me a "Status:0" message. Am I writing this code wrong? I've tried adding "Bearer " + token to the Authentication.
ErrorException = {"Cannot send a content-body with this verb-type."}
Post:
var client = new RestClient("https://api.box.com/oauth2/token");
RestRequest request = new RestRequest() { Method = Method.Post };
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("client_id", $"{client_ID}");
request.AddParameter("client_secret", $"{client_secret}");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("box_subject_type", "enterprise");
request.AddParameter("box_subject_id", enterpriseID);
var response = await client.ExecuteAsync(request);
var responseMessage = JObject.Parse(response.Content);
GET:
var client2 = new RestClient("https://api.box.com/2.0/files/154072314030");
var request2 = new RestRequest() { Method = Method.Get };
request2.AddHeader("Authorization", token);
request2.AddHeader("Content-Type", "application/json");
var response2 = await client2.ExecuteAsync(request2);
var responseMessage2 = JObject.Parse(response2.Content);
Ended up using their SDK. This is how I was able to login and pull the items in the folder:
BoxFolder folderWithLink = new BoxFolder();
BoxSharedLinkRequest linkRequest = new BoxSharedLinkRequest();
int offset = 0;
int count = 0;
string folderID = "";
//create connection to Box.com
var boxConfig = new BoxConfigBuilder("CLIENT ID", "CLIENT SECRET", "Enterprise ID", "PRIVATE KEY", "PRIVATE KEY PASSWORD", "PUBLIC KEY ID").Build();
var boxJWT = new BoxJWTAuth(boxConfig);
var adminToken = await boxJWT.AdminTokenAsync();
var client = boxJWT.AdminClient(adminToken);
//Get the parent folder information and find the Batch folderID
while (folderID == "")
{
var batches = await client.FoldersManager.GetFolderItemsAsync("FOLDER ID", 250, offset);
foreach (var batchEntry in batches.Entries)
{
Console.Writeline(Batch.Name);
}
I am trying to send a json Object to SalesFroce using HttpClient, but this behaves Weirdly...
First i login in to Salesforce Via following code
var sendPaylod = new Dictionary<string, string>
{
{"grant_type","password"},
{"client_id",s_clientId},
{"client_secret",s_clientSecrate},
{"username",s_username},
{"password",s_password}
};
HttpClient auth = new HttpClient();
HttpContent content = new FormUrlEncodedContent(sendPaylod);
HttpResponseMessage response = await auth.PostAsync(s_tokenRequestEndpointUrl, content);
string msg = await response.Content.ReadAsStringAsync();
Console.WriteLine(msg);
string authToken = (String)jsonObj["access_token"];
Now I have got authToken as a bearer token to send data to salesFroce
I am doing that by Following
var obj = new { Director = "003e000001MQYjB",
CityName = "XXAA",
CityId = "000000",
RegionName = "India",
RegionId = "00000" };
string c_url = "URL to which data will sent";
var c_Obj = JsonConvert.SerializeObject(obj);
var c_content = new System.Net.Http.StringContent(c_Obj, Encoding.UTF8, "application/json");
HttpClient c_client = new HttpClient();
c_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization","Bearer "+authToken);
HttpContent c_content = new StringContent(c_Obj, Encoding.UTF8, "application/json");
c_content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var c_response = await c_client.PostAsync(c_url, content);
var c_msg = await c_response.Content.ReadAsStringAsync();
Now Am getting Following Response...
"status": "success",
"recordId": "",
"message": ""
If i Use Same Bearer Token in Postman and Send same Json Object I receive Following response.
"status": "success",
"recordId": "a16e0000002qV6aE",
"message": ""
Please Help in this matter.
Fix the next errors:
Change:
var c_response = await c_client.PostAsync(c_url, content);
to:
var contentType = new MediaTypeWithQualityHeaderValue("application/json");
c_client.DefaultRequestHeaders.Accept.Add(contentType);
var c_response = await c_client.PostAsync(c_url, c_content);
var c_msg = await c_response.Content.ReadAsStringAsync();
var result =JsonConvert.DeserializeObject<your return class>(c_msg);
and change your authorization to:
c_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken );
I'm trying to replicate an example for calling a web API using RestSharp and I'm running into some issues.
Here is the example
string apiKey = "my key";
string apiSecret = "my secret";
string requestUri = "https://www.cryptopia.co.nz/Api/GetBalance";
var postData = new
{
Currency = "DOT"
};
// Create Request
var request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(requestUri);
request.Content = new ObjectContent(typeof(object), postData, new JsonMediaTypeFormatter());
// Authentication
string requestContentBase64String = string.Empty;
if (request.Content != null)
{
// Hash content to ensure message integrity
using (var md5 = MD5.Create())
{
requestContentBase64String = Convert.ToBase64String(md5.ComputeHash(await request.Content.ReadAsByteArrayAsync()));
}
}
//create random nonce for each request
var nonce = Guid.NewGuid().ToString("N");
//Creating the raw signature string
var signature = Encoding.UTF8.GetBytes(string.Concat(apiKey, HttpMethod.Post, HttpUtility.UrlEncode(request.RequestUri.AbsoluteUri.ToLower()), nonce, requestContentBase64String));
using (var hmac = new HMACSHA256(Convert.FromBase64String(apiSecret)))
{
request.Headers.Authorization = new AuthenticationHeaderValue("amx", string.Format("{0}:{1}:{2}", apiKey, Convert.ToBase64String(hmac.ComputeHash(signature)), nonce));
}
// Send Request
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
//{"Success":true,"Error":null,"Data":[{"CurrencyId":2,"Symbol":"DOT","Total":9646.07411016,"Available":9646.07411016,"Unconfirmed":0.0,"HeldForTrades":0.0,"PendingWithdraw":0.0,"Address":"1HEfio1kreDBgj5uCw4VHbEDSgc6YJXfTN","Status":"OK","StatusMessage":null}]}
}
}
I believe the issue I'm having is that the signature variable isn't being created properly. I'm setting the body of the RestSharp request using
request.AddJsonBody(request.JsonSerializer.Serialize(new { Currency = "DOT" }));
To get the body request.content I'm using
var body = request.Parameters.Where(p => p.Type == ParameterType.RequestBody).FirstOrDefault().Value.ToString();
To get the requestContentBase64String I'm using
var requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
And finally to add the Authorization header I'm using
request.AddHeader("Authorization", $"amx {apiKey}:{requestSignatureBase64String}:{nonce}");
The response from the server is
"Success":false,"Error":"Signature does not match request parameters."
So, because HttpClient is "better," I need to convert WebClient to HttpClient, but it just doesn't work as expected. The following function uses WebClient and works like a charm.
private static void Authenticate()
{
Console.WriteLine("Authenticating . . .");
var clientId = ConfigurationManager.AppSettings["AuthNClientId"];
var uri = ConfigurationManager.AppSettings["AuthNUri"];
var userName = ConfigurationManager.AppSettings["AuthNUserName"];
var password = ConfigurationManager.AppSettings["AuthNPassword"];
var client = new WebClient();
string formData = $"client_id={clientId}&grant_type=password&username={userName}&password={password}";
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
var response = client.UploadString($"{uri}", formData);
dynamic authResult = JsonConvert.DeserializeObject(response);
_accessToken = authResult.access_token;
if (_accessToken == null)
{
throw new ApplicationException("Unable to authenticate. Check your configuration file <appSettings>.");
}
Console.WriteLine("Authenticated.");
}
This code, on the other hand, returns a BadRequest response code.
static async Task<string> GetAuthenticationToken()
{
string token = string.Empty;
var clientId = ConfigurationManager.AppSettings["AuthNClientId"];
var uri = ConfigurationManager.AppSettings["AuthNUri"];
var userName = ConfigurationManager.AppSettings["AuthNUserName"];
var password = ConfigurationManager.AppSettings["AuthNPassword"];
client.BaseAddress = new Uri("https://myurl.com/oauth2/token");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Add("ContentType", "application/x-www-form-urlencoded");
var path = $"client_id={clientId}&grant_type=password&username={userName}&password={password}";
HttpResponseMessage response = await client.GetAsync($"https://myurl.com/oauth2/token?{path}");
if (response.IsSuccessStatusCode)
{
Console.WriteLine("success");
token = await response.Content.ReadAsStringAsync();
}
else { Console.WriteLine($"failure: {response.StatusCode}"); }
return token;
}
You can see that I've tried it a couple of ways, including setting the client BaseAddress as well as just try to pass the url into the GetAsync method.
Anyone see what I'm doing wrong here?
UploadString is a POST method in the first example. In the second example a GET method is being done.
static async Task<string> GetAuthenticationTokenAsync() {
string token = string.Empty;
var clientId = ConfigurationManager.AppSettings["AuthNClientId"];
var uri = ConfigurationManager.AppSettings["AuthNUri"];
var userName = ConfigurationManager.AppSettings["AuthNUserName"];
var password = ConfigurationManager.AppSettings["AuthNPassword"];
var client = new HttpClient();
client.BaseAddress = new Uri(uri);
client.DefaultRequestHeaders.Accept.Clear();
var nameValueCollection = new Distionary<string, string>() {
{ "client_id", clientId },
{ "grant_type", "password" },
{ "username", userName },
{ "password", password },
};
var content = new FormUrlEncodedContent(nameValueCollection);
var response = await client.PostAsync("", content);
if (response.IsSuccessStatusCode) {
Console.WriteLine("success");
var json = await response.Content.ReadAsStringAsync();
dynamic authResult = JsonConvert.DeserializeObject(json);
token = authResult.access_token;
}
else { Console.WriteLine($"failure: {response.StatusCode}"); }
return token;
}
I'm trying to use the below code but for some reason I'm getting an invalid or expired token it seemed to work once but never again.
Any ideas? (consumerKey and consumerSecret are constants generated in the class.)
public ActionResult Index()
{
string twitterAccount = System.Configuration.ConfigurationManager.AppSettings["twitterAccount"];
JsonDeserializer jsonDeserializer = new JsonDeserializer();
var model = new TwitterVM.LandingModel();
var qs = GetToken();
string oauthToken = qs["oauth_token"];
string oauthTokenSecret = qs["oauth_token_secret"];
RestClient client = new RestClient("https://api.twitter.com/1.1")
{
Authenticator = OAuth1Authenticator.ForProtectedResource(consumerKey, consumerSecret, oauthToken, oauthTokenSecret)
};
RestRequest request = new RestRequest("statuses/user_timeline", Method.GET);
request.Parameters.Add(new Parameter()
{
Name = "screen_name",
Value = twitterAccount,
Type = ParameterType.GetOrPost
});
request.Parameters.Add(new Parameter()
{
Name = "count",
Value = 10,
Type = ParameterType.GetOrPost
});
request.Parameters.Add(new Parameter()
{
Name = "include_rts",
Value = true,
Type = ParameterType.GetOrPost
});
request.Parameters.Add(new Parameter()
{
Name = "include_entities",
Value = true,
Type = ParameterType.GetOrPost
});
IRestResponse response = client.Execute(request);
model.Tweets =
jsonDeserializer.Deserialize<List<TwitterVM.Tweet>>(response);
return View(model);
}
private NameValueCollection GetToken()
{
RestClient client = new RestClient("https://api.twitter.com") { Authenticator = OAuth1Authenticator.ForRequestToken(consumerKey, consumerSecret) };
//Do the auth shit...
RestRequest request = new RestRequest("oauth/request_token", Method.POST);
IRestResponse response = client.Execute(request);
return HttpUtility.ParseQueryString(response.Content);
}
Using Twitter's OAuth2 API (https://api.twitter.com/oauth2/token)
See https://dev.twitter.com/oauth/application-only for details....
var client = await CreateHttpClient("....", "....");
//don't dispose this client and use for subsequent API calls
var screenName = "....";
var count = 10;
var include_rts = true;
var url = $"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name={screenName}&include_rts={include_rts}&count={count}";
var json = await client.GetStringAsync(url);
public static async Task<HttpClient> CreateHttpClient(string consumerKey, string consumerSecret)
{
var bearerToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(consumerKey + ":" + consumerSecret));
string url = "https://api.twitter.com/oauth2/token";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Basic " + bearerToken);
var resp = await client.PostAsync(url, new StringContent("grant_type=client_credentials", Encoding.UTF8, "application/x-www-form-urlencoded")).ConfigureAwait(false);
resp.EnsureSuccessStatusCode();
var result = await resp.Content.ReadAsStringAsync().ConfigureAwait(false);
var jObj = new JavaScriptSerializer().Deserialize<Dictionary<string,string>>(result);
if (jObj["token_type"] != "bearer") throw new Exception("Invalid Response From Twitter/OAuth");
client.DefaultRequestHeaders.Remove("Authorization");
client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Bearer " + jObj["access_token"]);
return client;
}