The exaple code from google is
static string[] Scopes = { SheetsService.Scope.SpreadsheetsReadonly };
static string ApplicationName = "Google Sheets API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.CurrentDirectory;
credPath = Path.Combine(credPath, "../.credentials/sheets.googleapis.com-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Google Sheets API service.
var service = new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// continuing
my attempt to translate it into f# is (link)
[<EntryPoint>]
let main argv =
let Scopes = [| SheetsService.Scope.SpreadsheetsReadonly |]
let ApplicationName = "Google Sheets API .NET Quickstart"
let credPath = Path.Combine(System.Environment.CurrentDirectory,
"../.credentials/sheets.googleapis.com-dotnet-quickstart.json")
use stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read)
let credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result
let service = new SheetsService(new BaseClientService.Initializer(),
ApplicationName = ApplicationName,
HttpClientInitializer = credential)
it fails with the error message
Method 'set_ApplicationName' is not accessible from this code location fsheets C:\db\code\visualstudio\fbsol\fsheets\Program.fs 30
I have the project with running c# and my f# on https://github.com/fbehrens/fbsol.git
What am I missing. How does this translate correctly ?
I think the issue is that you are passing in ApplicationName and HttpClientInitializer and parameters into the constructor of SheetsService. The C# code instead passes in those parameters in the constructor of the BaseClientService. This is how you might do it in F#.
let baseService = new BaseClientService.Initializer()
baseService.ApplicationName <- ApplicationName
baseService.HttpClientInitializer <- credential
let service = new SheetsService(baseService)
Related
I wrote a dll using .NET C# that was supposed to send emails using graph API.
When I'm using the dll from a console application - everything works as expected: if the user is logged in the mail is sent, and if not - a screen pops up to connect.
But, when I try to use the same dll in WinForms, the program stuck.
Any idea why?
This is my code:
var options = new PublicClientApplicationOptions {
ClientId = clientId,
TenantId = tenantId,
RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient",
};
if (application == null) {
application = PublicClientApplicationBuilder.CreateWithApplicationOptions(options).WithAuthority(AzureCloudInstance.AzurePublic, ClientSecretOrTenantId).Build();
}
string token = "";
GraphServiceClient graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(async(requestMessage) =>{
token = await GetToken();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}));
Recipient recipient = new Recipient();
recipient.EmailAddress = new EmailAddress();
recipient.EmailAddress.Address = toAddress;
List < Recipient > recipients = new List < Recipient > ();
recipients.Add(recipient);
var message = new Message {
Subject = subject,
Body = new ItemBody {
ContentType = isHtml ? BodyType.Html: BodyType.Text,
Content = bodyText,
},
ToRecipients = recipients,
};
try {
await graphServiceClient.Me.SendMail(message, false).Request().PostAsync(); // get stuck here
} catch(ServiceException) {
graphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider(async(requestMessage) =>{
token = await GetToken();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}));
await graphServiceClient.Me.SendMail(message, false).Request().PostAsync();
}
I'd hazard a guess that you're trying to make the asynchronous method synchronous by calling SendEmailAsync(email).Wait() in your (button click?) event handler, which is causing a WinForms UI thread lock.
The solution is to mark your event handler as async void and await your method in the event handler code.
We have a solution today where we use EWS's basic authentication (username and password) with .net Core 2.1, and it works. The problem is that basic authentication will expire in 2020. Therefore, we will transition to the OAuth solution that will work after 2020.
We have tried multiple solutions for this problem, including this: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth, but some of the methods have been updated (AcquireToken -> AcquireTokenAsync).
It's important that the authentication against azure is not client-based, since everything will happen in backend (web api).
Does anyone have a solution to this problem?
This is our current solution:
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
service.Credentials = new WebCredentials(<email>, <password>);
service.TraceEnabled = true;
service.TraceFlags = TraceFlags.All;
service.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
This is an example of what we have tried:
public class Program
{
public static void Run()
{
//tried this as well: string authority = "https://login.windows.net/<devAccountName>.onmicrosoft.com";
string authority = "https://login.microsoftonline.com/<tenantId>/OAuth2/Token";
string clientId = "<clientId>"; // Application ID from Azure
Uri clientAppUri = new Uri("http://localhost:55424/");
Uri resourceHostUri = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
AuthenticationResult authenticationResult = null;
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
string errorMessage = null;
try
{
Console.WriteLine("Trying to acquire token");
PlatformParameters platformParams = new PlatformParameters(PromptBehavior.Auto);
authenticationResult = authenticationContext.AcquireTokenAsync("https://outlook.office365.com/EWS/Exchange.asmx", clientId, clientAppUri, platformParams).Result;
}
catch (AdalException ex)
{
errorMessage = ex.Message;
if (ex.InnerException != null)
{
errorMessage += "\nInnerException : " + ex.InnerException.Message;
}
}
catch (ArgumentException ex)
{
errorMessage = ex.Message;
}
if (!string.IsNullOrEmpty(errorMessage))
{
Console.WriteLine("Failed: {0}" + errorMessage);
return;
}
Console.WriteLine("\nMaking the protocol call\n");
ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2013);
exchangeService.Url = resourceHostUri;
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.Credentials = new OAuthCredentials(authenticationResult.AccessToken);
exchangeService.FindFolders(WellKnownFolderName.Root, new FolderView(10));
}
}
We receive this error message after we log in:
AADSTS50001: The application named
https://outlook.office365.com/EWS/Exchange.asmx was not found in the tenant named <tenantId>. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant.
I am getting the error
An unhandled exception of type 'Google.GoogleApiException' occurred in mscorlib.dll Additional information: Google.Apis.Requests.RequestError
The caller does not have permission [403]
Errors [ Message[The caller does not have permission] Location[ - ] Reason[forbidden] Domain[global] ]
or
Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.
See https://developers.google.com/identity/sign-in/web/devconsole-project. [401]
please let me know what i need to edit
string AccountFilePath = #"C:\GFApps\My App\Google Service\ServiceAccount\Json\CREG Service-427e7b31069c.json";
string AccountEmail = "cregadmin#creg-service.iam.gserviceaccount.com";
string AccountAdminUser = "googleIntegration.NET#domain.com";
string UserToImpersonate = null;
ServiceAccountCredential credential;
var credentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(File.ReadAllText(AccountFilePath));
using (var stream = new FileStream(AccountFilePath, FileMode.Open, FileAccess.Read)) {
credential = ServiceAccountCredential.FromServiceAccountData(stream);
}
var credentialforuser = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(AccountEmail) {
Scopes = Scopes,
User = string.IsNullOrEmpty(UserToImpersonate) ? AccountAdminUser : UserToImpersonate,
Key = credential.Key
} .FromPrivateKey(credentialParameters.PrivateKey));
Console.WriteLine("read from spread sheet ");
// Create Google Sheets API service.
var service = new SheetsService(new BaseClientService.Initializer() {
HttpClientInitializer = credentialforuser,
ApplicationName = ApplicationName,
});
// Define request parameters.
String spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
// String spreadsheetId = "1nWdSM90mG7qT8YcOucHc_3NdmLYLpZd3FPJOF4lXMhY";
String range = "Class Data!A2:E";
SpreadsheetsResource.ValuesResource.GetRequest request =
service.Spreadsheets.Values.Get(spreadsheetId, range);
// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
ValueRange response = request.Execute();
IList<IList<Object>> values = response.Values;
if (values != null && values.Count > 0) {
Console.WriteLine("Name, Major");
foreach (var row in values) {
// Print columns A and E, which correspond to indices 0 and 4.
Console.WriteLine("{0}, {1}", row[0], row[4]);
}
} else {
Console.WriteLine("No data found.");
}
You appear to be using a service account. Service accounts need to be pre authorized. Useing the service account email address share your sheet with the service account like you would any other user it will then have access to see your sheet
/// <summary>
/// Authenticating to Google using a Service account
/// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
/// </summary>
/// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
/// <param name="serviceAccountCredentialFilePath">Location of the .p12 or Json Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
/// <returns>AnalyticsService used to make requests against the Analytics API</returns>
public static SheetsService AuthenticateServiceAccount(string serviceAccountEmail, string serviceAccountCredentialFilePath, string[] scopes) {
try
{
if (string.IsNullOrEmpty(serviceAccountCredentialFilePath))
throw new Exception("Path to the service account credentials file is required.");
if (!File.Exists(serviceAccountCredentialFilePath))
throw new Exception("The service account credentials file does not exist at: " + serviceAccountCredentialFilePath);
if (string.IsNullOrEmpty(serviceAccountEmail))
throw new Exception("ServiceAccountEmail is required.");
// For Json file
if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".json")
{
GoogleCredential credential;
using (var stream = new FileStream(serviceAccountCredentialFilePath, FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream).CreateScoped(scopes);
}
// Create the Analytics service.
return new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Sheets Service account Authentication Sample",
});
}
else if (Path.GetExtension(serviceAccountCredentialFilePath).ToLower() == ".p12")
{ // If its a P12 file
var certificate = new X509Certificate2(serviceAccountCredentialFilePath, "notasecret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scopes
} .FromCertificate(certificate));
// Create the Sheets service.
return new SheetsService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Sheets Authentication Sample",
});
}
else
{
throw new Exception("Unsupported Service accounts credentials.");
}
}
catch (Exception ex)
{
throw new Exception("CreateServiceAccountSheetsFailed", ex);
}
}
link to the above sample https://github.com/LindaLawton/Google-Dotnet-Samples/blob/master/Samples/Google%20Sheets%20API/v4/ServiceAccount.cs
Here is my code. It's been over a month I'm trying to add calendars in Outlook but nothing is working :( please help. The function AcquireTokenByAuthorizationCodeAsync never completes. And the token.Result is always null
string authority = ConfigurationManager.AppSettings["authority"];
string clientID = ConfigurationManager.AppSettings["clientID"];
Uri clientAppUri = new Uri(ConfigurationManager.AppSettings["clientAppUri"]);
string serverName = ConfigurationManager.AppSettings["serverName"];
var code = Request.Params["code"];
AuthenticationContext ac = new AuthenticationContext(authority, true);
ClientCredential clcred = new ClientCredential(clientid, secretkey);
//ac = ac.AcquireToken(serverName, clientID, clientAppUri, PromptBehavior.Auto);
//string to = ac.AcquireToken(serverName, clientID, clientAppUri, PromptBehavior.Auto).AccessToken;
var token = ac.AcquireTokenByAuthorizationCodeAsync(code, new Uri("http://localhost:2694/GetAuthCode/Index/"), clcred, resource: "https://graph.microsoft.com/");
string newtoken = token.Result.AccessToken;
ExchangeService exchangeService = new ExchangeService(ExchangeVersion.Exchange2013);
exchangeService.Url = new Uri("https://outlook.office365.com/" + "ews/exchange.asmx");
exchangeService.TraceEnabled = true;
exchangeService.TraceFlags = TraceFlags.All;
exchangeService.Credentials = new OAuthCredentials(token.Result.AccessToken);
exchangeService.FindFolders(WellKnownFolderName.Root, new FolderView(10));
Appointment app = new Appointment(exchangeService);
app.Subject = "";
app.Body = "";
app.Location = "";
app.Start = DateTime.Now;
app.End = DateTime.Now.AddDays(1);
app.Save(SendInvitationsMode.SendToAllAndSaveCopy);
I have experienced this issue when I call the AcquireTokenByAuthorizationCodeAsync using result instead of using await key words and all these code was in a asynchronously controller in the MVC.
If you are in the same scenario, you can fix this issue by two ways:
1.Always using the async, await like code below:
public async System.Threading.Tasks.Task<ActionResult> About()
{
...
var result =await ac.AcquireTokenByAuthorizationCodeAsync(code, new Uri("http://localhost:2694/GetAuthCode/Index/"), clcred, resource: "https://graph.microsoft.com/");
var accessToken = result.AccessToken;
...
}
2.Use the synchronization controller:
public void About()
{
...
var result =ac.AcquireTokenByAuthorizationCodeAsync(code, new Uri("http://localhost:2694/GetAuthCode/Index/"), clcred, resource: "https://graph.microsoft.com/").Result;
var accessToken = result.AccessToken;
...
}
I have problem with executing chained payment after obtaining permission from user. I have no troubles to get Access Token and Access Token Secret.
The code should work this way: User (personal type sandbox account) authorizes primary receiver (business type sandbox account) to take money from his account.
Primary receiver sends a part of the sum to the second receiver.
The code is written in ASP.NET MVC but I suppose it has nothing to do with the framework, I'm using PayPalAdaptivePaymentsSDK and PayPalPermissionsSDK
I want to use it in sandbox environment for testing.
I assume it has something to do with application id, I would be very grateful for step-by-step explanation
Here's how I obtain all my credentials:
I login into my developer account.
account1.Username, account1.Password, account1.Signature
- sandbox -> accounts -> I select primary receiver of the payment (business type account) -> API Credentials
applicationId - "APP-80W284485P519543T"
In the config file I specified mode as "sandbox".
I use the same config for executing the payment.
Then I want to execute following code and in payResponse I get errorId 520003 "Authentication failed. API credentials are incorrect."
public class PermissionController : Controller
{
private AdaptivePaymentsService _adaptivePaymentService;
public ActionResult Index()
{
ViewBag.AccessToken = PayPalConfig.AccessToken;
ViewBag.AccessTokenSecret = PayPalConfig.AccessTokenSecret;
return View();
}
public PermissionController()
{
_adaptivePaymentService = new AdaptivePaymentsService(PayPalConfig.GetConfig());
}
public ActionResult GetPermission()
{
RequestPermissionsRequest rp = new RequestPermissionsRequest();
rp.scope = new List<string>();
rp.scope.Add("EXPRESS_CHECKOUT");
Dictionary<string, string> config = PayPalConfig.GetConfig();
rp.callback = "http://localhost:42072/Permission/GetAccessToken";
rp.requestEnvelope = new PayPal.Permissions.Model.RequestEnvelope("en_US");
RequestPermissionsResponse rpr = null;
PermissionsService service = new PermissionsService(config);
rpr = service.RequestPermissions(rp);
string confirmPermissions = "https://www.sandbox.paypal.com/webscr&cmd=_grant-permission&request_token=" + rpr.token;
return Redirect(confirmPermissions);
}
public ActionResult GetAccessToken()
{
Uri uri = Request.Url;
Dictionary<string, string> config = PayPalConfig.GetConfig();
var gat = new GetAccessTokenRequest();
gat.token = HttpUtility.ParseQueryString(uri.Query).Get("request_token");
gat.verifier = HttpUtility.ParseQueryString(uri.Query).Get("verification_code");
gat.requestEnvelope = new PayPal.Permissions.Model.RequestEnvelope("en_US");
GetAccessTokenResponse gats = null;
var service = new PermissionsService(config);
gats = service.GetAccessToken(gat);
_adaptivePaymentService.SetAccessToken(gats.token);
_adaptivePaymentService.SetAccessTokenSecret(gats.tokenSecret);
PayPalConfig.AccessToken = _adaptivePaymentService.getAccessToken();
PayPalConfig.AccessTokenSecret = _adaptivePaymentService.getAccessTokenSecret();
return RedirectToAction("Index");
}
public ActionResult ChainedPayment()
{
ReceiverList receiverList = new ReceiverList();
receiverList.receiver = new List<Receiver>();
Receiver secondaryReceiver = new Receiver(1.00M);
secondaryReceiver.email = "mizerykordia6662-facilitator#gmail.com";
receiverList.receiver.Add(secondaryReceiver);
Receiver primaryReceiver = new Receiver(5.00M);
primaryReceiver.email = "mizTestMerchant#test.com";
primaryReceiver.primary = true;
receiverList.receiver.Add(primaryReceiver);
PayPal.AdaptivePayments.Model.RequestEnvelope requestEnvelope = new PayPal.AdaptivePayments.Model.RequestEnvelope("en_US");
string actionType = "PAY";
string returnUrl = "http://localhost:42072/Home/Index";
string cancelUrl = "https://devtools-paypal.com/guide/ap_chained_payment/dotnet?cancel=true";
string currencyCode = "USD";
_adaptivePaymentService.SetAccessToken(PayPalConfig.AccessToken);
_adaptivePaymentService.SetAccessTokenSecret(PayPalConfig.AccessTokenSecret);
PayRequest payRequest = new PayRequest(requestEnvelope, actionType,
cancelUrl, currencyCode, receiverList, returnUrl);
// it breaks here
PayResponse payResponse = _adaptivePaymentService.Pay(payRequest);
PaymentDetailsRequest paymentDetailsRequest = new PaymentDetailsRequest(new PayPal.AdaptivePayments.Model.RequestEnvelope("en-US"));
paymentDetailsRequest.payKey = payResponse.payKey;
SetPaymentOptionsRequest paymentOptions = new SetPaymentOptionsRequest()
{ payKey = payResponse.payKey };
_adaptivePaymentService.SetPaymentOptions(paymentOptions);
PaymentDetailsResponse paymentDetailsRespons = _adaptivePaymentService.PaymentDetails(paymentDetailsRequest);
ExecutePaymentRequest exec = new ExecutePaymentRequest(new PayPal.AdaptivePayments.Model.RequestEnvelope("en-US"), paymentDetailsRequest.payKey);
ExecutePaymentResponse response = _adaptivePaymentService.ExecutePayment(exec);
return RedirectToAction("Index");
}
}