Asked by:
Creating a WCF service form a SOAP 1.1 WSDL

Question
-
User1541882437 posted
I have been trying to create a service from a supplied WSDL for an API that we need to hook into. The way this works is that we have to create the service for the API to call into and send back information to the caller. I used svcutil to create the service contract and discovered that all the Action properties were blank, which meant that it would not compile. This then lead me to this post https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/dispatch-by-body-element and on checking, I found that indeed the soapAction in the WSDL for all functions was blank. I added the three classes from the example link into my project , added the DispatchByBodyElementBehavior property, added a default method and set the other OperationContractAttribute properties as per the article. The service then compiles and runs. However, if I try and create a client for it from the service I created using Visual Studio or svcutil , it has no functions. Also if I use the WCF Test Client (by starting the VS project with the .svc file selected), I get an error message "The contract 'IViatorWCFService' in client configuration does not match the name in service contract, or there is no valid method in this contract." I have checked "always regenerate config when launching services" and refreshed but no change. The problem is possibly to do with the wild cards for ReplyAction , which is what the article indicated was required. I have tried leaving a question ion the original article, but have had no reply.The code for the interface is below. There are a bunch of other classes and properties from the WSDL, but I have not pasted those here. I am new to WCF , so I'm struggling to work out what he issue is
Help !
Many thanks in advance
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] [System.ServiceModel.ServiceContractAttribute(Namespace = "http://toursgds.com/api/01", ConfigurationName = "Custom.ViatorWebService.IViatorWCFService"), DispatchByBodyElementBehavior] public interface IViatorWCFService { [OperationContractAttribute(Action = "*", ReplyAction = "*")] void DefaultOperation(); // CODEGEN: Generating message contract since the operation cancelBooking is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction = "*"), DispatchBodyElement("cancelBooking", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.BookingCancellationResponse1 cancelBooking(Custom.ViatorWebService.BookingCancellationRequest1 request); // CODEGEN: Generating message contract since the operation sendBookingNotification is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction="*"), DispatchBodyElement("sendBookingNotification", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.BookingNotificationResponse1 sendBookingNotification(Custom.ViatorWebService.BookingNotificationRequest1 request); // CODEGEN: Generating message contract since the operation getTourList is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction="*"), DispatchBodyElement("getTourList", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.TourListResponse1 getTourList(Custom.ViatorWebService.TourListRequest1 request); // CODEGEN: Generating message contract since the operation getAvailability is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction="*"), DispatchBodyElement("getAvailability", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.AvailabilityResponse1 getAvailability(Custom.ViatorWebService.AvailabilityRequest1 request); // CODEGEN: Generating message contract since the operation amendBooking is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction="*"), DispatchBodyElement("amendBooking", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.BookingAmendmentResponse1 amendBooking(Custom.ViatorWebService.BookingAmendmentRequest1 request); // CODEGEN: Generating message contract since the operation getBatchAvailability is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction="*"), DispatchBodyElement("getBatchAvailability", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.BatchAvailabilityResponse1 getBatchAvailability(Custom.ViatorWebService.BatchAvailabilityRequest1 request); // CODEGEN: Generating message contract since the operation makeBooking is neither RPC nor document wrapped. [System.ServiceModel.OperationContractAttribute(ReplyAction="*"), DispatchBodyElement("makeBooking", "http://toursgds.com/api/01")] [System.ServiceModel.FaultContractAttribute(typeof(Custom.ViatorWebService.Error), Action = "", Name = "RequestError")] [System.ServiceModel.XmlSerializerFormatAttribute()] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourAvailabilityBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TransactionStatus))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(TourOptionsBase))] [System.ServiceModel.ServiceKnownTypeAttribute(typeof(RequestResponseBase))] Custom.ViatorWebService.BookingResponse1 makeBooking(Custom.ViatorWebService.BookingRequest1 request); }
Wednesday, September 27, 2017 2:03 AM
All replies
-
User475983607 posted
PabloInNz
I have been trying to create a service from a supplied WSDL for an API that we need to hook into.It is not possible to create a WCF service from the WSDL. The WSDL is used to create the client proxy and contains only the interface (method calls and object/properties) not the actual implementation. The implementation is in the remote service.
Use the generated client proxy to interact with the remote service just like you would any class library. First instantiate the client. That will expose the available methods. You might have to populate input/output classes to interact with the service. Basically, containers to send data back and forth. Usually, services have documentation that explains the details; inputs, outputs, and expected errors.
Wednesday, September 27, 2017 3:43 PM -
User1541882437 posted
Maybe my wording was a bit misleading. The way that the Viator API works is that you create a service that complies to their WSDL and their API then calls into your implementation of the service. It's definitely possible to create a WCF service from the WSDL. Just google "create a WCF service from WSDL" and you will find plenty of articles on just that. For example http://scrumsofanarchy.com/reverse-engineering-a-soap-web-service-in-net-wcf-2/
The issue is with trying to get the WCF service to work correctly with the the WSDL supplied, where the soapAction parameters are all blank, which is what the article linked to in the original post is doing.
Wednesday, September 27, 2017 7:20 PM -
User475983607 posted
Maybe my wording was a bit misleading. The way that the Viator API works is that you create a service that complies to their WSDL and their API then calls into your implementation of the service. It's definitely possible to create a WCF service from the WSDL. Just google "create a WCF service from WSDL" and you will find plenty of articles on just that. For example http://scrumsofanarchy.com/reverse-engineering-a-soap-web-service-in-net-wcf-2/
The issue is with trying to get the WCF service to work correctly with the the WSDL supplied, where the soapAction parameters are all blank, which is what the article linked to in the original post is doing.
I must be missing the point. I've written services for many years and there is simply no way to get the actual source code from the WSDL. The example link provided shows how to build a proxy service which is essentially forwarding requests from a WCF service under your control to the remote service. The implementation is still on the remote service. However, you are using the operation and data contracts created by the svcutil.exe.
It sounds like you are supposed to use the operational interface and data contracts exposed by the WSDL and create your own implementation that will be called by the third party?
The issue is with trying to get the WCF service to work correctly with the the WSDL supplied, where the soapAction parameters are all blank, which is what the article linked to in the original post is doing.As far as I recall, The soapAction header can be blank if the HTTP POST has the URI which maps to the action.
Wednesday, September 27, 2017 8:58 PM -
User1541882437 posted
It sounds like you are supposed to use the operational interface and data contracts exposed by the WSDL and create your own implementation that will be called by the third party?Yup, exactly
.They provide the WSDL and we have to implement it using that contract and expose the interface, as our own service. For example, there is a function called getAvailability in the interface. We implement that function in our service and they call into it. I looked originally at creating an asmx service from the WSDL which was straightforward to do. However, to do so I had to use .NET 3.5 and (correct me if I'm wrong here) as I understand it asmx is outdated technology which has been superseded by WCF. When I built the WCF , it would not run, since all the functions (such as getAvailability) had Action = "" (due to the fact that in the WSDL, soapAction=""). I can't simply set an Action name (as far as I am aware) since the client that will be calling into the service (over which I have no control) has not set the Action name. Hence why I tried to implement the code to overcome this. I'm still waiting to hear back from the Viator help desk about it. Hopefully they can offer some insight and I will post any comments they have.
Wednesday, September 27, 2017 10:34 PM -
User1168443798 posted
Hi PablolnNz,
We could not create WCF Service directly from WSDL, we could get service Interface, and then you need to implement your own WCF Service.
For getting Service Interface and DataContract, you could try below command.
svcutil.exe http://localhost/WCFHttps/Service1.svc?wsdl
This will create a file called .cs file which contains all the necessary items.
Now, you need to create a class "MyService" which will implement the service interface (IServiceInterface) - or the several service interfaces - and this is your server instance.
# How to use a WSDL file to create a WCF service (not make a call)
Best Regards,
Edward
Friday, September 29, 2017 7:50 AM -
User1541882437 posted
Thanks Edward, I have done that as I explained in the original question. The issue is that the supplied WSDL file is fairly old (SOAP 1.1) and does not confirm completely to standards. The soapAction parameters are all empty, which means the created service has Action="" in multiple functions which is not allowed, hence trying to use the linked article.
Wednesday, October 4, 2017 8:05 PM -
User1168443798 posted
Hi pabloinnz,
>> The issue is that the supplied WSDL file is fairly old (SOAP 1.1) and does not confirm completely to standards.
What is the service type which supplied WSDL? Is it .NET WCF Service or Java Web Service?
As my experience, WCF Service does not allow multiple Action="" on OperationContract.
Best Regards,
Edward
Thursday, October 5, 2017 7:22 AM