PayPal RestApiSDK .NET http 503 Server Unavailable - asp.net

I am trying to use the PayPal .NET RestApiSDK to store credit cards and take payments in their sandbox. I am using .NET 4.5 in an MVC project.
I followed the example code here:
https://developer.paypal.com/webapps/developer/docs/api/#store-a-credit-card
Initially, things were very easy. On day one, I was able to:
-take several payments
-store several cards
-look up sales
-refund sales
-store cards in the vault
(basically, everything in their example code)
Ever since day one (about a week), I have been getting an http 503 "Server Unavailable" error. Unless I changed something in my sleep, I am using the exact code that worked before.
I contacted PayPal support, and after several back and forth messages they have let me know that while they can't pinpoint an error in my code, the error must be on my side, because their servers are working fine.
What is really strange, is that I seem to be able to do anything that doesn't change data. For instance, I can call payments.List(). However, I can't call creditCard.Create() or payment.Create().
Also, the access token is being created just fine. The line tokenCredential.GetAccessToken() does not return any server error. When I debug the code, it has indeed returned with a proper token.
Question:
What could possibly be causing an http 503 error when I try to store a card or take a payment?
Here is some relevant code.
controller:
public JsonResult RunTestPayment()
{
string id = ConfigManager.Instance.GetProperties()["ClientID"];
string secret = ConfigManager.Instance.GetProperties()["ClientSecret"];
OAuthTokenCredential tokenCredential = new OAuthTokenCredential(id, secret);
string accessToken = tokenCredential.GetAccessToken();
PayPal.Api.Payments.Address billingAddress = new PayPal.Api.Payments.Address();
billingAddress.line1 = "52 N Main St";
billingAddress.city = "Johnstown";
billingAddress.country_code = "US";
billingAddress.postal_code = "43210";
billingAddress.state = "OH";
PayPal.Api.Payments.CreditCard creditCard = new PayPal.Api.Payments.CreditCard();
creditCard.number = "4417119669820331";
creditCard.type = "visa";
creditCard.expire_month = 11;
creditCard.expire_year = 2018;
creditCard.cvv2 = "874";
creditCard.first_name = "Joe";
creditCard.last_name = "Shopper";
creditCard.billing_address = billingAddress;
PayPal.Api.Payments.Details amountDetails = new PayPal.Api.Payments.Details();
amountDetails.subtotal = "7.51";
amountDetails.tax = "0.03";
amountDetails.shipping = "0.03";
PayPal.Api.Payments.Amount amount = new PayPal.Api.Payments.Amount();
amount.total = "7.56";
amount.currency = "USD";
amount.details = amountDetails;
PayPal.Api.Payments.Transaction transaction = new PayPal.Api.Payments.Transaction();
transaction.amount = amount;
transaction.description = "This is the payment transaction description.";
List<PayPal.Api.Payments.Transaction> transactions = new List<PayPal.Api.Payments.Transaction>();
transactions.Add(transaction);
PayPal.Api.Payments.FundingInstrument fundingInstrument = new PayPal.Api.Payments.FundingInstrument();
fundingInstrument.credit_card = creditCard;
List<PayPal.Api.Payments.FundingInstrument> fundingInstruments = new List<PayPal.Api.Payments.FundingInstrument>();
fundingInstruments.Add(fundingInstrument);
PayPal.Api.Payments.Payer payer = new PayPal.Api.Payments.Payer();
payer.funding_instruments = fundingInstruments;
payer.payment_method = "credit_card";
PayPal.Api.Payments.Payment payment = new PayPal.Api.Payments.Payment();
payment.intent = "sale";
payment.payer = payer;
payment.transactions = transactions;
PayPal.Api.Payments.Payment createdPayment = payment.Create(accessToken);
return Json(new JsonWrapper { Data = createdPayment });
}
When stepping through, the error occors on the line
PayPal.Api.Payments.Payment createdPayment = payment.Create(accessToken);
the exact error (as a Json Object):
"ClassName":"PayPal.Exception.PayPalException","Message":"Exception in HttpConnection Execute: Invalid HTTP response The remote server returned an error: (503) Server Unavailable.","Data":null,"InnerException":{"ClassName":"PayPal.Exception.ConnectionException","Message":"Invalid HTTP response The remote server returned an error: (503) Server Unavailable.","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":" at PayPal.HttpConnection.Execute(String payLoad, HttpWebRequest httpRequest)","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nExecute\nPayPalCoreSDK, Version=1.4.1.0, Culture=neutral, PublicKeyToken=null\nPayPal.HttpConnection\nSystem.String Execute(System.String, System.Net.HttpWebRequest)","HResult":-2146233088,"Source":"PayPalCoreSDK","WatsonBuckets":null},"HelpURL":null,"StackTraceString":" at PayPal.PayPalResource.ConfigureAndExecute[T](Dictionary`2 config, IAPICallPreHandler apiCallPreHandler, HttpMethod httpMethod, String resourcePath)\r\n at PayPal.PayPalResource.ConfigureAndExecute[T](APIContext apiContext, HttpMethod httpMethod, String resource, String payload)\r\n at PayPal.Api.Payments.Payment.Create(APIContext apiContext)\r\n at PayPal.Api.Payments.Payment.Create(String accessToken)\r\n at Scout.Controllers.PaymentController.RequestPermissions() in e:\\Scout\\Scout\\Controllers\\PaymentController.cs:line 1105","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nConfigureAndExecute\nPayPalCoreSDK, Version=1.4.1.0, Culture=neutral, PublicKeyToken=null\nPayPal.PayPalResource\nT ConfigureAndExecute[T](System.Collections.Generic.Dictionary`2[System.String,System.String], PayPal.IAPICallPreHandler, PayPal.HttpMethod, System.String)","HResult":-2146233088,"Source":"PayPalCoreSDK","WatsonBuckets":null
web.config (api keys are truncated here):
...
<configuration>
<configSections>
<section name="paypal" type="PayPal.Manager.SDKConfigHandler, PayPalCoreSDK" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
...
</configSections>
...
<paypal>
<settings>
<add name="endpoint" value="https://api.sandbox.paypal.com"/>
<add name="ClientID" value="AbayoRB3Eq6YxM6"/>
<add name="ClientSecret" value="EDWNfxDxnGZ3hWZW"/>
<add name="connectionTimeout" value="360000"/>
<!-- The number of times a request must be retried if the API endpoint is unresponsive -->
<add name="requestRetries" value="3"/>
</settings>
</paypal>
...
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="ScoutPaypalLog.log" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
As you can see, I have configured log4net, and it is recording data generated by another .dll I'm using (for RavenDB), but there are no entries made by PayPal.
Thanks!

