I have an application of my client in which he has used PaypalAdaptivePayments but the API stopped working since 2 years back, now this project is within my hands so I started investigating the API and found that PayPal has deprecated the usage of this API, actually in his application what he tends to have is this:
1- There is only 1 account of this Vendor in PayPal in which the amount debits and credits from the application.
2- Basically this application is sort of Ride booking web app, in which the customer books a ride and then deposits X amount into the wallet (remember this wallet is connected to the vendor account I have mentioned in point 1).
3- When the customer ride is completed he marks the amount as to be cleared for DEBIT, then this decision is saved into my database but till this stage the driver is not reimbursed.
4- The ADMIN logs in to this site and then he goes to the drivers list and then select an appropriate driver and then he puts in his X COMMISSION for this ride, and then clicks on PAY so with this action the driver gets paid. Note: This is a commission based procedure so for example the RIDE which an customer has booked was of USD100 so he credited this amount into the VENDORS wallet, then when the VENDOR is about to lend payment to the DRIVER he enters his own commission for e.g. 10%, so the DRIVER would be paid USD90 only. This payment is also deducted from the VENDORS wallet and then transferred to the DRIVER.
Now after painting the scenario, can you please guide me which API is best suited for this scenario? as there are LOADS of PayPal API and SDK .... I am totally lost in their world, Please keep in mind my application is build in ASP.NET MVC.
Please note:
My Client(Vendor) already owns a SANDBOX and a verified BUSINESS ACCOUNT in PayPal.
Warm Regards.
Emad.
For community ease I am sharing my code:
using Classes;
using EFare.Classes;
using PayPalMvc;
using PayPalMvc.Enums;
using SampleMVC3WebApplication.Models;
using SampleMVC3WebApplication.Services;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Web;
using System.Web.Mvc;
namespace SampleMVC3WebApplication
{
public class WebUILogging
{
// Add your favourite logger here
public static void LogMessage(string message)
{
DoTrace(message);
}
public static void LogLongMessage(string message, string longMessage)
{
DoTrace(message);
DoTrace(longMessage);
}
public static void LogException(string message, Exception ex)
{
DoTrace(message);
DoTrace(ex.Message);
DoTrace(ex.StackTrace);
}
private static void DoTrace(string message)
{
Trace.WriteLine(DateTime.Now + " - " + message);
}
}
}
namespace SampleMVC3WebApplication.Services
{
public interface ITransactionService
{
SetExpressCheckoutResponse SendPayPalSetExpressCheckoutRequest(ApplicationCart cart, string serverURL,
string userEmail = null);
GetExpressCheckoutDetailsResponse SendPayPalGetExpressCheckoutDetailsRequest(string token);
DoExpressCheckoutPaymentResponse SendPayPalDoExpressCheckoutPaymentRequest(ApplicationCart cart, string token,
string payerId);
}
/// <summary>
/// The Transaction Service is used to transform a purchase object (eg cart, basket, or single item) into a sale
/// request with PayPal (in this case a cart)
/// It also allows your app to store the transactions in your database (create a table to match the PayPalTransaction
/// model)
/// You should copy this file into your project and modify it to accept your purchase object, store PayPal transaction
/// responses in your database,
/// as well as log events with your favourite logger.
/// </summary>
public class TransactionService : ITransactionService
{
private readonly ITransactionRegistrar _payPalTransactionRegistrar = new TransactionRegistrar();
public SetExpressCheckoutResponse SendPayPalSetExpressCheckoutRequest(ApplicationCart cart, string serverURL,
string userEmail = null)
{
try
{
WebUILogging.LogMessage("SendPayPalSetExpressCheckoutRequest");
// Optional handling of cart items: If there is only a single item being sold we don't need a list of expressCheckoutItems
// However if you're selling a single item as a sale consider also adding it as an ExpressCheckoutItem as it looks better once you get to PayPal's site
// Note: ExpressCheckoutItems are currently NOT stored by PayPal against the sale in the users order history so you need to keep your own records of what items were in a cart
List<ExpressCheckoutItem> expressCheckoutItems = null;
if (cart.Items != null)
{
expressCheckoutItems = new List<ExpressCheckoutItem>();
foreach (var item in cart.Items)
expressCheckoutItems.Add(new ExpressCheckoutItem(item.Quantity, item.Price, item.Name,
item.Description));
}
var response = _payPalTransactionRegistrar.SendSetExpressCheckout(cart.Currency, cart.TotalPrice,
cart.PurchaseDescription, cart.Id.ToString(), serverURL, expressCheckoutItems, userEmail);
// Add a PayPal transaction record
var transaction = new PayPalTransaction
{
RequestId = response.RequestId,
TrackingReference = cart.Id.ToString(),
RequestTime = DateTime.Now,
RequestStatus = response.ResponseStatus.ToString(),
TimeStamp = response.TIMESTAMP,
RequestError = response.ErrorToString,
Token = response.TOKEN
};
// Store this transaction in your Database
return response;
}
catch (Exception ex)
{
WebUILogging.LogException(ex.Message, ex);
}
return null;
}
public GetExpressCheckoutDetailsResponse SendPayPalGetExpressCheckoutDetailsRequest(string token)
{
try
{
WebUILogging.LogMessage("SendPayPalGetExpressCheckoutDetailsRequest");
var response = _payPalTransactionRegistrar.SendGetExpressCheckoutDetails(token);
// Add a PayPal transaction record
var transaction = new PayPalTransaction
{
RequestId = response.RequestId,
TrackingReference = response.TrackingReference,
RequestTime = DateTime.Now,
RequestStatus = response.ResponseStatus.ToString(),
TimeStamp = response.TIMESTAMP,
RequestError = response.ErrorToString,
Token = response.TOKEN,
PayerId = response.PAYERID,
RequestData = response.ToString
};
// Store this transaction in your Database
return response;
}
catch (Exception ex)
{
WebUILogging.LogException(ex.Message, ex);
}
return null;
}
public DoExpressCheckoutPaymentResponse SendPayPalDoExpressCheckoutPaymentRequest(ApplicationCart cart,
string token, string payerId)
{
try
{
WebUILogging.LogMessage("SendPayPalDoExpressCheckoutPaymentRequest");
var response =
_payPalTransactionRegistrar.SendDoExpressCheckoutPayment(token, payerId, cart.Currency,
cart.TotalPrice);
// Add a PayPal transaction record
var transaction = new PayPalTransaction
{
RequestId = response.RequestId,
TrackingReference = cart.Id.ToString(),
RequestTime = DateTime.Now,
RequestStatus = response.ResponseStatus.ToString(),
TimeStamp = response.TIMESTAMP,
RequestError = response.ErrorToString,
Token = response.TOKEN,
RequestData = response.ToString,
PaymentTransactionId = response.PaymentTransactionId,
PaymentError = response.PaymentErrorToString
};
// Store this transaction in your Database
return response;
}
catch (Exception ex)
{
WebUILogging.LogException(ex.Message, ex);
}
return null;
}
}
}
namespace SampleMVC3WebApplication.Controllers
{
public class PurchaseController : Controller
{
private readonly TransactionService transactionService = new TransactionService();
private bool checkcustomerid(string uid)
{
var dl = new AccountDataLayer();
var ds = dl.Inline_Process("select UserId from dbo.Login_Table where UserId='" + uid +
"' and UType='customer'");
return ds.Tables[0].Rows.Count > 0;
}
#region Set Express Checkout and Get Checkout Details
public ActionResult PayPalExpressCheckout()
{
WebUILogging.LogMessage("Express Checkout Initiated");
// SetExpressCheckout
var cart = (ApplicationCart)Session["Cart"];
var serverURL = HttpContext.Request.Url.GetLeftPart(UriPartial.Authority) +
VirtualPathUtility.ToAbsolute("~/");
var transactionResponse =
transactionService.SendPayPalSetExpressCheckoutRequest(cart, serverURL);
// If Success redirect to PayPal for user to make payment
if (transactionResponse == null || transactionResponse.ResponseStatus != ResponseType.Success)
{
SetUserNotification(
"Sorry there was a problem with initiating a PayPal transaction. Please try again and contact an Administrator if this still doesn't work.");
var errorMessage = transactionResponse == null
? "Null Transaction Response"
: transactionResponse.ErrorToString;
WebUILogging.LogMessage(
"Error initiating PayPal SetExpressCheckout transaction. Error: " + errorMessage);
return RedirectToAction("Error", "Purchase");
}
return Redirect(string.Format(PayPalMvc.Configuration.Current.PayPalRedirectUrl,
transactionResponse.TOKEN));
}
public ActionResult
PayPalExpressCheckoutAuthorisedSuccess(string token,
string PayerID) // Note "PayerID" is returned with capitalisation as written
{
// PayPal redirects back to here
WebUILogging.LogMessage("Express Checkout Authorised");
// GetExpressCheckoutDetails
TempData["token"] = token;
TempData["payerId"] = PayerID;
var transactionResponse =
transactionService.SendPayPalGetExpressCheckoutDetailsRequest(token);
if (transactionResponse == null || transactionResponse.ResponseStatus != ResponseType.Success)
{
SetUserNotification(
"Sorry there was a problem with initiating a PayPal transaction. Please try again and contact an Administrator if this still doesn't work.");
var errorMessage = transactionResponse == null
? "Null Transaction Response"
: transactionResponse.ErrorToString;
WebUILogging.LogMessage("Error initiating PayPal GetExpressCheckoutDetails transaction. Error: " +
errorMessage);
return RedirectToAction("Error", "Purchase");
}
return RedirectToAction("ConfirmPayPalPayment");
}
#endregion Set Express Checkout and Get Checkout Details
#region Confirm Payment
public ActionResult ConfirmPayPalPayment()
{
WebUILogging.LogMessage("Express Checkout Confirmation");
var cart = (ApplicationCart)Session["Cart"];
return View(cart);
}
[HttpPost]
public ActionResult ConfirmPayPalPayment(bool confirmed = true)
{
WebUILogging.LogMessage("Express Checkout Confirmed");
var cart = (ApplicationCart)Session["Cart"];
// DoExpressCheckoutPayment
var token = TempData["token"].ToString();
var payerId = TempData["payerId"].ToString();
var transactionResponse =
transactionService.SendPayPalDoExpressCheckoutPaymentRequest(cart, token, payerId);
if (transactionResponse == null || transactionResponse.ResponseStatus != ResponseType.Success)
{
if (transactionResponse != null && transactionResponse.L_ERRORCODE0 == "10486")
{ // Redirect user back to PayPal in case of Error 10486 (bad funding method)
// https://www.x.com/developers/paypal/documentation-tools/how-to-guides/how-to-recover-funding-failure-error-code-10486-doexpresscheckout
WebUILogging.LogMessage("Redirecting User back to PayPal due to 10486 error (bad funding method - typically an invalid or maxed out credit card)");
return Redirect(string.Format(PayPalMvc.Configuration.Current.PayPalRedirectUrl, token));
}
else
{
SetUserNotification(
"Sorry there was a problem with taking the PayPal payment, so no money has been transferred. Please try again and contact an Administrator if this still doesn't work.");
var errorMessage = transactionResponse == null
? "Null Transaction Response"
: transactionResponse.ErrorToString;
WebUILogging.LogMessage("Error initiating PayPal DoExpressCheckoutPayment transaction. Error: " +
errorMessage);
return RedirectToAction("Error", "Purchase");
}
}
if (transactionResponse.PaymentStatus == PaymentStatus.Completed)
return RedirectToAction("PostPaymentSuccess");
// Something went wrong or the payment isn't complete
WebUILogging.LogMessage("Error taking PayPal payment. Error: " + transactionResponse.ErrorToString +
" - Payment Error: " + transactionResponse.PaymentErrorToString);
TempData["TransactionResult"] = transactionResponse.PAYMENTREQUEST_0_LONGMESSAGE;
return RedirectToAction("PostPaymentFailure");
}
#endregion Confirm Payment
#region Post Payment and Cancellation
public ActionResult PostPaymentSuccess()
{
WebUILogging.LogMessage("Post Payment Result: Success");
var cart = (ApplicationCart)Session["Cart"];
ViewBag.TrackingReference = cart.Id;
ViewBag.Description = cart.PurchaseDescription;
ViewBag.TotalCost = cart.TotalPrice;
ViewBag.Currency = cart.Currency;
var dl = new Customer();
var amt = "";
var date = "";
;
var time = "";
var EFareloginCookie = Request.Cookies["Efarelogin_Cookies"];
if (EFareloginCookie != null)
if (checkcustomerid(EFareloginCookie["UserId"]))
{
amt = cart.TotalPrice.ToString();
date = DateTime.Now.ToString("yyyy-MM-dd");
time = DateTime.Now.ToString("hh:mm:ss");
var i = dl.addMoney(EFareloginCookie["UserId"], amt, date, time);
if (i > 0)
{
TempData["WalletSuccess"] = "Data saved successfully.";
//return RedirectToAction("Wallet", "Account");
ModelState.Clear();
}
else
{
TempData["Walleterror"] = "Opps something is wrong.";
}
}
return View();
}
public ActionResult PostPaymentFailure()
{
WebUILogging.LogMessage("Post Payment Result: Failure");
ViewBag.ErrorMessage = TempData["TransactionResult"];
return View();
}
public ActionResult CancelPayPalTransaction()
{
return View();
}
#endregion Post Payment and Cancellation
#region Transaction Error
private void SetUserNotification(string notification)
{
TempData["ErrorMessage"] = notification;
}
public ActionResult Error()
{
ViewBag.ErrorMessage = TempData["ErrorMessage"];
return View();
}
#endregion Transaction Error
}
}
Use PayPal Checkout for receiving money: https://developer.paypal.com/docs/checkout/ --- for a server-based API integration see the front-end UI at https://developer.paypal.com/demo/checkout/#/pattern/server
Request access to Payouts for sending money: https://developer.paypal.com/docs/payouts/integrate/prerequisites/#get-access-to-paypal-payouts
Related
I'm implementing an annual subscription for my web app in java. So I first create a customer using the following code :
public Customer createCustomer() {
Stripe.apiKey = key;
Customer customer = null;
CustomerCreateParams params =
CustomerCreateParams
.builder()
.setEmail(this.person.getEmail())
.setPaymentMethod("pm_card_visa")
.setInvoiceSettings(
CustomerCreateParams.InvoiceSettings
.builder()
.setDefaultPaymentMethod("pm_card_visa")
.build()
).build();
try {
customer = Customer.create(params);
this.personService.update(customer.getId(), person);
subscribe(customer);
}catch (StripeException ex) {
System.out.println(ex.getMessage());
}
return customer;
}
and then I subscribe to a service with the price specified
public void subscribe(Customer customer) throws StripeException {
Stripe.apiKey = key;
List<Object> phases = new ArrayList<>();
List<Object> items = new ArrayList<>();
Map<String, Object> item1 = new HashMap<>();
item1.put(
"price",
"price_1KYAvqCLVCGN5jA7yGSJzUam"
);
item1.put("quantity", 1);
items.add(item1);
Map<String, Object> phase1 = new HashMap<>();
phase1.put("items", items);
phase1.put("iterations", 12);
phases.add(phase1);
Map<String, Object> params = new HashMap<>();
params.put("customer", customer.getId());
params.put("start_date", 1646485214);
params.put("end_behavior", "release");
params.put("phases", phases);
SubscriptionSchedule subscriptionSchedule = SubscriptionSchedule.create(params);
}
And when I run my code I can see in the dashboard the following logs
As I'm in test mode I don't know if it's in half to make a correct implementation of a subscription for a new customer who got a visa (as you can see I never ask for card id and card holder and CVC)
Thanks for your kindly support
EDIT :
I'm looking on the implementation of check out demo app written in Java and as I can see their is first an handler on create-checkout-session :
post("/create-checkout-session", (request, response) -> {
String domainUrl = dotenv.get("DOMAIN");
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [payment_intent_data] - lets capture the payment later
// [customer_email] - lets you prefill the email input in the form
// [automatic_tax] - to automatically calculate sales tax, VAT and GST in the checkout page
// For full details see https://stripe.com/docs/api/checkout/sessions/create
// ?session_id={CHECKOUT_SESSION_ID} means the redirect will have the session ID
// set as a query param
SessionCreateParams params = new SessionCreateParams.Builder()
.setSuccessUrl(domainUrl + "/success.html?session_id={CHECKOUT_SESSION_ID}")
.setCancelUrl(domainUrl + "/canceled.html")
.setMode(SessionCreateParams.Mode.SUBSCRIPTION)
.addLineItem(new SessionCreateParams.LineItem.Builder()
.setQuantity(1L)
.setPrice(request.queryParams("priceId"))
.build()
)
// .setAutomaticTax(SessionCreateParams.AutomaticTax.builder().setEnabled(true).build()).
.build();
try {
Session session = Session.create(params);
response.redirect(session.getUrl(), 303);
return "";
} catch(Exception e) {
Map<String, Object> messageData = new HashMap<>();
messageData.put("message", e.getMessage());
Map<String, Object> responseData = new HashMap<>();
responseData.put("error", messageData);
response.status(400);
return gson.toJson(responseData);
}
});
As I think I need to create another Vaadin view that will create this session
I have a background service which reads & sends from a mailbox. It is created in a web ui, but after the schedule is created and mailbox set, it should run automatically, without further user prompt.
I have used the various combinations of the MSAL and both public and confidential clients (either would be acceptable as the server can maintain the client secret.
I have used the EWS client and got that working, but there is a note that the client_credentials flow won't work for IMAP/POP/SMTP.
I have a small console app working, but each time it runs, it needs to login interactively, and so long as I don't restart the application, it will keep authenticating, and I can call the AquireTokenSilently.
The Question
How can I make the MSAL save the tokens/data such that when it next runs, I can authenticate without user interaction again? I can store whatever is needed to make this work when the user authenticates, but I don't know what that should be nor how to reinstate it to make a new request, if the console app is restarted.
The Code
internal async Task<string> Test()
{
PublicClientApplication =
PublicClientApplicationBuilder.Create( "5896de31-e251-460c-9dc2-xxxxxxxxxxxx" )
.WithRedirectUri( "https://login.microsoftonline.com/common/oauth2/nativeclient" )
.WithAuthority( AzureCloudInstance.AzurePublic, ConfigurationManager.AppSettings["tenantId"] )
.Build();
//var scopes = new string[] { "email", "offline_access", "profile", "User.Read", "Mail.Read" };
var scopes = new string[] { "https://outlook.office.com/IMAP.AccessAsUser.All" };
var accounts = await PublicClientApplication.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
AuthenticationResult authResult;
if (firstAccount == null )
{
authResult = await PublicClientApplication.AcquireTokenInteractive( scopes ).ExecuteAsync();
}
else
{
//The firstAccount is null when the console app is run again
authResult = await PublicClientApplication.AcquireTokenSilent( scopes, firstAccount ).ExecuteAsync();
}
if(authResult == null)
{
authResult = await PublicClientApplication.AcquireTokenInteractive( scopes ).ExecuteAsync();
}
MailBee.Global.LicenseKey = "MN120-569E9E8D9E5B9E8D9EC8C4BC83D3-D428"; // (demo licence only)
MailBee.ImapMail.Imap imap = new MailBee.ImapMail.Imap();
var xOAuthkey = MailBee.OAuth2.GetXOAuthKeyStatic( authResult.Account.Username, authResult.AccessToken );
imap.Connect( "imap.outlook.com", 993 );
imap.Login( null, xOAuthkey, AuthenticationMethods.SaslOAuth2, AuthenticationOptions.None, null );
imap.SelectFolder( "INBOX" );
var count = imap.MessageCount.ToString();
return authResult.AccessToken;
}
It feels very much like a step missed, which can store the information to make subsequent requests and I would love a pointer in the right direction please.
When you create your PublicClientApplication, it provides you with the UserTokenCache.
UserTokenCache implements interface ITokenCache, which defines events to subscribe to token cache serialization requests as well as methods to serialize or de-serialize the cache at various formats.
You should create your own TokenCacheBuilder, which can store the tokens in file/memory/database etc.. and then use the events to subscribe to to token cache request.
An example of a FileTokenCacheProvider:
public abstract class MsalTokenCacheProviderBase
{
private Microsoft.Identity.Client.ITokenCache cache;
private bool initialized = false;
public MsalTokenCacheProviderBase()
{
}
public void InitializeCache(Microsoft.Identity.Client.ITokenCache tokenCache)
{
if (initialized)
return;
cache = tokenCache;
cache.SetBeforeAccessAsync(OnBeforeAccessAsync);
cache.SetAfterAccessAsync(OnAfterAccessAsync);
initialized = true;
}
private async Task OnAfterAccessAsync(TokenCacheNotificationArgs args)
{
if (args.HasStateChanged)
{
if (args.HasTokens)
{
await StoreAsync(args.Account.HomeAccountId.Identifier,
args.TokenCache.SerializeMsalV3()).ConfigureAwait(false);
}
else
{
// No token in the cache. we can remove the cache entry
await DeleteAsync<bool>(args.SuggestedCacheKey).ConfigureAwait(false);
}
}
}
private async Task OnBeforeAccessAsync(TokenCacheNotificationArgs args)
{
if (!string.IsNullOrEmpty(args.SuggestedCacheKey))
{
byte[] tokenCacheBytes = await GetAsync<byte[]>(args.SuggestedCacheKey).ConfigureAwait(false);
args.TokenCache.DeserializeMsalV3(tokenCacheBytes, shouldClearExistingCache: true);
}
}
protected virtual Task OnBeforeWriteAsync(TokenCacheNotificationArgs args)
{
return Task.CompletedTask;
}
public abstract Task StoreAsync<T>(string key, T value);
public abstract Task DeleteAsync<T>(string key);
public abstract Task<T> GetAsync<T>(string key);
public abstract Task ClearAsync();
}
And the MsalFileTokenCacheProvider:
public sealed class MsalFileTokenCacheProvider : MsalTokenCacheProviderBase
{
private string basePath;
public MsalFileTokenCacheProvider(string basePath)
{
this.basePath = basePath;
}
public override Task ClearAsync()
{
throw new NotImplementedException();
}
public override Task DeleteAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
string path = Path.Combine(basePath, key + ".json");
if (File.Exists(path))
File.Delete(path);
return Task.FromResult(true);
}
public override Task<T> GetAsync<T>(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Key MUST have a value");
}
string path = Path.Combine(basePath, key + ".json");
if (File.Exists(path))
{
T value = JsonConvert.DeserializeObject<T>(File.ReadAllText(path));
return Task.FromResult(value);
}
else
return Task.FromResult(default(T));
}
public override Task StoreAsync<T>(string key, T value)
{
string contents = JsonConvert.SerializeObject(value);
string path = Path.Combine(basePath, key + ".json");
File.WriteAllText(path, contents);
return Task.FromResult(value);
}
}
So based on your code you will have:
PublicClientApplication =
PublicClientApplicationBuilder.Create( "5896de31-e251-460c-9dc2-xxxxxxxxxxxx" )
.WithRedirectUri( "https://login.microsoftonline.com/common/oauth2/nativeclient" )
.WithAuthority( AzureCloudInstance.AzurePublic, ConfigurationManager.AppSettings["tenantId"] )
.Build();
MsalFileTokenCacheProvider cacheProvider = new MsalFileTokenCacheProvider("TokensFolder");
cacheProvider.InitializeCache(PublicClientApplication.UserTokenCache);
//var scopes = new string[] { "email", "offline_access", "profile", "User.Read", "Mail.Read" };
var scopes = new string[] { "https://outlook.office.com/IMAP.AccessAsUser.All" };
// when you call the below code, the PublicClientApplication will use your token cache
//provider in order to get the required Account. You should also use the
//PublicClientApplication.GetAccountAsync(key) which will use the token cache provider for
//the specific account that you want to get the token. If there is an account you could
//just call the AcquireTokenSilent method. The acquireTokenSilent method will take care of the token expiration and will refresh if needed.
//Please bare in mind that in some circumstances the AcquireTokenSilent method will fail and you will have to use the AcquireTokenInteractive method again. //Example of this would be when the user changes password, or has removed the access to your Application via their Account.
var accounts = await PublicClientApplication.GetAccountsAsync();
var firstAccount = accounts.FirstOrDefault();
Please refer to the following documentation from Microsoft.
https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-net-token-cache-serialization
Is anyone still using the Yahoo Fantasy Sports API? I had an app that worked last year, have not changed my code at all, and now it is returning a 500 internal error when I try to run it.
I used to test things through the YQL Console, but that is no longer available.
https://developer.yahoo.com/yql/
Anyone know how to make authenticated requests on that site above?
My feeling is that Yahoo has just discontinued support for their FantasySports API, I will have to look for other solutions I think.
Wondering if anyone else out there used this API previously and is or is not still having success with it.
I figured out how to use C# core and Yahoo's API. Huge thanks to this guy
Get your api key etc from yahoo.
Make a controller action that redirects to the request URL something like this:
public IActionResult Test()
{
yo.yKey = {your Yahoo API key};
yo.ySecret = {your Yahoo API secret};
yo.returnUrl = {your return URL as set in the API setup, example "https://website.com/home/apisuccess"};
var redirectUrl = "https://api.login.yahoo.com/oauth2/request_auth?client_id=" + yo.yKey + "&redirect_uri=" + yo.returnUrl + "&response_type=code&language=en-us";
return Redirect(redirectUrl);
}
This will send you to a site that authenticates with Yahoo. Upon successful authentication it is going to send you to your redirect site with a string parameter called code, in the example it would be home/apisuccess, so that controller action should look like this:
public async Task<IActionResult> ApiSuccess(string code)
{
List<string> msgs = new List<string>(); //This list just for testing
/*Exchange authorization code for Access Token by sending Post Request*/
Uri address = new Uri("https://api.login.yahoo.com/oauth2/get_token");
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] headerByte = System.Text.Encoding.UTF8.GetBytes(_yKey + ":" + _ySecret);
string headerString = System.Convert.ToBase64String(headerByte);
request.Headers["Authorization"] = "Basic " + headerString;
/*Create the data we want to send*/
StringBuilder data = new StringBuilder();
data.Append("client_id=" + _yKey);
data.Append("&client_secret=" + _ySecret);
data.Append("&redirect_uri=" + _returnUrl);
data.Append("&code=" + code);
data.Append("&grant_type=authorization_code");
//Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
using (Stream postStream = await request.GetRequestStreamAsync())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
var vM = new yOauthResponse();
string responseFromServer = "";
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
msgs.Add("Into response");
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
responseFromServer = reader.ReadToEnd();
msgs.Add(responseFromServer.ToString());
vM = JsonConvert.DeserializeObject<yOauthResponse>(responseFromServer.ToString());
}
}
catch (Exception ex)
{
msgs.Add("Error Occured");
}
ViewData["Message"] = msgs;
return View(vM);
}
Note that I used a json deserializer of this model, but you can do whatever you want with the response to get the data you need out of it. This is my json model:
public class yOauthResponse
{
[JsonProperty(PropertyName = "access_token")]
public string accessToken { get; set; }
[JsonProperty(PropertyName = "xoauth_yahoo_guid")]
public string xoauthYahooGuid { get; set; }
[JsonProperty(PropertyName = "refresh_token")]
public string refreshToken { get; set; }
[JsonProperty(PropertyName = "token_type")]
public string tokenType { get; set; }
[JsonProperty(PropertyName = "expires_in")]
public string expiresIn { get; set; }
}
Once you have that data, the main thing you need is the access_token, and use it as follows in a controller action:
//simple code above removed
var client = new HttpClient()
{
BaseAddress = new Uri({your request string to make API calls})
};
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
HttpResponseMessage response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
//do what you will with the response....
}
//rest of simple code
Hopefully this helps someone somewhere. Happy coding!
I am following the blog http://www.venkatbaggu.com/signalr-database-update-notifications-asp-net-mvc-usiing-sql-dependency/ to get a signalR push message out to connected clients.
My debugger never hits the onchange event.
my Global.asax.cs:
string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
protected void Application_Start()
{
// basic stuff
SqlDependency.Start(connString);
var repo = new Repositories.MarkerRepository();
repo.GetAllMarkers(); // to register the dependency
}
My MarkerRepository.cs:
readonly string _connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
private MarkersHub _mh = new MarkersHub(); // my signalr hub class
public IEnumerable<House> GetAllMarkers()
{
var markers = new List<House>();
using (var connection = new SqlConnection(_connString))
{
connection.Open();
using (var command = new SqlCommand(#"SELECT * FROM [dbo].Houses", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
markers.Add(item: new House {
ID = (int)reader["ID"],
Name = (string)reader["Name"],
Code = reader["Code"] != DBNull.Value ? (string)reader["Code"] : "",
Latitude = Convert.ToDouble(reader["Latitude"]),
Longitude = Convert.ToDouble(reader["Longitude"])
});
}
}
}
return markers;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
_mh.SendMarkers();
}
}
I have had a hit once but it was no change, only a notification for subscribe. I have read a lot about resubscribe, but when it hit this event the sql:
select * from sys.dm_qn_subscriptions
still returns no rows. Not on my db or master. So I think that there is an error in the blog post with the re-subscribe to the on change event? This sample https://msdn.microsoft.com/en-us/library/a52dhwx7(VS.80).aspx does unregister in the onchange event and calls the method which registers a new event. Can someone verify my assumption?
These were the values for the SqlNotificationEventArgs e in my event and told me that my query to depend on, was invalid.
SqlNotificationEventArgs.Type --> SqlNotificationType.Subscribe
SqlNotificationEventArgs.Info --> SqlNotificationInfo.Invalid
SqlNotificationEventArgs.Source --> SqlNotificationSource.Statement
The statement may not use the asterisk () or table_name. syntax to specify columns.
source https://msdn.microsoft.com/en-us/library/ms181122.aspx
I am trying to integrate my website with Docusign via embedded signing. I have been pretty successful - thanks to the documentation and pointers from SO).
My issue is that I have a website and on initial sign up I need the users to e-sign a document before they proceed to shop at my site. So I have set up a docusign embedded signing experience once they login - which will take them seamlessly(without login to docusign server etc) to Docusign - where in the document for signing shows up - this document is coming thru fine - but the tags are not showing up and it is showing as free form signing. There are "FIELDS" to the left of my document and I need to drag and drop these on the form ( I have populated these fields with values).
The real issue is docusign lets me "FINISH" without signing since the document is showing up as free form - Please find my code below - I am using the DocuSign REST API to created an embedded signing for a predefined document template using the /envelopes/{envelopeID}/views/recipient call. I am using RESTSHARP to connect to docusign. Thanks much for your help!
protected const string IntegratorKey = "XX";
protected const string Environment = "https://demo.docusign.net";
protected const string templateRole = "Applicant";
protected const string templateId = "XX";
private static Logger logger = LogManager.GetCurrentClassLogger();
protected const string AccountEmail = "XX#XX.com";
protected const string AccountPassword = "***";
private RestSharp.RestClient client = new RestClient();
private RestSharp.RestRequest request;
bool docuSignCallresult = false;
//
// GET: /Docusign/
public ActionResult launchDocusign(int id)
{
RestSettings.Instance.IntegratorKey = IntegratorKey;
RestSettings.Instance.DocuSignAddress = Environment;
RestSettings.Instance.WebServiceUrl = Environment + "/restapi/v2";
Domain.Account currentAccount = null;
using (var accountRepo = new AccountRepository())
{
currentAccount = accountRepo.AccountGet(id);
}
string RecipientEmail = currentAccount.Email;
string RecipientName = currentAccount.FullName;
Account docuSignAcct = GetDocusignAcctDetails();
Envelope docuSignEnvelope = GetDocusignEnvelopeDetails(docuSignAcct,RecipientEmail,RecipientName);
RecipientView rv = GetRecipientView(RecipientEmail, RecipientName);
client = new RestSharp.RestClient(Environment);
request = new RestRequest("/restapi/{apiVersion}/accounts/{accountId}/envelopes/{envelopeId}/views/recipient");
request.AddUrlSegment("apiVersion", "v2");
request.AddUrlSegment("accountId", docuSignAcct.AccountId);
request.AddUrlSegment("envelopeId", docuSignEnvelope.EnvelopeId);
Mysite.Web.Models.DocuSignData.AuthenticationHeader header = new Mysite.Web.Models.DocuSignData.AuthenticationHeader();
var jsonHeader = JsonConvert.SerializeObject(header);
request.AddHeader("X-DocuSign-Authentication", jsonHeader);
request.Method = Method.POST;
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(rv);
var response = client.Execute(request);
char[] charstoTrim = { '\r', '\n', ' ', '\'' };
var json = response.Content.Trim(charstoTrim);
var jo = JObject.Parse(json);
var recipientUrl = jo["url"].ToString();
return Redirect(recipientUrl);
}
/// <summary>
/// Get the recipient view to launch the docusign(Embedded signing experience)
/// </summary>
/// <param name="RecipientEmail"></param>
/// <param name="RecipientName"></param>
/// <returns></returns>
private RecipientView GetRecipientView(string RecipientEmail, string RecipientName)
{
RecipientView rv = new RecipientView();
rv.authenticationMethod = "email";
rv.returnUrl = Request.Url.Scheme + System.Uri.SchemeDelimiter + Request.Url.Host + "/MySiteController/MySiteActionMethod";
rv.email = RecipientEmail;
rv.userName = RecipientName;
rv.clientUserId = "1";
return rv;
}
/// <summary>
/// Create an Envelope using the template on docusign
/// </summary>
/// <param name="acct"></param>
/// <param name="recipientEmail"></param>
/// <param name="recipientName"></param>
/// <returns></returns>
private Envelope GetDocusignEnvelopeDetails(Account acct,string recipientEmail,string recipientName)
{
Envelope envelope = new Envelope();
envelope.Login = acct;
envelope.Status = "sent";
envelope.EmailSubject = "Testing";
envelope.TemplateId = templateId;
envelope.TemplateRoles = new TemplateRole[]
{
new TemplateRole()
{
email = recipientEmail,
name = recipientName,
roleName = templateRole,
clientUserId = "1"
}
};
try
{
docuSignCallresult = envelope.Create();
}
catch (Exception ex)
{
logger.Error("Login to docusign failed due to {0} and the exception generated is {2}", envelope.RestError.message, ex.Message);
}
return envelope;
}
/// <summary>
/// Access Docusign Account information
/// </summary>
/// <returns></returns>
private Account GetDocusignAcctDetails()
{
Account docuSignAcct = new Account();
docuSignAcct.Email = AccountEmail;
docuSignAcct.Password = AccountPassword;
try
{
docuSignCallresult = docuSignAcct.Login();
}
catch (Exception ex)
{
logger.Error("Login to docusign failed due to {0} and the exception generated is {2}", docuSignAcct.RestError.message, ex.Message);
}
return docuSignAcct;
}
}
}
As Jeff has mentioned in the comments this is most likely caused by you not matching your recipient correctly to a template (placeholder) role on your template. From your code it looks like you are sending the value Applicant as the template role name - this means that you need to have a role called Applicant in your Template in the Web Console.
For instance, in the below screenshot the role name is Signer1:
To fix either login to the Console and name the role on your template "Applicant" or whatever name it currently has copy that into the code and send that in the API request.