I want to send a mock response from my service when the request matches on these characteristics:
URL matches with /BATConnectWS/services/CoverApplication
The HTTP method matches with POST
The XPath matcher must match an amount of 5000
Code setup:
var server = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://+:8099" },
StartAdminInterface = true,
Logger = new WireMockConsoleLogger()
});
server
.Given(Request.Create().WithPath("/*")).AtPriority(10)
.RespondWith(Response.Create()
.WithProxy("https://TheRealService.com/"));
server
.Given(Request.Create().WithPath("/BATConnectWS/services/CoverApplication").UsingPost()
.WithBody(new XPathMatcher(#"//applyForCreditLimit/application/RequestedAmount/text() = 5000")))
.AtPriority(1)
.RespondWith(Response.Create()
.WithHeader("Content-Type", "text/xml; charset=utf-8")
.WithCallback(req =>
{
return CoverApplicationResponseBuilder.CreateResponse(req);
}));
The request message:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soap:Header>
<wsa:Action>urn:applyForCreditLimit</wsa:Action>
<wsa:MessageID>urn:uuid:6da4a592-90a0-4623-8c71-1e685cbdac33</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To>http://localhost:58070/BATConnectWS/services/CoverApplication</wsa:To>
<wsse:Security soap:mustUnderstand="1">
<wsu:Timestamp wsu:Id="Timestamp-6befddc7-4e4f-4a76-a203-49b729bd483a">
<wsu:Created>2019-10-15T08:22:37Z</wsu:Created>
<wsu:Expires>2019-10-15T08:27:37Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-x-x-x-x-x">
<wsse:Username>xxx</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">xxx</wsse:Password>
<wsse:Nonce>xxx</wsse:Nonce>
<wsu:Created>2019-10-15T08:22:37Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<applyForCreditLimit xmlns="http://atradius.com/connect/_2007_08/">
<application>
<CustomerId xmlns="">1234</CustomerId>
<PolicyNr policyTypeIdentifier="NON_LEG" xmlns="">
<Id>5678</Id>
</PolicyNr>
<ExternalCoverId xmlns="">9101112</ExternalCoverId>
<CustomerReference xmlns="">areference</CustomerReference>
<Buyer registeredOffice="SYMPH" xmlns="">
<id xmlns="http://atradius.com/organisation/_2007_08/type/">13141516</id>
<countryTypeIdentifier xmlns="http://atradius.com/organisation/_2007_08/type/">AUT</countryTypeIdentifier>
</Buyer>
<RequestedAmount xmlns="">5000</RequestedAmount>
<CurrencyCode xmlns="">EUR</CurrencyCode>
</application>
</applyForCreditLimit>
</soap:Body>
</soap:Envelope>
Without the XPathMatcher the mocked response will be sent.
With the XPatchMatcher the real service will be called (pass through), because there was no WithBody match on the content.
What should the XPath query be like to match on the amount of 5000, in the RequestedAmount element?
This has to do with the namespaces used maybe?
If you are only interested if any RequestedAmount element with value 5000 exists in the soap message, you could just use this I think:
#"//RequestedAmount/text() = 5000"
Related
So I am working on an internal project where I am consuming a Java based SOAP Web Service from a WinForm application using a WCF Service Reference interface. (This is something new for me so I apologize if I not totally using the right terminology, etc.) I am sending my request over to the service and I am getting a response, although it has taken some hoop jumping to get there. The format of the response is what is causing me some problems in that it has excessive namespaces and the response size can get large.
I hope someone can point me to a simple solution / setting to reduce the excess.
A few things that I have no control over: The interface is via HTTP (not HTTPS) and security is handled via an App Key/ID mechanism using the a SOAP Security Header and client certificates. The server WSDL does not indicate that WSSE is required in the SOAP Header so the header is being overwritten by the security one prior to the send.
All items below are actual code structure and SOAP request/response format but have been changed to generic items. Also, the "response" is greatly reduced in size. With the right request parameters, a response is over 64k in length.
The SoapUI Request 1 example built with the WSDL load looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pric="http://xmlns.example.com/system/pricing" xmlns:ns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<soapenv:Header/>
<soapenv:Body>
<pric: PricingRequest majorVersion="2" minorVersion="1">
<pric:version>?</pric:version>
<pric:timestamp>?</pric:timestamp>
<!--1 or more repetitions:-->
<pric:acctType>
<!--You have a CHOICE of the next 2 items at this level-->
<pric:customerNbr>?</pric: customerNbr >
<pric:accountNbr>?</pric:accountNbr>
</pric: acctType >
<!--1 to 3 repetitions:-->
<pric:system>?</pric: system >
<pric:source>?</pric:source>
<pric:searchItems>
<pric:purchaseDate>?</pric: purchaseDate >
<!--Zero or more repetitions:-->
<pric:service>
<ns:system>?</ns:system>
<ns:serviceType>?</ns:serviceType>
<!--Optional:-->
<ns:serviceDesc>?</ns:serviceDesc>
<!--Optional:-->
<ns:billingType>?</ns:billingType>
<!--Optional:-->
<ns:effectiveDate>?</ns:effectiveDate>
<!--Optional:-->
<ns:expirationDate>?</ns:expirationDate>
<!--Optional:-->
</pric:service>
</pric: searchItems >
</pric: PricingRequest >
</soapenv:Body>
</soapenv:Envelope>
The app.config Service Model - I added the maxReceivedMessageSize in order to handle the large responses:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="PricingServiceSoap11" maxReceivedMessageSize="256000" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://pricing-websvc.example.com:60000/PricingService"
binding="basicHttpBinding" bindingConfiguration="PricingServiceSoap11"
contract="pricingSvcRef.PricingService" name="PricingServiceSoap11" />
</client>
</system.serviceModel>
Code to consume service:
pricingSvcRef.PricingClient pricing = new pricingSvcRef.PricingClient();
var reqInfo = new InspectorBehavior();
pricing.Endpoint.Behaviors.Add(reqInfo);
pricingSvcRef.PricingRequest request = new pricingSvcRef.PricingRequest();
request.majorVersion = 2;
request.minorVersion = 1;
request.version = pricingSvcRef.PricingRequestVersion.Ver1;
request.timestamp = DateTime.Now;
request.acctType = new pricingSvcRef.PricingRequestAcctType[1];
request.acctType[0] = new pricingSvcRef.GetPricingRequestAcctype();
request.acctType[0].Item = txtAcctNo.Text.Trim();
request.system = "Pricing";
request.source = "MyApp";
List<pricingSvcRef.pricingService> svcList = new List<pricingSvcRef.pricingService>();
svcList.Add(
new pricingSvcRef.pricingService
{
system = txtSystem.Text.Trim(),
serviceType = Convert.ToInt32(txServiceType.Text.Trim(),
serviceDesc = txtService.Text.Trim(),
billingType = Convert.ToInt32(txBillingType.Text.Trim(),
effectiveDate = dateEffective.Value,
expirationDate = dateExpiration.Value
});
pricingSvcRef.PricingRequestSearchItems srchItems = new pricingSvcRef.PricingRequestSearchItems
{
purchaseDate = DateTime.Now;
service = svcList.ToArray(),
};
request.searchItems = srchItems;
pricingSvcRef.PricingResponse response = null;
try
{
response = eddSvcRef.GetPricing(request);
}
catch (Exception ex)
{
string msg = "Msg: " + ex.Message;
if ((ex.InnerException != null) && (ex.InnerException.Message.Trim().Length > 0))
msg = msg + "\r\n\r\nInner Msg: " + ex.InnerException.Message.Trim();
MessageBox.Show(msg);
}
SOAP Request that is generated:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>v1:APP1234567:SfPLRHKdXWWqW7mdOdk+gTABVo+y4VZR7UqLHWibVD73jaI0IL9FT4PMgAVAxGsa83P/aon61GuS+IZnuVjRHR4hJgyMuCvtI07QtNaSdwEyw9Lw/Iewm+098fkMYK2pflV7w6hn0U2A9/wzuQS/vfWe53vhGSX1zfhuo6AygKA=:APP1234567</wsse:Username>
</wsse:UsernameToken>
</Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PricingRequest majorVersion="2" minorVersion="1" xmlns="http://xmlns.example.com/system/pricing">
<version>1.0.0</version>
<timestamp>2019-03-25T09:46:26.7337264-05:00</timestamp>
<acctType>
<accountNbr>123456789</accountNbr>
</acctType>
<system>Pricing</system>
<source>MyApp</source>
<searchItems>
<purchaseDate>2019-03-25</purchaseDate>
<service>
<system xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">MyPricing</system>
<serviceType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1000</serviceType>
<serviceDesc xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Service Description</serviceDesc>
<billingType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1234</billingType>
<effectiveDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-01-01</effectiveDate>
<expirationDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-12-31</expirationDate>
</service>
</searchItems>
</PricingRequest>
</s:Body>
</s:Envelope>
SOAP Response in application:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header />
<SOAP-ENV:Body>
<PricingResponse xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1" xmlns:ns2="http://xmlns.example.com/system/pricing">
<pricingContainer xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<version xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1.0.0</version>
<timestamp xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-03-25T14:46:28.876Z</timestamp>
<source xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">MyApp</source>
<status xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<code xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">0000</code>
<description xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">SUCCESS</description>
</status>
<acctType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<accountNbr xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">123456789</accountNbr>
</acctType>
<system xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Pricing</system>
<serviceDetail xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">
<valid xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Y</valid>
<system xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">MyPricing</system>
<serviceType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1000</serviceType>
<serviceDesc xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">Service Description</serviceDesc>
<billingType xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">1234</billingType>
<effectiveDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-01-01</effectiveDate>
<expirationDate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">2019-12-31</expirationDate>
<pricingRate xmlns="http://xmlns.example.com/system/pricing/shared/3.1.1">100</pricingRate>
</serviceDetail>
</pricingContainer>
</PricingResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
So even though namespaces are returning as part of the PricingResponse element, they are also on each child item below that.
UPDATE: I thought SoapUI responses were coming back w/o the excessive namespace items on each element but I have now determined using Wireshark and SoapUI Raw display that this not the case.
Is there anyway to request from the WCF Interface to the Java Web Service that the response uses namespace prefixes rather than having a namespace on almost every response element? Obviously I am going to keep digging at it but any help / guidance would be appreciated.
Thanks
I'm trying to get some Data from a WebAPI via the POST method. The API is a public transport data API and sends/ receives XML serialized data. When I call the API from Postman I get the data, when I try to do the same from C# although I receive a Message with the status code 200 the ContentLength is -1 and I can't read any data from it.
My C# API Call and stream generation:
var stream = new MemoryStream();
serializer.Serialize(stream, toSend);
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = await
client.PostAsync("https://api.opentransportdata.swiss/trias",
new StringContent(new StreamReader(stream,
Encoding.UTF8).ReadToEnd(), Encoding.UTF8, "text/xml"));
Where my stream is a MemoryStream that contains my XML Serialized data.
The Response Message is 200 (OK) but the content is empty, when I do the same with Postman it works.
Here's the serialized XML Data I'm sending that I read from the Stream the same way I'm reading it to send it to the API
<?xml version="1.0" encoding="utf-16"?>
<Trias xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="1.1" xmlns="http://www.vdv.de/trias">
<ServiceRequest>
<siri_x003A_RequestTimestamp>2018-10-09T10:31:56.2886025+02:00</siri_x003A_RequestTimestamp>
<siri_x003A_RequestorRef>SEUS</siri_x003A_RequestorRef>
<RequestPayload>
<TripRequest>
<Origin>
<LocationRef>
<StopPointRef>8500320</StopPointRef>
</LocationRef>
</Origin>
<Destination>
<LocationRef>
<StopPointRef>8500322</StopPointRef>
</LocationRef>
</Destination>
</TripRequest>
<Params>
<NumberOfResults>0</NumberOfResults>
<IncludeTrackSections>false</IncludeTrackSections>
<IncludeLegProjection>false</IncludeLegProjection>
<IncludeIntermediateStops>false</IncludeIntermediateStops>
</Params>
</RequestPayload>
</ServiceRequest>
</Trias>
And here's the expected result:
<?xml version="1.0" encoding="UTF-8"?>
<Trias xmlns="http://www.vdv.de/trias" version="1.1">
<ServiceDelivery>
<ResponseTimestamp xmlns="http://www.siri.org.uk/siri">2018-10-09T08:33:26Z</ResponseTimestamp>
<ProducerRef xmlns="http://www.siri.org.uk/siri">EFAController10.2.9.62-WIN-G0NJHFUK71P</ProducerRef>
<Status xmlns="http://www.siri.org.uk/siri">true</Status>
<MoreData>false</MoreData>
<Language>de</Language>
<DeliveryPayload>
<TripResponse>
<TripResult>
<ResultId>ID-A24DE912-0263-4067-AD73-591DF01F4B05</ResultId>
<Trip>
<TripId>ID-E442EC5E-1B70-4E9D-836F-47585406D2F7</TripId>
<Duration>PT7M</Duration>
<StartTime>2018-10-09T08:19:00Z</StartTime>
<EndTime>2018-10-09T08:26:00Z</EndTime>
<Interchanges>0</Interchanges>
<TripLeg>
<LegId>1</LegId>
<TimedLeg>
<LegBoard>
<StopPointRef>8500320</StopPointRef>
<StopPointName>
<Text>Stein-Säckingen</Text>
<Language>de</Language>
</StopPointName>
<PlannedBay>
<Text>2</Text>
<Language>de</Language>
</PlannedBay>
<ServiceDeparture>
<TimetabledTime>2018-10-09T08:19:00Z</TimetabledTime>
</ServiceDeparture>
<StopSeqNumber>1</StopSeqNumber>
</LegBoard>
<LegAlight>
<StopPointRef>8500322</StopPointRef>
<StopPointName>
<Text>Laufenburg</Text>
<Language>de</Language>
</StopPointName>
<PlannedBay>
<Text>1</Text>
<Language>de</Language>
</PlannedBay>
<ServiceArrival>
<TimetabledTime>2018-10-09T08:26:00Z</TimetabledTime>
</ServiceArrival>
<StopSeqNumber>2</StopSeqNumber>
</LegAlight>
<Service>
<OperatingDayRef>2018-10-09</OperatingDayRef>
<JourneyRef>odp:04001::H:j18:17235:17235</JourneyRef>
<LineRef>odp:04001::H</LineRef>
<DirectionRef>outward</DirectionRef>
<Mode>
<PtMode>rail</PtMode>
<RailSubmode>suburbanRailway</RailSubmode>
<Name>
<Text>S-Bahn</Text>
<Language>de</Language>
</Name>
</Mode>
<PublishedLineName>
<Text>1</Text>
<Language>de</Language>
</PublishedLineName>
<OperatorRef>odp:11</OperatorRef>
<OriginText>
<Text></Text>
<Language>de</Language>
</OriginText>
<DestinationStopPointRef>8500322</DestinationStopPointRef>
<DestinationText>
<Text>Laufenburg</Text>
<Language>de</Language>
</DestinationText>
</Service>
</TimedLeg>
</TripLeg>
</Trip>
</TripResult>
<TripResult>
<ResultId>ID-CE13C278-DFBE-4AFF-8318-1E96EEE6FA9B</ResultId>
<Trip>
<TripId>ID-832873CC-4085-4131-9265-D5EF1F80DBF6</TripId>
<Duration>PT25M</Duration>
<StartTime>2018-10-09T08:35:00Z</StartTime>
<EndTime>2018-10-09T09:00:00Z</EndTime>
<Interchanges>0</Interchanges>
<TripLeg>
<LegId>1</LegId>
<InterchangeLeg>
<InterchangeMode>walk</InterchangeMode>
<LegStart>
<StopPointRef>8500320</StopPointRef>
<LocationName>
<Text>Stein-Säckingen</Text>
<Language>de</Language>
</LocationName>
</LegStart>
<LegEnd>
<StopPointRef>8572748</StopPointRef>
<LocationName>
<Text>Stein-Säckingen, Bahnhof</Text>
<Language>de</Language>
</LocationName>
</LegEnd>
<TimeWindowStart>2018-10-09T08:35:00Z</TimeWindowStart>
<TimeWindowEnd>2018-10-09T08:39:00Z</TimeWindowEnd>
<Duration>PT4M</Duration>
</InterchangeLeg>
</TripLeg>
<TripLeg>
<LegId>2</LegId>
<TimedLeg>
<LegBoard>
<StopPointRef>8572748</StopPointRef>
<StopPointName>
<Text>Stein-Säckingen, Bahnhof</Text>
<Language>de</Language>
</StopPointName>
<ServiceDeparture>
<TimetabledTime>2018-10-09T08:39:00Z</TimetabledTime>
</ServiceDeparture>
<StopSeqNumber>1</StopSeqNumber>
</LegBoard>
<LegAlight>
<StopPointRef>8572403</StopPointRef>
<StopPointName>
<Text>Laufenburg, Bahnhof</Text>
<Language>de</Language>
</StopPointName>
<ServiceArrival>
<TimetabledTime>2018-10-09T08:56:00Z</TimetabledTime>
</ServiceArrival>
<StopSeqNumber>10</StopSeqNumber>
</LegAlight>
<Service>
<OperatingDayRef>2018-10-09</OperatingDayRef>
<JourneyRef>odp:01143::R:j18:14332:14332</JourneyRef>
<LineRef>odp:01143::R</LineRef>
<DirectionRef>return</DirectionRef>
<Mode>
<PtMode>bus</PtMode>
<BusSubmode>regionalBus</BusSubmode>
<Name>
<Text>Bus</Text>
<Language>de</Language>
</Name>
</Mode>
<PublishedLineName>
<Text>143</Text>
<Language>de</Language>
</PublishedLineName>
<OperatorRef>odp:801</OperatorRef>
<Attribute>
<Text>
<Text>Linie 143: 1555</Text>
<Language>de</Language>
</Text>
<Code>Y3933</Code>
<Mandatory>false</Mandatory>
</Attribute>
<OriginText>
<Text></Text>
<Language>de</Language>
</OriginText>
<DestinationText>
<Text>Laufenburg, Bahnhof
</Text>
<Language>de</Language>
</DestinationText>
</Service>
</TimedLeg>
</TripLeg>
<TripLeg>
<LegId>3</LegId>
<InterchangeLeg>
<InterchangeMode>walk</InterchangeMode>
<LegStart>
<StopPointRef>8572403</StopPointRef>
<LocationName>
<Text>Laufenburg, Bahnhof</Text>
<Language>de</Language>
</LocationName>
</LegStart>
<LegEnd>
<StopPointRef>8500322</StopPointRef>
<LocationName>
<Text>Laufenburg</Text>
<Language>de</Language>
</LocationName>
</LegEnd>
<TimeWindowStart>2018-10-09T08:56:00Z</TimeWindowStart>
<TimeWindowEnd>2018-10-09T09:00:00Z</TimeWindowEnd>
<Duration>PT4M</Duration>
</InterchangeLeg>
</TripLeg>
</Trip>
</TripResult>
<TripResult>
<ResultId>ID-7C9B4974-1D9D-4828-98BB-5A7022CD55B1</ResultId>
<Trip>
<TripId>ID-2FB9793D-93E8-495D-9802-0ECC6C4B98F3</TripId>
<Duration>PT6M</Duration>
<StartTime>2018-10-09T09:19:00Z</StartTime>
<EndTime>2018-10-09T09:25:00Z</EndTime>
<Interchanges>0</Interchanges>
<TripLeg>
<LegId>1</LegId>
<TimedLeg>
<LegBoard>
<StopPointRef>8500320</StopPointRef>
<StopPointName>
<Text>Stein-Säckingen</Text>
<Language>de</Language>
</StopPointName>
<PlannedBay>
<Text>2</Text>
<Language>de</Language>
</PlannedBay>
<ServiceDeparture>
<TimetabledTime>2018-10-09T09:19:00Z</TimetabledTime>
<EstimatedTime>2018-10-09T09:19:00Z</EstimatedTime>
</ServiceDeparture>
<StopSeqNumber>1</StopSeqNumber>
</LegBoard>
<LegAlight>
<StopPointRef>8500322</StopPointRef>
<StopPointName>
<Text>Laufenburg</Text>
<Language>de</Language>
</StopPointName>
<PlannedBay>
<Text>1</Text>
<Language>de</Language>
</PlannedBay>
<ServiceArrival>
<TimetabledTime>2018-10-09T09:26:00Z</TimetabledTime>
<EstimatedTime>2018-10-09T09:25:00Z</EstimatedTime>
</ServiceArrival>
<StopSeqNumber>2</StopSeqNumber>
</LegAlight>
<Service>
<OperatingDayRef>2018-10-09</OperatingDayRef>
<JourneyRef>odp:04001::H:j18:17239:17239</JourneyRef>
<LineRef>odp:04001::H</LineRef>
<DirectionRef>outward</DirectionRef>
<Mode>
<PtMode>rail</PtMode>
<RailSubmode>suburbanRailway</RailSubmode>
<Name>
<Text>S-Bahn</Text>
<Language>de</Language>
</Name>
</Mode>
<PublishedLineName>
<Text>1</Text>
<Language>de</Language>
</PublishedLineName>
<OperatorRef>odp:11</OperatorRef>
<OriginText>
<Text></Text>
<Language>de</Language>
</OriginText>
<DestinationStopPointRef>8500322</DestinationStopPointRef>
<DestinationText>
<Text>Laufenburg</Text>
<Language>de</Language>
</DestinationText>
</Service>
</TimedLeg>
</TripLeg>
</Trip>
</TripResult>
</TripResponse>
</DeliveryPayload>
</ServiceDelivery>
</Trias>
You can try this for yourself here (just change the "Template" to "TripRequest")
I figured it out.
In the client.PostAsync(...) I was telling the API I am posting Encoding.UTF8 encoded data, but my serializer was generating ibm850 encoded Data
I am new to using Webservice. I implemented a soap Post action to an external Company. Working great. I now want to start creating my own for people to interact with us. I have created the basic add service as all tutorial etc.
Now I want to create a service that you place orders from. Currently I just write the order to a text file with the PO nr as the file name. Got testing working with submitting just 1 item to it. But I want them to pass it with mutiple items on the call. Here is what I got now.
c#
public struct OrderSystem
{
public string ResultMsg;
}
[WebMethod(MessageName = "Submit Order", Description = "Submit Order")]
public OrderSystem Order(string Custnr,string POnr, string[] Item , int[] qty)
{
using (System.IO.StreamWriter file =
new System.IO.StreamWriter(#"C:\Users\Public\TestFolder\"+POnr+".txt"))
{
file.WriteLine(Custnr);
file.WriteLine(POnr);
for (int i =0; i< Item.Length; i++)
{
file.WriteLine("LineItem" + i +Item[i] + " | "+qty[i]);
}
}
OrderSystem result;
result.ResultMsg = "Complete";
return (result);
}
Current XML way to call it. Not friendly for them to design a Call to me
POST /Orders.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Submit Order"
<?xml version="1.0" encoding="utf-8"?>
<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>
<Submit_x0020_Order xmlns="http://tempuri.org/">
<Custnr>string</Custnr>
<POnr>string</POnr>
<Item>
<string>string</string>
<string>string</string>
</Item>
<qty>
<int>int</int>
<int>int</int>
</qty>
</Submit_x0020_Order>
</soap:Body>
</soap:Envelope>
How I want to make the xml call file to look at.
POST /Orders.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Submit Order"
<?xml version="1.0" encoding="utf-8"?>
<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>
<Submit_x0020_Order xmlns="http://tempuri.org/">
<Custnr>000223</Custnr>
<POnr>988590</POnr>
<ItemList>
<Item>
<ItemNr>1</Item>
<Item>ABC123</Item>
<Qty>2</Qty>
</Item>
<Item>
<ItemNr>2</Item>
<Item>ASC123</Item>
<Qty>45</Qty>
</Item>
<Item>
<ItemNr>3</Item>
<Item>XYZKKF</Item>
<Qty>4</Qty>
</Item>
<Item>
<ItemNr>4</Item>
<Item>FGH789</Item>
<Qty>6</Qty>
</Item>
</ItemList>
</Submit_x0020_Order>
</soap:Body>
</soap:Envelope>
How Can I go about and Change my C# service to handle that XML file.
Thank you in advance
Regards
First of all, don't create new services using ASMX in 2018. It's been deprecated for a couple of years already. Use WCF or Web API.
The solution applies to all technologies. Simply create a class:
public class Item
{
public string ItemNr { get; set; }
public int Quantity { get; set; }
}
And let your service accept a list of that class.
I have an XML file (it's a SOAP request to an SAP ME Service).
The file looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:me="http://sap.com/xi/ME">
<soapenv:Header />
<soapenv:Body>
<me:ShopOrderByBasicDataQuery_sync>
<me:ShopOrderByBasicDataQuery>
<me:ShopOrder>BOXBUILD_LASER_TEST</me:ShopOrder>
<me:SiteRef>
<me:Site>TEST1</me:Site>
</me:SiteRef>
</me:ShopOrderByBasicDataQuery>
</me:ShopOrderByBasicDataQuery_sync>
</soapenv:Body>
</soapenv:Envelope>
Using Paste Special I used Paste XML as Classes and got a number of classes.
I the created a new Envelope object
Envelope shoporder = new Envelope();
EnvelopeBody shoporderBody = new EnvelopeBody();
ShopOrderByBasicDataQuery_sync shoporderSync = new ShopOrderByBasicDataQuery_sync();
ShopOrderByBasicDataQuery_syncShopOrderByBasicDataQuery shoporderDataQuery = new ShopOrderByBasicDataQuery_syncShopOrderByBasicDataQuery();
shoporderSync.ShopOrderByBasicDataQuery = shoporderDataQuery;
shoporderDataQuery.ShopOrder = "BOXBUILD_LASER_TEST";
shoporderDataQuery.SiteRef = new ShopOrderByBasicDataQuery_syncShopOrderByBasicDataQuerySiteRef();
shoporderDataQuery.SiteRef.Site = "TEST1";
shoporderSync.ShopOrderByBasicDataQuery = shoporderDataQuery;
shoporderBody.ShopOrderByBasicDataQuery_sync = shoporderSync;
shoporder.Body = shoporderBody;
string tmp = (string)SoapHelper.SerializeToXmlString(shoporder);
The string tmp contains this (after a bit of formatting)
<?xml version="1.0" encoding="utf-16"?>
<Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ShopOrderByBasicDataQuery_sync xmlns="http://sap.com/xi/ME">
<ShopOrderByBasicDataQuery>
<ShopOrder>BOXBUILD_LASER_TEST</ShopOrder>
<SiteRef>
<Site>TEST1</Site>
</SiteRef>
</ShopOrderByBasicDataQuery>
</ShopOrderByBasicDataQuery_sync>
</Body>
</Envelope>
Which is not a correct file! What have I done wrong?
I have been trying to add a header to SOAP request as follows
<soapenv:Header>
<UsernameToken xmlns="http://test.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://test.com/webservices">password</PasswordText>
<SessionType xmlns="http://test.com/webservices">None</SessionType>
</soapenv:Header>
I have found suggestions to use SoapHeader to include header values, but introduces another level such as
<soapenv:Header>
<CustomHeader>
<UsernameToken xmlns="http://test.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://test.com/webservices">password</PasswordText>
<SessionType xmlns="http://test.com/webservices">None</SessionType>
</CustomHeader>
</soapenv:Header>
Can anyone suggest how I can form a request without CustomHeader.
Try to use this one
private static void Main()
{
using (var client = new ServiceClient())
using (var scope = new OperationContextScope(client.InnerChannel))
{
MessageHeader usernameTokenHeader = MessageHeader.CreateHeader("UsernameToken",
"http://test.com/webservices", "username");
OperationContext.Current.OutgoingMessageHeaders.Add(usernameTokenHeader);
MessageHeader passwordTextHeader = MessageHeader.CreateHeader("PasswordText",
"http://test.com/webservices", "password");
OperationContext.Current.OutgoingMessageHeaders.Add(passwordTextHeader);
MessageHeader sessionTypeHeader = MessageHeader.CreateHeader("SessionType",
"http://test.com/webservices", "None");
OperationContext.Current.OutgoingMessageHeaders.Add(sessionTypeHeader);
string result = client.GetData(1);
Console.WriteLine(result);
}
Console.ReadKey();
}
The Service Trace viewer shows following
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<UsernameToken xmlns="http://test.com/webservices">username</UsernameToken>
<PasswordText xmlns="http://test.com/webservices">password</PasswordText>
<SessionType xmlns="http://test.com/webservices">None</SessionType>
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:13332/Service1.svc</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService/GetData</Action>
</s:Header>
</s:Envelope>
Take a look OperationContextScope for more info