Why are the parameters of the ASMX Proxy Methods capsulated? - c#

I am adding a Service Reference to a Third-Party-ASMX Webservice in my VS2015 or VS2017 Project (Net 4.6.1).
I do this with the normal Userinterface in Visual Studio (Rightclick --> Add new Service Reference). I use the default settings and everything seems to work except that i am not happy with the generated classes.
According to the WSDL i am expecting to use the methods like this:
ServiceSoapClient ssc = new ServiceSoapClient();
object response = ssc.getEmployees("xxx", "yyy", "zzz");
But what i get is classes that i have to use like this:
ServiceSoapClient ssc = new ServiceSoapClient();
getEmployeesResponse response = ssc.getEmployees(
new getEmployeesRequest
{
Body = new getEmployeesRequestBody { Division = "xxx", Username = "yyy", Password = "zzz" }
});
Every Method needs one Request-Parameter, which itself has a Body-Element. The Body-Element has all the necessary Parameters.
The Method is defined like that when opened in the browser:
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<getEmployees xmlns="xxx">
<division>string</division>
<Username>string</Username>
<Password>string</Password>
</getEmployees>
</soap:Body>
</soap:Envelope>
That is the information for this Method in the WSDL:
<s:element name="getEmployees">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="division" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="Username" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="Password" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="getEmployeesResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="getEmployeesResult" type="tns:XMLResponse"/>
</s:sequence>
</s:complexType>
</s:element>
<wsdl:operation name="getEmployees">
<wsdl:input message="tns:getEmployeesSoapIn"/>
<wsdl:output message="tns:getEmployeesSoapOut"/>
</wsdl:operation>
<wsdl:operation name="getEmployees">
<soap:operation soapAction="http://xxx/getEmployees" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
Why do i not get a method with the three parameters of type string? Am i even able to control this on client-side or is there a common mistake?
When i provide the Webservices by myself or use other services i never had this problem before.

I found the reason. In the settings of the "Service Reference" you have to activate "Generate assynchronous operations".

Related

How to return an XML with node-soap server?

