Solved

Two WSDLs, Same Definition, Different Endpoints

Posted on 2011-02-24
10
1,255 Views
Last Modified: 2012-05-11
Hello,

We are consuming an external WSDL in our app layer using a Service Reference.  Its actually the PayPal WSDL.

They have a test (sandbox) WSDL url and a live production WSDL url.  They both have the same definition but with different wsdl locations and different endpoints.  So how does one handle this in their code?  

We are basically trying to figure out how we can eliminate duplicate clasess/methods but be able to easily run the code for either the sanbox or live site using some config app keys or something.  Not sure what that all entails.

Do I need both of them as Service References?  If so, we can't include both in the same class file, otherwise there is ambiguity, so then do we need different classes and methods for each WSDL service reference?  

Is there a way to only use the live WSDL as the service reference but pass in the sandbox endpoint url so it hits their test site?  Is there anything else needed to be able to do this?

Ideas?  Thanks, ks

0
Comment
Question by:kruegerste
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
10 Comments
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34974781
>>  Do I need both of them as Service References?  If so, we can't include both in the same class file, otherwise there is ambiguity, so then do we need different classes and methods for each WSDL service reference?  

The wonderful thing about "Add Service Reference," though, is that at the bottom of the dialog, you can specify the namespace you would like to give to the reference being added (see screenshot). So you can potentially add both references, but give them different and meaningful namespaces, and there should be no conflict.
untitled.PNG
0
 
LVL 4

Author Comment

by:kruegerste
ID: 34974861
That part I do understand and they do have different namespaces but that leads me to the other questions I had.  Are you able to answer any of the other ones?  

How do I differentiate between the two services in my code?  They have the same exact definition but different endpoints.

If they have different definitions, do I still need both even if they can have different namespaces?  If I have to reference both, then even with different namespaces, when I do the following, ambiguity persists:

using PayPalSvc;
using PayPalSvcSandbox;

We really need help with the overall solution of how to handle two services with the exact same definition but different endpoints.  Is it only the endpoint that matters if they are the same but different locations?  

Please help :)
0
 
LVL 4

Author Comment

by:kruegerste
ID: 34974902
Below is my method for doing the direct payment.  

So how do I specify an endpoint here?  Is this suppose to be in my web.config?  When I created the service, it created an app.config file with some endpoints and stuff in the c# class library.  But obviously my web app can't see that app.config.

And then the other issue of trying to use the same method/class for both the sandbox and live references.   Again, are they both really needed?  if so, how do i handle this?  if not, how do i handle this?
using System;
using System.Data;
using PayPalSvcSandbox;
using PayPalSvc;

public class PaymentBL
{
  public String DoDirectPayment(MOPInfo creditCardMOPInfo, String ipAddress)
		{
            try
            {
                PayPalAPIAAInterfaceClient client = new PayPalAPIAAInterfaceClient();
             
                CustomSecurityHeaderType credentials = new CustomSecurityHeaderType();
                credentials.Credentials = new UserIdPasswordType();
                credentials.Credentials.Username = SecurityBL.Decrypt(ConfigurationUtil.PayPalAPIUsername);
                credentials.Credentials.Password = SecurityBL.Decrypt(ConfigurationUtil.PayPalAPIPassword);
                credentials.Credentials.Signature = SecurityBL.Decrypt(ConfigurationUtil.PayPalAPISignature);
                credentials.Credentials.DevId = ConfigurationUtil.PayPalAPIEnvironment;
            
                DoDirectPaymentReq request = new DoDirectPaymentReq();
                request.DoDirectPaymentRequest = new DoDirectPaymentRequestType();
                request.DoDirectPaymentRequest.Version = "51.0";

                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails = new DoDirectPaymentRequestDetailsType();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.IPAddress = ipAddress;

                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard = new CreditCardDetailsType();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CreditCardNumber = creditCardMOPInfo.CreditCardNumber;
                switch (creditCardMOPInfo.CreditCardType)
			    {
				    case ConstantRepository.CREDIT_CARD_VISA:
					    request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CreditCardType = CreditCardTypeType.Visa;
					    break;
				    case ConstantRepository.CREDIT_CARD_MASTERCARD:
					    request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CreditCardType = CreditCardTypeType.MasterCard;
					    break;
				    case ConstantRepository.CREDIT_CARD_DISCOVER:
					    request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CreditCardType = CreditCardTypeType.Discover;
					    break;
			    }
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.ExpMonth = creditCardMOPInfo.CreditCardExpMonth.ToInt32();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.ExpMonthSpecified = true;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.ExpYear = creditCardMOPInfo.CreditCardExpYear.ToInt32();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.ExpYearSpecified = true;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CVV2 = creditCardMOPInfo.CreditCardSecurityCode;

                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner = new PayerInfoType();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Payer = "";
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.PayerStatus = PayPalUserStatusCodeType.unverified;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.PayerCountry = CountryCodeType.US;

                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.PayerName = new PersonNameType();      
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.PayerName.FirstName = CustomerBL.GetName(creditCardMOPInfo.CreditCardName, EnumRepository.NamePart.FirstName);
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.PayerName.LastName = CustomerBL.GetName(creditCardMOPInfo.CreditCardName, EnumRepository.NamePart.LastName);
                                     
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address = new AddressType();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.Street1 = creditCardMOPInfo.MOPAddress.AddressLine1;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.Street2 = creditCardMOPInfo.MOPAddress.AddressLine2;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.CityName = creditCardMOPInfo.MOPAddress.City;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.StateOrProvince = creditCardMOPInfo.MOPAddress.StateCode;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.PostalCode = creditCardMOPInfo.MOPAddress.ZipCode.ToString();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.CountryName = "USA";
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.Country = CountryCodeType.US;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.CreditCard.CardOwner.Address.CountrySpecified = true;

                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.PaymentDetails = new PaymentDetailsType();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.PaymentDetails.OrderTotal = new BasicAmountType();
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.PaymentDetails.OrderTotal.currencyID = CurrencyCodeType.USD;
                request.DoDirectPaymentRequest.DoDirectPaymentRequestDetails.PaymentDetails.OrderTotal.Value = creditCardMOPInfo.MOPAmount.ToString();

                var response = client.DoDirectPayment(ref credentials, request);

			    return response.ToString();
            }
       }
}

