c# Web service to handle repeating/multiple items - c#

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.

Related

Web Service dll behaving differently in Xamarin from Framework and Core versions

I have a SOAP web service that I need to call in a wide array applications, so I created a service DLL that targets both .net standard 2.0 and .net framework 4.6.1.
The DLL seems to work fine with on Desktop Framework applications, and on Desktop Core applications. However, the behavior on a Xamarin Android project is just slightly off of what the other two are.
A correctly sent message from the other two applications looks like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ZBAPI_GOODSMVT_CREATE xmlns="urn:sap-com:document:sap:rfc:functions">
<CODE xmlns="">
<GM_CODE>03</GM_CODE>
</CODE>
<HEADER xmlns="">
<PSTNG_DATE>2019-12-08</PSTNG_DATE>
<DOC_DATE>2019-12-08</DOC_DATE>
</HEADER>
<ITEM xmlns="">
... data here ...
</ITEM>
<RETURN xmlns="">
... data here ...
</RETURN>
</ZBAPI_GOODSMVT_CREATE>
</s:Body>
And the a successfully sent(but not processed) message from the android device is so:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ZBAPI_GOODSMVT_CREATE>
<CODE>
<GM_CODE>03</GM_CODE>
</CODE>
<HEADER>
<PSTNG_DATE>2019-12-08</PSTNG_DATE>
<DOC_DATE>2019-12-08</DOC_DATE>
</HEADER>
<ITEM>
... data here ...
</ITEM>
<RETURN>
... data here ...
</RETURN>
</ZBAPI_GOODSMVT_CREATE>
</s:Body>
So nearly identical, except every namespace inside the body element has been stripped out.
I've confirmed with SOAPUI that All the namespaces are needed, even the blank ones.
The DLL in question is, as stated, a .net standard 2.0, and the service was imported using the vendor provided wsdl file.
inside the DLL code I am calling the service like so:
private void RunRequest(ServiceData payload)
{
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
var address = new EndpointAddress("https:\\serviceaddress.com\service");
new ChannelFactory<ServiceChannel>(binding, address).Using(factory =>
{
factory.Credentials.UserName.UserName = "Uset";
factory.Credentials.UserName.Password = "Pass";
var proxy = factory.CreateChannel();
proxy.Open();
var context = new OperationContext((IClientChannel)proxy);
var prevOpContext = OperationContext.Current;
OperationContext.Current = context;
try
{
var results = proxy.ServiceChannel_CREATEAsync(payload).ConfigureAwait(false).GetAwaiter().GetResult().SerivceChannelResponse;
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(ServiceChannelResponse));
using StringWriter text = new StringWriter();
serializer.Serialize(text, results);
Message = text.ToString();
}
catch
{
throw;
}
});
how can I force the xmlns namespaces inclusion across all platforms?

XML serialized from classes created with xsd is not correct

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?

How to change WebMethod XML output for ASP.NET Webservice, specifically namespace declaration?

