Integrating PayPal in C#/.NET Solution using WSDL (SOAP) - c#

Environment :
Visual Studio 2010 Professional
.NET Framework 4
C#
Added Service Reference using the following WSDL : https://www.paypalobjects.com/wsdl/PayPalSvc.wsdl
Problem 1 : When compiled simply like this, get a bunch of errors from the Reference.cs file. Looks like namespace errors. It mentions that it cannot find the Service Reference Namespace in my project's Namespace. Therefore, I went into the Reference.cs file and whereever I got this error, I removed the project's namespace before the method names, and now it compiles.
Finally getting access to all classes.
Created and populated DoDirectPaymentReq and CustomSecurityHeader objects with the required properties.
Created an instance of PayPalAPIAAInterfaceClient class, which contains the method DoDirectPayment which takes in the arguments of type CustomSecurityHeader and DoDirectPaymentReq. Looks like this :
using (var client = new **PayPalAPIAAInterfaceClient**())
{
var credentials = new CustomSecurityHeaderType
{
Credentials = new UserIdPasswordType
{
Username = "xxxxxxxx#xxxxxx.com",
Password = "xxxxxxx",
Signature = "jksadfuhasfweakjhasf"
}
};
_doDirectPaymentResponseType = client.DoDirectPayment(ref credentials, _doDirectPaymentReq);
}
Problem 2 : After writing a TestMethod for the method which contains the above code, I get the error as follows :
System.InvalidOperationException: Could not find default endpoint element that references contract 'Paypal.PayPalAPIAAInterface' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.
at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)
at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)
at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)
at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)
at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)
at System.ServiceModel.EndpointTrait`1.CreateSimplexFactory()
at System.ServiceModel.ClientBase`1.CreateChannelFactoryRef(EndpointTrait`1 endpointTrait)
at System.ServiceModel.ClientBase`1.InitializeChannelFactoryRef()
at System.ServiceModel.ClientBase`1..ctor()
at PaymentEngine.Paypal.PayPalAPIAAInterfaceClient..ctor() in Reference.cs: line 30063
Therefore, so far I have not been able to make a successful transaction using PayPal SOAP protocol via using WSDL in C#.
I was under the impression that this is very simple. Simply Add Service Reference and utilize the Classes with their properties and methods created in the proxy from WSDL.
Where am I going wrong ?
Am I using the wrong WSDL ? I'd like to test against Sandbox first and then go Live.
If I am right with the WSDL, looks like the class PayPalAPIAAInterfaceClient doesn't know its endpoint, which I don't know if I am suppose to set manually or not since its already there in the WSDL definition at the end (check it out). I think the class itself should know which endpoint to call depending on whether I am using Signature or Certificate to populate CustomSecurityHeaderType.
But how does the PayPalAPIAAInterfaceClient class know whether I am trying to call into the Sandbox (testing) or it is a live transaction ?
PayPal used to have two different WSDLs for Sandbox and for Live. They can be found here :
->https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_soap_PayPalSOAPAPIArchitecture
After speaking to their support I was asked to use the following WSDL for both Sandbox and Live:
->https://www.paypalobjects.com/wsdl/PayPalSvc.wsdl
But how do I tell the PayPalAPIAAInterfaceClient class when it is suppose to perform Live or Sandbox tests. And also to which end point to use depending on my method of SOAP and Signature. The endpoints from PayPal are mentioned here :
https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_api_endpoints
HELP !

You have a few problems here, but none should be too painful to resolve. First of all, when I add a Service Reference to the WSDL you link at the top of your post I don't have any of the problems with namespaces that you describe. It could be that your own namespaces/references are conflicting somehow with the auto-generated terms, or perhaps that you selected some strange option during the add reference process? A delete-and-re-add might solve the problem, or I guess you can just ignore it since you've already worked around it. (It is kind of a hassle to edit auto-generated code, however, so you should plan on a fix eventually.)
To resolve the InvalidOperationException, you probably just need to specify one of the endpoints that Visual Studio has automatically added to your app.config file. You should have something like this in your config file:
<system.serviceModel>
<client>
<endpoint name="PayPalAPI" ... />
<endpoint name="PayPalAPIAA" ... />
</client>
</system.serviceModel>
You can pass the name of the endpoint you want to the constructor of the proxy class. There are other options to solve this problem, but just specifying an endpoint is easy and clean. (Note: if you don't have this section in your config file, then something went wrong during the Add Service Reference phase. Again I would just suggest resetting your project and re-adding the reference.)
Finally, you don't want to use a using block when you make use of the proxy class in spite of it being IDisposable. Basically, there's a design bug in WCF.

I had the same problem, because I was doing unit testing.
You have to copy the application.config file to the test project, otherwise it won't find the WCF config.

Related

Can we have environment-based endpoints with a WCF Connected Service?

I recently migrated one of our assemblies (a referenced library) from the old CSProj format to the new CSProj format (the Microsoft.Net.Sdk format). This helps a lot due to the globbing rules and how it handles dependencies (reference, project reference, package reference) so well.
After the transition, there is no longer an option for "Service References", instead we have "Connected Services". I removed the old Service Reference files (code, wsdl, xsd, etc.) and created a new Connected Service.
It seems cleaner because it generates a json configuration (used for auto-generating code) and a single Reference.cs file. The auto-generated code is a bit different than the old service reference code that was generated. Firstly, all methods are async (makes sense), so I adjusted our code to account for this.
The problem I am running into is that we had originally relied on the application's Web.Config file (also Web.Dev.Config, Web.Test.Config, etc.) -- during our deploy process we rename/replace the Web.Config with the appropriate environments configuration. This worked just fine, our app added a reference to our library and the app held the config information.
With the new Connected Services auto-generated code, it is hard coding in the localhost address as the endpoint because I used that to auto-generate the code.
Basically, the old "Service Reference" generated code had the default constructor of the client pull the endpoint from the application config. The new Connected Service offers overloads, but does not by default pull the endpoint from the config.
<system.serviceModel>
<client>
<endpoint address="http://xdev/xservice.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IXService" contract="XService.IXService" name="BasicHttpBinding_IXService" />
</client>
</system.serviceModel>
What do I do different to take advantage of my app config with the new WCF Connected Services auto-generated code?
See this answer:
There is a partial abstract method partial void ConfigureEndpoint in your service client to override. There you can programmatically set the endpoint via serviceEndpoint.Address = new EndpointAddress(...).
This URL can be stored in the <appSettings> of your .config or in the appsettings.<Environment>.json, depending on your platform.
Note, that the development endpoint from which the code was generated gets hard-coded into the sources and remains as a fallback. If for some reason your overridden method does not get called, you have a very hard to spot error. If someone has a solution for that, I'd be very interested.

Are Web Service References necessary in all project?

I currently have one Web Service in a solution of multiple projects. Since I don't want to add service references in all project to be able to use it, I have created a project with static a class named "ServiceHelper" for the moment. This project would be the only one with the service references and the helper would do all the request ncessary. The Web Service is set public (not internal).
My problem here is that when I initialize my SoapClient in my helper from another project that do not have the service references, it throws an exception. But when I add the service reference to that other project, it works. Is it normal or not?
The exception throwed translated (because it is said in French) is :
Unable to find an element endpoint default refers to the contract 'ServiceReference.WebServiceSoap' section in the ServiceModel client configuration. This may be due to the fact that the configuration file of your application is not found or the endpoint element matching this contract is found in the client element
Is there something missing in my config file? because I didn't change anything in the 2 projects mentionned.
Exemple of how I initialize my SoapClient in my helper :
private static ServiceReference.WebServiceSoapClient _webService = new ServiceReference.WebServiceSoapClient();
Following on with #zverev.eugene, you don't need the references in every project, but the web.config or app.config in the project is where the connection and configuration information is retrieved from. This is because the application calling your class library is what supplies all configuration information (e.g., if you have a data access layer in a class library, the connection string would come from the .config of the application calling the DAL, not the class library itself).

Passing parameter to WCF Service Ctor from Proxy Client

This may be a basic question since I am new to WCF. I don't even know if this is supported or not.
I have a WCF Service called MyCustomService. I added this service reference in my client solution and now I can create a proxy object by calling:
MyCustomServiceClient myClient = new MyCustomServiceClient();
myClient.GetData();
myClient.GetData();
How, do I layout my Service so that I can pass the parameter during proxy instance creation i.e.
MyCustomServiceClient myClient = new MyCustomServiceClient("SomeString");
I noticed every method call I make creates a new instance of the MyCustomService(i.e I can get the breakpoint hit on MyCustomService Ctor). So, I want the value that I had passed when creating proxy object (i.e. SomeString) to exist for all the calls I make until the lifetime of myClient
Any ideas ?
The proxy generation feature of Visual Studio (or svcutil.exe) creates a proxy class with five different constructor signatures. The one that you are asking about, the constructor that takes a single string, is a very useful one, because it allows you to reference different client configurations from your app.config or Web.config file.
Take this extremely simple hypothetical configuration file:
<configuration>
<system.serviceModel>
<client>
<endpoint name="serverABinding" />
<endpoint name="serverBBinding" />
</client>
</system.serviceModel>
</configuration>
You can then control which binding you use for the proxy:
string endpointName = useB ? "serverBBinding" : "serverABinding";
var myClient = new MyCustomServiceClient(endpointName);
Of course, the endpoint bindings I've shown above are too simple to actually be useful, but hopefully you get the idea.
Your motivation isn't exactly clear, but it sounds like you want to control the proxy behavior across all proxy instances of your application. If that's what you want, then don't use a constructor: use the endpoint configuration in your app.config or Web.config file to control the proxy connection. The default endpoint configuration that is generated by Visual Studio uses an endpoint name that matches the default name of the proxy client. Change this endpoint definition, and you'll change the behavior of your service client.
Since you are new to WCF, my advice to you is this: learn all about configuration files. Once you understand a WCF configuration file, you understand WCF.
You can not have constructor with parameter in your WCF service, even when you try to create such service you will get below error.
The service type provided could not be loaded as a service because it
does not have a default (parameter-less) constructor. To fix the
problem, add a default constructor to the type, or pass an instance of
the type to the host.
Now if you want the data to persist for a client you can set ServiceInstanceContextMode as below as a attribute on Service Class
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Service : IService

Can I generate a service reference automatically for a REST WCF service?

The ONLY argument I can see for SOAP WCF over REST (json) wcf is the fact that once my service is created I can add a a reference in visual studio and I get a load of strongly typed classes ready for me and a client class that I can call all my webmethod through. It even sets up the web.config as far as I remember.
However when I expose a REST (json) service I still get a WSDL. So Im wondering is there still a way to build my references automatically?
Not using WCF tools. Unlike with SOAP (which has an established protocol for describing services - WSDL), REST doesn't. WADL is one such protocol, but it isn't too widespread and WCF does not support it. You still get a WSDL, because WCF will describe everything it can from the service. However, the WSDL won't have a <wsdl:port> element, which would describe the REST endpoint, which is why you get the WSDL, but cannot generate a reference to it.
The post at http://blogs.msdn.com/b/carlosfigueira/archive/2012/03/26/mixing-add-service-reference-and-wcf-web-http-a-k-a-rest-endpoint-does-not-work.aspx has a lot more info on this issue.
Very old question, newer answer.
today using openapi (swagger) I can achieve this by using swagger inspector doing samples i can document my rest services as well as create a spec yml/json file allowing for validations and acceptance criteria as well as automated clients for java,python,c#,ruby,javascript and others I'm sure
I would like top elaborate:
Although it is true you cannot get a WSDL add service reference with a JSON REST WCF service, what I do is create two met data hooks:
is the operations returning JSON
is a single XML op returning a class wrapper which includes all the service classes I allow, I call it Discover:
i.e.
public class Discover
{
public Manager Manager {get;}
public Employee Emp {get;}
....
}
[OperationContract]
public Discover DiscoverDTOs()
You can, indirectly. While the client generated by Visual Studio won't work, that client implements an interface, also generated, that you can use like this:
WebChannelFactory<IService> factory = new WebChannelFactory<IService>(new Uri(endpointAddress));
IService proxy = factory.CreateChannel();
int result = proxy.Operation(1, 2, 3);
WebChannelFactory has another overload which accepts a WebHttpBinding, you can configure based on the service configuration, or you can make this configuration manually in your app.config file.

Generating wcf proxy vs ChannelFactory

Which one of this two ways of using wcf service is better? why?
Generating proxy from Service Reference
using ChannelFactory
ex.
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>();
IMyContract proxy1 = factory.CreateChannel();
proxy1.MyMethod();
It is a bit boring to call wcf service like so
IMyContract proxy1 = null;
try
{
proxy1 = factory.CreateChannel();
proxy1.MyMethod();
((ICommunicationObject)proxy1).Close();
}
catch
{
((ICommunicationObject)proxy1).Abort();
}
Should we repeat this snippet for every proxy call? Or Is there generic way to create a wrapper class for closing and aborting proxies?
Is writing class like this ServiceExecution.Execute(proxy=>proxy.MyMethod()); which creates proxy, and closes or aborts it good way to do that?
Here is an MSDN post, that recomends not to use generated proxies in .Net 3 because it creates ChanelFactory each time, .Net 3.5 ChanelFactory is cached.
But personally I prefer to use ChanelFactory myself, generated code is always a pain even after partials come out
In first case when you use VS to add Service Reference it generates all the code for you including ServiceContrcats and DataContracts.
But when you use ChannelFactory you must have service contracts and etc on client side already.
I suggest using approach 1.
I've found this blog with an example including source code that also explains how to properly handle the connection (closing, aborting, etc.). The blog also contains links for more details at MSDN.
Manually creating the service proxies from a running service might be a good alternative. The tool svcutil is what Visual Studio uses under the hood when adding a service reference. Using this, you can generate the proxy class in a common location, and then link to it in each project you require, and also gain better control over your proxy classes.
For example, to generate a proxy for a service called TestService running locally on port 8000, you would run the following in the Visual Studio command prompt, generating a proxy class TestServiceProxy.cs in the proxies directory.
cd "C:\src\proxies"
svcutil /noLogo /out:TestServiceProxy http://localhost:8000/TestService
There are some other useful parameters for the tool, for example:
Add /n:*,WcfServices.TestService will specify a namespace for the proxy class.
Add /config:TestServiceProxy.config and svcutil will generate a sample configuration file for using TestService including endpoints, bindings etc.
Add /r:"Common.dll" and the proxy class emitted by svcutil will not have definitions for types used by the service, but defined in the assembly Common.dll.
Use svcutil /? for more information.

Categories