Open in new window

0
Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34979155
Line 12 should have an overload that allows you to pass in the name of the configuration (as specified in your web.config/app.config).
0
 
LVL 4

Author Comment

by:kruegerste
ID: 34979187
So does this mean I don't need both services referenced if they have the same definition?  And I can just pass in a different endpoint name, depending on the location/environment to hit?
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34979240
I believe that as long as the namespaces on the XML itself are the same, then it should be possible. I haven't personally dealt with a scenario like this, though, so I can only surmise.
0
 
LVL 4

Author Comment

by:kruegerste
ID: 34979775
Anybody else?
0
 
LVL 75

Expert Comment

by:käµfm³d 👽
ID: 34979988
If they have different definitions, do I still need both even if they can have different namespaces?  If I have to reference both, then even with different namespaces, when I do the following, ambiguity persists:

using PayPalSvc;
using PayPalSvcSandbox;

Of course there is ambiguity. You have included both namespaces in your "using" section. How would C# know which class you are referring to? If you want to stick with having a reference to both services, then you can provide another "using" in the context of an alias:

    using TestSvc = PayPalSvcSandbox.PaymentBL;

Then in code, you can refer to TestSvc.DoDirectPayment() rather than its official name.
0
 
LVL 4

Author Comment

by:kruegerste
ID: 34980126
It isn't so much "do I want to have both references", my question was, do I need both WSDL references?  I'm trying to first understand the correct solution, I haven't picked one cause I'm not sure which way to go.  This can't be that extraordinary of an issue.  I would assume many 3rd parties have this sort of architecture.  

I think my preference would to not use both in order to prevent having redundant code.  But again, I don't know what issues this would cause, if any.  I guess maybe this part is a PayPal question and I am waiting for a response from them.  They do have versioning too that is specified in the call so you would think that is even more of a reason you could get away with using one WSDL definition and different endpoints, no?

If it turns out that both references are definitely needed, then I will revisit your last post on how to handle this.  It seems your example is for placement in the calling method that is using the DoDirectPayment() method.  But my issue is actually inside the PaymentBL class on how to implement a class and methods using both references.  
0
 
LVL 75

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 34980199
Part of you confusion may stem from the use of the term "reference". There is not an actual reference (like you would have in a Forms project); rather there is a conversion of the WSDL into a class or set of classes which can inter-operate with the service. Web services are designed to be architecture and language independent, so the internal storage of data should be irrelevant. What I was trying to imply above is that the "data type" the service cares about at its exposed point is that described by the XML (e.g. xs:string, xs:int, etc)--it doesn't know if you store it internally as an int, string, Point, Rectangle, etc. Just as you store your data in some class(es), the backend of the service stores its data in a structure familiar to it.

In short what I am saying is that if the XML types and namespaces are the same for both services, and that your internal storage (which should have been generated for you when you added a service reference to the WSDL) can safely be converted to those types (which it should since .NET did the class creation for you), then I don't see a reason why you would need a reference to both services. You should be able to use the same classes for each service and just change the endpoint as necessary.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

While working on Silverlight and WCF application, I faced one issue where fault exception occurred at WCF operation contract is not getting propagated to Silverlight client. So after searching net I came to know that it was behavior by default for s…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…
Are you ready to implement Active Directory best practices without reading 300+ pages? You're in luck. In this webinar hosted by Skyport Systems, you gain insight into Microsoft's latest comprehensive guide, with tips on the best and easiest way…

710 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question