I finally uninstalled the two nuget packages RestApiSDK and PayPalCoreSDK. I then restarted Visual Studio. Finally, I re-installed those same two packages.
Without changing any code, it started working.

Related

integrate mailchimp api in asp.net

I am integrating mailchimp api in asp.net.
web.config:
<add key="APIKey" value="XXXX9dsfij4yZXXXXXXXXXX-XXXX" />
in code
using mailchimp;
IMailChimpManager manager = new MailChimpManager();
when I see what's in 'manager' object, it's null.
how do i get api key from web.config file?
According to:
https://github.com/brandonseydel/MailChimp.Net/blob/master/README.md You have two options here.
First, you can manually read API key from config:
using mailchimp;
using System.Configuration;
//Read API key from config
var apiKey= ConfigurationManager.AppSettings["APIKey"];
IMailChimpManager manager = new MailChimpManager(apiKey);
Second option is that you can change read key to MailChimpApiKey, so change
<add key="APIKey" value="XXXX9dsfij4yZXXXXXXXXXX-XXXX" />
to
<add key="MailChimpApiKey" value="XXXX9dsfij4yZXXXXXXXXXX-XXXX" />
In that case you don't need to pass API key:
using mailchimp;
IMailChimpManager manager = new MailChimpManager();

DocumentDB Trace listener

I'm trying register DocumentDB tracing with an existing listener. The code snippet below properly traces a single message to my expected listener but not the actual traces generated by the DocumentDB C# client. Am I missing something?
Snippet from Global.asax:
private static TraceSource DocDBSource;
private static TraceListener ExistingListener = new .....;
public void RegisterDocDBListener() {
DocDBSource = new TraceSource("DocDBTrace");
DocDBSource.Switch.Level = SourceLevels.Information;
DocDBSource.Listeners.Add(ExistingListener);
DocDBSource.TraceInformation("DocDB tracing initialized");
}
According to your description, I have checked the DefaultTrace from DocumentDB client library for .NET as follows:
For Client-side Logging with the .NET DocumentDB Client Library, you could configure the system.diagnostics configuration as follows to collect and persist documentdb log messages to a text file as follows:
<system.diagnostics>
<sources>
<source name="DocDBTrace">
<listeners>
<!--ConsoleTraceListener-->
<add name="configConsoleListener" type="System.Diagnostics.ConsoleTraceListener"/>
<!--TextWriterTraceListener-->
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="TextWriterOutput.log" />
</listeners>
</source>
</sources>
<switches>
<add name="ClientSwitch" value="Warning"/>
</switches>
</system.diagnostics>
Note: The default Log Level is Information, you could change the ClientSwitch to your expected Log Level (Off, Error, Information, Verbose).
Result
Console Application
Web Application