I'm developing an ASP.NET Webservice (not WCF) for a given client. This is one of those situations, where you can not change anything at the client.
The client sends the following XML to request a method:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:cometxsd="http://werk-ii.de/soap/comet/Schema"
xmlns:comet="http://werk-ii.de/soap/comet"
xmlns:xop="http://www.w3.org/2004/08/xop/include"
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"
xmlns:xmime5="http://www.w3.org/2005/05/xmlmime"
xmlns:ns1="http://soap.comet.werkii.com/">
<SOAP-ENV:Body>
<ns1:login xsi:type="ns1:login">
<user>myusername</user>
<password>mypassword</password>
<client>whatever</client>
<language>de</language>
</ns1:login>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
My Service provides the login-Method like this:
[WebService(Namespace = "http://soap.comet.werkii.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class CometService : WebService
{
[WebMethod(MessageName = "login")]
[return: XmlElement("return")]
public LoginResult Login (string user, string password, string client, string language)
{
return new LoginResult() {
ResultCode = 0,
SessionId = user + "-" + password + "-" + client + "-" + language
};
}
}
public class LoginResult
{
[XmlElement("resultCode")]
public int ResultCode { get; set; }
[XmlElement("sessionId")]
public string SessionId { get; set; }
}
If I start the service, it tells me what SOAP 1.1 code I have to send as a request, that ist:
<?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>
<login xmlns="http://soap.comet.werkii.com/">
<user>string</user>
<password>string</password>
<client>string</client>
<language>string</language>
</login>
</soap:Body>
</soap:Envelope>
When I use this code - as told by the service - from another test client (i wrote one in PHP), everything works fine an I get a result. But when I send the code from the beginning (which is what the real client will send), the method is called but all 4 arguments are null.
From an XML view, in my opinion both requests are the same. The only difference is, where the namespace is defined and if elements use the ns1 prefix. This should not make any difference, when the service reads it as XML. Maybe I'm wrong.
Perhaps the 4 arguments in the first XML have a different namespace (none) than the method (ns1). Can that be the reason why all arguments are null? How would I change the namespace for the arguments only?
When I change only the method lines in XML - replacing <ns1:login xsi:type="ns1:login"> with <login xmlns="http://soap.comet.werkii.com/"> and also the closing tag - it works! So the service seems not to understand my request, if the method element uses a namespace prefix, though the namespace is properly defined in the root element.
I tried the following to change the XML format which the service expects:
System.Web.Services.Protocols.SoapDocumentMethodAttribute - no effect at all
XmlNamespaceDeclarationsAttribute as shown here - which seems not to work because it is made for manipulating complex types, not the service class or a method
So the question is, how can I tell my service to accept the XML from the first example?
Good to know that parameters can also have Attributes:
public LoginResult Login (
[XmlElement(Namespace = "")] string user,
[XmlElement(Namespace = "")] string password,
[XmlElement(Namespace = "")] string client,
[XmlElement(Namespace = "")] string language)
{
return new LoginResult() {
ResultCode = 0,
SessionId = user + "-" + password + "-" + client + "-" + language
};
}
That's the solution to put the parameters into the global namespace – problem solved.

Update Merchant Order ID in Amazon Marketplace

I need to update MerchantOrderID in Amazon Marketplace via Amazon MWS API using C#.
So, first I created XML file like:
<?xml version="1.0"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>M_STORE_3918753</MerchantIdentifier>
</Header>
<MessageType>OrderAcknowledgement</MessageType>
<Message>
<MessageID>1</MessageID>
<OrderAcknowledgement>
<AmazonOrderID>104-9209939-0469021</AmazonOrderID>
<MerchantOrderID>100828163</MerchantOrderID>
<StatusCode>Success</StatusCode>
<Item>
<AmazonOrderItemCode>11111111111111</AmazonOrderItemCode>
<MerchantOrderItemID>111111</MerchantOrderItemID>
<AmazonOrderItemCode>22222222222222</AmazonOrderItemCode>
<MerchantOrderItemID>222222222</MerchantOrderItemID>
</Item>
</OrderAcknowledgement>
</Message>
</AmazonEnvelope>
then I try to call Amazon MWS SubmitFeed:
SubmitFeedRequest request = new SubmitFeedRequest();
request.Merchant = merchantId;
request.MarketplaceIdList = new IdList();
request.MarketplaceIdList.Id = new List<string>(new string[] { marketplaceId });
request.FeedContent = File.Open(path, FileMode.Open, FileAccess.Read);
request.ContentMD5 = MarketplaceWebServiceClient.CalculateContentMD5(request.FeedContent);
request.FeedContent.Position = 0;
request.FeedType = "_POST_ORDER_ACKNOWLEDGEMENT_DATA_";
MarketplaceWebService.MarketplaceWebService serviceFeed = new MarketplaceWebServiceClient(
accessKeyId,
secretAccessKey,
applicationName,
applicationVersion,
configFeed);
SubmitFeedResponse response = serviceFeed.SubmitFeed(request);
it succesfully submits but when I open my order in Amazon (sellercentral.amazon.com) it says "none saved":
Your Merchant Order ID: # none saved
Who can help me, what is wrong or what should I do?
Thanks!
For those who want to update merchant order id in multiple orders at once, here is example (also works in amazon mws scratchpad):
<?xml version="1.0"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
<Header>
<DocumentVersion>1.01</DocumentVersion>
<MerchantIdentifier>ALVH0CYWPBFNA</MerchantIdentifier>
</Header>
<MessageType>OrderAcknowledgement</MessageType>
<Message>
<MessageID>1</MessageID>
<OrderAcknowledgement>
<AmazonOrderID>000-0000000-0000000</AmazonOrderID>
<MerchantOrderID>YOUR_MERCHANT_ORDER_ID</MerchantOrderID>
<StatusCode>Success</StatusCode>
</OrderAcknowledgement>
</Message>
<Message>
<MessageID>2</MessageID>
<OrderAcknowledgement>
<AmazonOrderID>000-0000000-0000000</AmazonOrderID>
<MerchantOrderID>YOUR_MERCHANT_ORDER_ID</MerchantOrderID>
<StatusCode>Success</StatusCode>
</OrderAcknowledgement>
</Message>
</AmazonEnvelope>
It's actually right code. Somehow amazon doesn't mark some special orders or marks them later.

C# + XML Serialization

I have a method that is calling a web service. When this web service is called, the following method is called:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(
"http://mydomain.com/services/DoSomething",
RequestNamespace = "http://mydomain.com/services",
ResponseNamespace = "http://mydomain.com/services",
Use = System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[return: System.Xml.Serialization.XmlElementAttribute("MyResponse")]
public MyResponse DoSomethingr(MyRequest myRequest)
{
object[] results = this.Invoke("DoSomething", new object[] { myRequest});
return ((MyResponse)(results[0]));
}
When this method is called, I've noticed that the XML includes the following:
<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">
<soap:Body>
<!-- XML --!>
</soap:Body>
</soap:Envelope>
How do I remove the <soap:> wrappers from my XML?
I wouldn't. Soap is a standard protocol for publishing services and accessing remote data. Without it the remote server won't understand your request.

Categories

Resources