I'm making a NodeJS web service that contains API REST and SOAP methods (Im using https://www.npmjs.com/package/soap) with Express. With API REST I don't have any problem but with SOAP I have an inconvenient, when I try to consume the SOAP method from a testing C# application I can see that the parameters are going fine, but in the response I have the next error in C# (Response is not correct XML code)
When I consume the method from a NodeJS client with node-soap too the response working fine.
Part of my NodeJS code:
const express = require('express');
const bodyParser = require('body-parser');
const soap = require('soap');
const fs = require('fs');
const xml = fs.readFileSync('src/templates/ws_soap.wsdl', 'utf8');
const app = express();
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
const soap_service = {
integrations: {
pull: {
getSnapshotGIGA: function(args) {
return {
res: "HOLA"
};
},
}
}
};
app.listen(port, ip, function() {
soap.listen(app, '/integrations_service', soap_service, xml, function() {
console.log('SOAP web service started on ' + ip + ':' + port);
});
console.log('API REST started on ' + ip + ':' + port);
});
My WSDL file is next (In response I have the type string because I wanted to see how it behaved, but I need to return an object XML):
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="integrations_service" targetNamespace="http://localhost:4205/integrations_service" xmlns="http://localhost:4205/integrations_service" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<wsdl:message name="getSnapshotGIGARequest">
<wsdl:part name="User" type="xs:string"/>
<wsdl:part name="Password" type="xs:string"/>
</wsdl:message>
<wsdl:message name="getSnapshotGIGAResponse">
<wsdl:part name="res" type="xs:string"/>
</wsdl:message>
<wsdl:portType name="pull_integrations">
<wsdl:operation name="getSnapshotGIGA">
<wsdl:input message="getSnapshotGIGARequest"/>
<wsdl:output message="getSnapshotGIGAResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="pull_integrations_binding" type="pull_integrations">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getSnapshotGIGA">
<soap:operation soapAction="getSnapshotGIGA"/>
<wsdl:input>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="integrations">
<wsdl:port binding="pull_integrations_binding" name="pull">
<soap:address location="http://localhost:4205/integrations_service"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
In C# I have an console application and I have registered the SOAP service as a web referency.
The way I consume the SOAP method is (When I make a SOAP Service with C# I test methods from this way too because is the way clients working):
Console.WriteLine("Consume NodeJS SOAP service");
Thread.Sleep(500);
integrations_service.integrations integrations = new integrations_service.integrations();
integrations.Url = "http://localhost:4205/integrations_service?wsdl";
var some_response = integrations.getSnapshotGIGA("myuser", "123456");
Console.WriteLine("Press enter to out...");
I want to get the response in and XmlNode like in this example:
Console.WriteLine("Consume C# SOAP service");
Thread.Sleep(500);
serviceSOAP sSOAP = new serviceSOAP ();
sSOAP.Url = "http://my.domain.com.mx/";
XmlNode xmlNode = sSOAP .anyMethodSoap("yomero", "123456");
Console.WriteLine(XElement.Parse(xmlNode.OuterXml).ToString());
Thread.Sleep(500);
If you know how I can return the XML from NodeJS and get it correctly in C# or any idea, I would appreciate it. Reggards.
Answer to my question, the problem was the WSDL configuration. With this configuration I made this works with C# web reference. The principal problem, the style, I changed it from "rpc" to "document" and configure correctly the element for the response.
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
name="devices_service"
targetNamespace="http://localhost:4205/devices_service"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:s="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://localhost:4205/devices_service">
<wsdl:types>
<xs:schema targetNamespace="http://localhost:4205/devices_service" xmlns="http://localhost:4205/devices_service" attributeFormDefault="qualified" elementFormDefault="qualified">
<xs:element name="GetDevicesRequest">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="User" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" name="Password" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="GetDevicesResponse">
<xs:complexType>
<xs:sequence>
<xs:any/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</wsdl:types>
<wsdl:message name="GetDevicesSoapIn">
<wsdl:part name="parameters" element="GetDevicesRequest"/>
</wsdl:message>
<wsdl:message name="GetDevicesSoapOut">
<wsdl:part name="parameters" element="GetDevicesResponse"/>
</wsdl:message>
<wsdl:portType name="user_devices">
<wsdl:operation name="GetDevices">
<wsdl:input message="GetDevicesSoapIn"/>
<wsdl:output message="GetDevicesSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="user_devices_binding" type="user_devices">
<s:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
<wsdl:operation name="GetDevices">
<s:operation soapAction="http://localhost:4205/devices_services/GetDevices"/>
<wsdl:input>
<s:body use="literal" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</wsdl:input>
<wsdl:output>
<s:body use="literal" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="devices">
<wsdl:port binding="user_devices_binding" name="user">
<s:address location="http://localhost:4205/devices_service"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>**
You'll probably want to use one of:
node-soap
strong-soap (rewrite of node-soap)
easysoap

How should WSDL be structured?

As I am new to WSDL, WCF and SOAP, I have no real clue how I should structure the WSDL.
My problem right now is that when a user logs in using their username//password, the server should respond with data owned by the user. Lets say the data that wants to be sent back are:
MatterID
MatterTitle
MatterText
MatterDate
The problem is that each user can own more than 1 matter and my problem is that I have no idea how to parse more than the first Matter that the server send as response. My WSDL is structured something like this:
IN:
username
password
OUT:
int MatterID
str MatterTitle
str MatterText
int MatterDate
Am I doing it wrong? Should I respond with a list instead containing all the data? Or is there a way to loop through a response?
If you have an array of data to return, you better define a list in the WSDL (the types section) like so:
<wsdl:types>
<s:schema xmlns:s="http://www.w3.org/2001/XMLSchema" targetNamespace="http://localhost/SampleService" elementFormDefault="unqualified" attributeFormDefault="unqualified">
<s:complexType name="MatterItemType"> <!-- List Item -->
<s:sequence>
<s:element name="MatterID" type="s:integer" minOccurs="1" maxOccurs="1"/>
<s:element name="MatterTitle" type="s:string" minOccurs="1" maxOccurs="1"/>
<s:element name="MatterText" type="s:string" minOccurs="1" maxOccurs="1"/>
<s:element name="MatterDate" type="s:integer" minOccurs="1" maxOccurs="1"/>
</s:sequence>
</s:complexType>
<s:complexType name="MatterListType"> <!-- List -->
<s:sequence>
<s:element name="MatterItem" type="tns:MatterItemType" minOccurs="0" maxOccurs="unbounded"/>
</s:sequence>
</s:complexType>
<!-- Request and Response -->
<s:element name="SampleRequest">
<s:complexType>
<s:sequence>
<s:element name="username" type="s:string" minOccurs="1" maxOccurs="1"/>
<s:element name="password" type="s:string" minOccurs="1" maxOccurs="1"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="SampleResponse">
<s:complexType>
<s:sequence>
<s:element name="MatterList" type="tns:MatterListType" minOccurs="1" maxOccurs="1"/>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
The Response always contains a MatterList element which is of MatterListType. The MatterListType contains from 0 to N MatterItem items defined in the MatterItemType.
The response will be structured something like this (not including SOAP envelope, namespaces, etc, just for illustration of the structure):
<SampleResponse>
<MatterList>
<MatterItem>
<MatterID>1</MatterID>
<MatterTitle>Title1</MatterTitle>
<MatterText>Text1</MatterText>
<MatterDate>1</MatterDate>
</MatterItem>
<MatterItem>
<MatterID>2</MatterID>
<MatterTitle>Title2</MatterTitle>
<MatterText>Text2</MatterText>
<MatterDate>2</MatterDate>
</MatterItem>
</MatterList>
</SampleResponse>
Let me know if you need more help in the comments.

Editing the WSDL generated by a web service

I have a basic web service that parses XML sent from a client. The web service works fine but I was asked to remove elements from the WSDL file generated by the web service. Is it even possible to do this?
Here are the first lines from the WSDL file:
<wsdl:definitions targetNamespace="localhost">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="localhost">
<s:element name="HTTPWebService">
<s:complexType/>
</s:element>
<s:element name="HTTPWebServiceResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="HTTPWebServiceResult">
<s:complexType mixed="true">
<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="HTTPWebServiceSoapIn">
<wsdl:part name="parameters" element="tns:HTTPWebService"/>
</wsdl:message>
Is it possible to remove the lines <s:element name="HTTPWebServiceResponse"> and it's contents, and <s:element name="HTTPWebServiceResponse">?
WSDL is a system generated xml file and editing its content may cause unexpected behavior and may not be load during introspecting. You cannot edit those lines without understanding what functionality these elements do.

Mapping WSDL enumeration to string in ASP.NET webservice

Background:
I'm in the process of creating a web service using ASP.NET 2.0. This web service provides another interface to an existing web form which contains selection boxes dynamically populated from a database.
My first draft of the web service accepted a string for each of these and then ensured that it was valid, throwing back an error if it wasn't. However the consumer of the web service has asked, since the possible values aren't likely to change all that often, that we provide enumerated values in the WSDL.
I am reluctant to create an enumeration with my web service code, so I have instead altered the generated WSDL file and instructed my web service to use that instead of inspecting my classes to generate it.
WSDL:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://example.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://example.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://example.org/">
<s:element name="MyMethod">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="myClass" type="tns:MyClass" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="MyClass">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="MyString" type="tns:MyStringPossibleValues" />
</s:sequence>
</s:complexType>
<s:element name="MyMethodResponse">
<s:complexType />
</s:element>
<s:simpleType name="MyStringPossibleValues">
<s:restriction base="s:string">
<s:enumeration value="alpha" />
<s:enumeration value="bravo" />
</s:restriction>
</s:simpleType>
</s:schema>
</wsdl:types>
<wsdl:message name="MyMethodSoapIn">
<wsdl:part name="parameters" element="tns:MyMethod" />
</wsdl:message>
<wsdl:message name="MyMethodSoapOut">
<wsdl:part name="parameters" element="tns:MyMethodResponse" />
</wsdl:message>
<wsdl:portType name="ExternalAccessSoap">
<wsdl:operation name="MyMethod">
<wsdl:input message="tns:MyMethodSoapIn" />
<wsdl:output message="tns:MyMethodSoapOut" />
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="ExternalAccessHttpGet" />
<wsdl:portType name="ExternalAccessHttpPost" />
<wsdl:binding name="ExternalAccessSoap" type="tns:ExternalAccessSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="MyMethod">
<soap:operation soapAction="http://example.org/MyMethod" style="document" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:binding name="ExternalAccessSoap12" type="tns:ExternalAccessSoap">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="MyMethod">
<soap12:operation soapAction="http://example.org/MyMethod" style="document" />
<wsdl:input>
<soap12:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap12:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
</wsdl:definitions>
Webservice:
namespace Example.Service
{
[WebService(Namespace = "http://example.org/")]
[WebServiceBinding(
ConformsTo = WsiProfiles.BasicProfile1_1,
Location="ExternalAccess.wsdl",
Name="ExternalAccessSoap",
Namespace = "http://example.org/")]
[ToolboxItem(false)]
public class ExternalAccess : System.Web.Services.WebService
{
public class MyClass
{
public string MyString;
}
[WebMethod]
[SoapDocumentMethod(
Action = "http://example.org/MyMethod",
RequestNamespace = "http://example.org/",
Binding="ExternalAccessSoap")]
public void MyMethod(MyClass myClass)
{
}
}
}
The problem:
As the WSDL specifies an enumeration for MyString and the code specified a string type, ASP.NET does not manage to map the fields correctly.
Is there an attribute I can use to instruct the deserialiser to populate the string field with the value of the enumeration?
Regards,
Matt
Having gone through the process of creating a soap extension to do this for me I discovered that MyString wasn't actually being sent to my web service.
This was because the test application for this service was built in .NET also and, when building the request object, the MyStringSpecified property of the generated proxy class was overlooked. This then prevented the enumerated value being sent as part of the SOAP request.
When this property was set to true, the enumerated value was successfully assigned to the MyString field in the webservice.

Supporting XSDs with attributes in WCF

We have some XSDs in our project that define types that use attributes, as well as elements, to specify property values, e.g.:
<Instrument name="blah">
</Instrument>
I use these XSDs to define a schema used by a WSDL, but when I run it through schemagen, the generated code is unwrapped. For example:
public interface InstrumentService
{
// CODEGEN: Parameter 'GetInstrumentResponse' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlElementAttribute'.
GetInstrumentResponse GetInstrument(GetInstrumentRequest request);
}
(the GetInstrumentRequest and GetInstrumentResponse should be unwrapped to the parameters and return value only).
The reason for this is that the data contract serializer doesn't support complex types with attributes, but I did read somewhere that if you use document/literal, rather than document/literal wrapped to define the WSDL, schemagen will fall back to an XmlSerializer implementation, that does support attributes. So far, my attempts to get this to work have failed:
// CODEGEN: Generating message contract since the operation GetInstrument is neither RPC nor document wrapped.
So, is this assumption about document/literal faulty? Is there any way to generate unwrapped interface code from a WSDL that defines complex types with attributes?
Here's the modified document/literal WSDL I am using:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
targetNamespace="http://tempuri.org/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:tns="http://tempuri.org/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xs:schema targetNamespace="http://tempuri.org/">
<xs:complexType name="testComplexType">
<xs:sequence/>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
<xs:element name="input" type="tns:testComplexType"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="GetInstrumentIn">
<wsdl:part element="tns:input" name="input"/>
</wsdl:message>
<wsdl:message name="GetInstrumentOut"/>
<wsdl:portType name="InstrumentService">
<wsdl:operation name="GetInstrument">
<wsdl:input message="tns:GetInstrumentIn"/>
<wsdl:output message="tns:GetInstrumentOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="InstrumentService" type="tns:InstrumentService">
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetInstrument">
<soap:operation soapAction="GetInstrument" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="InstrumentService">
<wsdl:port binding="tns:InstrumentService" name="InstrumentService"/>
</wsdl:service>
</wsdl:definitions>
apologies for answering my own question. It seems that just removing the nillable="true" statement from the operation response type, in th document/literal/wrapped WSDL types schema does the trick - no need to drop to document/literal.
<wsdl:types>
<xs:schema elementFormDefault="qualified" targetNamespace="http://com.barcap.cbts.core.messaging.rpc/">
<xs:element name="GetInstrument">
<xs:complexType/>
</xs:element>
<xs:element name="GetInstrumentResponse">
<xs:complexType>
<xs:sequence>
<!-- nillable="true" removed -->
<xs:element maxOccurs="1" minOccurs="0"
name="GetInstrumentResponse" type="tns:Instrument"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="Instrument">
<xs:sequence/>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:schema>
</wsdl:types>

Categories

Resources