Acces-Control-Allow-Origin works with Web.config (IIS7) but not with (WebApiConfig.cs) ASP.NET Cross Origin support

For a project i want to load and view a pdf file with angular-pdfjs. The team uses ASP.net Cross Origin, to Allow-Acces-Control, Headers, Credentials etc.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Replace the default implementation of the ITraceWriter with our custom logger.
config.Services.Replace(typeof (ITraceWriter), new GlobalTraceLogger());
// Replace the default exception logger to be able to log exceptions with NLog
config.Services.Replace(typeof (IExceptionLogger), new GlobalExceptionLogger());
// Replace the default exceptionhandler to be able to handle exceptions globally
config.Services.Replace(typeof (IExceptionHandler), new GlobalExceptionHandler());
// We must enable cors, because otherwise we are not able to commuincate with a java script client
// TODO: We need to restirct the requested resource. Do not allow every origin!
// Do not run this in prodocutive environment
var cors = new EnableCorsAttribute("*", "*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
// Make the default return type JSON
var appXmlType =
config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
This works good so far, but if i want to load my pdf file with angular-pdfjs, i get a Cross Origin Error, because Allow-Acces-Control-Origin "*" didn't works for my pdf-url.
(https://img3.picload.org/image/roirrgcw/corsworksnot.png)
But if i using instead of ASP.net Cross Origin Support the Allow-Access-Control of IIS7 in Web.config:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Origin, X-Requested- With, Content-Type, Accept" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Credentials" value="true" />
</customHeaders>
</httpProtocol>
it works and the pdf will be loaded correctly.
(https://picload.org/image/roirrgci/corsworks.jpg)
But the problem is, at the moment the page is loaded via "file://" and so i get
an error because there is no Access-Control-Allow-Origin for 'null'. That means, my pdf is loading correctly this way, but the login, pictures... won't be loaded anymore. So my question is, if someone knows how i can change the WebApiConfig-Implementation that my pdf-file get an Access-Controll-Allow as well. Or maybe can someone tell where the error could be.
For information:
Thats the way i'm loading the pdf with angular-pdfjs:
<!---------------------------THE PDF VIEWER DIRECTIVE------------------------->
<div pdf-viewer="options" pdf-url="pdfUrl" id="my-viewer" class="col col-lg-10"></div>
<!---------------------------THE PDF VIEWER DIRECTIVE------------------------->
and thats the url, i'm using:
function PdfviewController(ebmGuideLineService, mediaService, $scope, $window) {
var vm = this;
$scope.pdfUrl = 'http://localhost:3787/NCCN_Evidence_Blocks_Melanoma.pdf';
$scope.options = { mouseZoom: false, mousePan: false };
Please tell me, if you need more informations and thank you for your help.

Request returns 404 Not Found for OPTIONS, but works fine when using Postman (ASP.NET)?

Browser console output:
XMLHttpRequest cannot load https://api.[...].com/[...]. Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost' is therefore not allowed access.
The response had HTTP status code 404.
I have an AngularJS application that is making calls to an API built in ASP.NET. Recently the backend team added versioning to the application, and for some reason, one of the API endpoints will no longer return 200 OK for the OPTIONS request (even though all the other API endpoints on that same server still return 200 OK). Always return 404 Not Found.
ASP.NET server seems to be using a WebApi.Cors package; no specific [HttpOptions] methods are being declared (all OPTIONS request are handled through the package); and the web.config feeds the CorsConfig with * for all of origin, headers, methods.
I've tried many of the solutions from Google results but nothing has worked.
Anyone face a similar issue and can give general guidance on what could be causing the issue, or how to potentially test for the problem, or attempt a solution?
[Edit:] Found solution.
Issue caused because "Version 1" of the API endpoint was dropped on that specific route. The first valid version on that endpoint was now "Version 2". So I added a blank Controller method to catch requests for "Version 1" (which only returns a blank string, nothing more), and this was sufficient to allow the OPTION request to resolve.
I think part of the issue here is the routing has changed:
Recently the backend team added versioning to the application
Things to check:
WebApi Configuration
Can you make sure that your configuration takes place as the first item in your Global.asax file:
void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configure(WebApiConfig.Register);
//...
}
Web API Routing
Has the versioniong been correctly configured inside the WebApiConfig?
public static void Register(HttpConfiguration config)
{
config.EnableCors(new EnableCorsAttribute("*", "*", "*");
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
}
In IIS 7.5 the only way I got CORS working was via the web.config and not through the Nuget package:
My web.config was as follows:
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="ExtensionLessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionLessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionLessUrlHandler-Integrated-4.0" />
<add name="ExtensionLessUrlHandler-ISAPI-4.0_32bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionLessUrlHandler-ISAPI-4.0_64bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Found the solution. Posting it here for anyone else that has the problem in the future.
The API endpoint started with "version 2". There had been an earlier "version 1" that never made it to production, but it was dropped/discontinued because the signature would be completely changing. This was done because development teams had been using "version 1" up to that point, but since it wasn't going into production, logic dictated no longer having that version/endpoint.
For some reason, not having a "version 1" caused the OPTIONS to fail and return a 404 Not Found. My guess is because the required version header was not actually included with the OPTIONS pre-flight request, so it never resolved to a GET destination in the Controller.
Thus, you must have a version 1 reference, even if it's a placeholder that just returns a blank string.
Before:
[VersionedRoute("products", 2, Name = "GetProducts")]
[HttpGet]
public IHttpActionResult GetProducts([FromUri] GetProductsRequest request)
{
After:
[VersionedRoute("products", 1, Name = "GetProducts")]
[HttpGet]
public IHttpActionResult GetProducts()
{
    return NotFound();
}
[VersionedRoute("products", 2, Name = "GetProducts_V2")]
[HttpGet]
public IHttpActionResult GetProducts_V2([FromUri] GetProductsRequest request)
{

Trying to get REST service running on ASP.NET

I have created a REST server under ASP.NET and I can't figure out the url to bring up the service. I am running under VS 2010 using it's built in web server. I believe it is actually running (VS 2010 starts up fine). But every combination I can think of for a url doesn't bring it up.
Update: Please take a look at the file http://www.windward.net/temp/RestUnderAspDotNet.zip - I have two solutions in there. The one at src\update runs fine as a REST server. I have pretty much the same code at inetpub\wwwroot\update and while it runs, I can't find a url that talks to it. I tried every variation of http://localhost:56469/update/App_Code/RestServiceImpl.svc/test I could think of and get either 403 or 404.
Any idea why? (I do not want any security on this - anyone will be able to hit it once it's up.)
App_Code\IRestServiceImpl.cs:
[ServiceContract]
public interface IRestServiceImpl
{
[OperationContract]
[WebInvoke(UriTemplate = "/version", Method = "POST")]
XmlElement GetVersion(XmlElement stats);
[OperationContract]
[WebInvoke(UriTemplate = "/test", Method = "GET")]
string GetTest();
}
App_Code\RestServiceImpl.svc:
<%# ServiceHost Language="C#" Debug="true" Service="RestServiceImpl" CodeBehind="RestServiceImpl.svc.cs" %>
App_Code\RestServiceImpl.cs:
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Xml;
[AspNetCompatibilityRequirements
(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class RestServiceImpl : IRestServiceImpl
{
public XmlElement GetVersion(XmlElement stats)
{
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement("update");
root.SetAttribute("version", "11.0.13.0");
doc.AppendChild(root);
return doc.DocumentElement;
}
public string GetTest()
{
return "update server is running";
}
}
Relevant part of web.config:
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="RestServiceImpl">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="webHttpBinding" contract="IRestServiceImpl" behaviorConfiguration="webBinding">
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="RestServiceImpl">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webBinding">
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Any idea what the url is to bring up the /test GET?
thanks - dave
You can try something like:
http://localhost:whateverportVSgivesyou/RestServiceImpl.svc/test
If the VS webserver is running you should see a system tray icon for it, and if you hover over it you'll see the port it's running on...
I finally figured this out. I have this also on my blog at Windward Wrocks with screenshots. Here's the solution w/o screenshots:
Install the WCF REST Service Template 40(CS) (requires .NET 4.0).
Create a WCF service. This is a New “Project…” not a “Web Site…”. And it is under the general “Visual C#” templates, not “WCF”!

Resources