2

I have been reading and reading but I just get more confused the further I go. I am building an ASP.NET 4.0 web application in C#. I am trying to implement credit card processing. The company I am using has supplied an example XML SOAP request and response but I am not sure what to do with that. I am a novice developer and am new to all of this. I just don't even know where to begin. Any help is greatly appreciated, I also have to send over SSL but that is probably a whole other question.

Here is the SOAP request

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <v1:SendTranRequest xmlns:v1="http://postilion/realtime/merchantframework/xsd/v1/">
      <v1:merc>
        <v1:id>9000</v1:id>
        <v1:regKey>RegistrationKey</v1:regKey>
        <v1:inType>1</v1:inType>
        <v1:prodType>5</v1:prodType>
      </v1:merc>
      <v1:tranCode>1</v1:tranCode>
      <v1:card>
        <v1:pan>411111******1111</v1:pan>
        <v1:xprDt>1312</v1:xprDt>
      </v1:card>
      <v1:contact>
        <v1:id>1234567</v1:id>
        <v1:fullName>John Doe</v1:fullName>
        <v1:coName>Ajax Intl.</v1:coName>
        <v1:title>CEO</v1:title>
        <v1:phone>
          <v1:type>3</v1:type>
          <v1:nr>5555555555</v1:nr>
        </v1:phone>
        <v1:addrLn1>123 1st St.</v1:addrLn1>
        <v1:city>Somewhere</v1:city>
        <v1:state>CO</v1:state>
        <v1:zipCode>80021</v1:zipCode>
        <v1:ctry>US</v1:ctry>
        <v1:email>email@email.com</v1:email>
        <v1:ship>
          <v1:fullName>John Doe</v1:fullName>
          <v1:addrLn1>123 1st St.</v1:addrLn1>
          <v1:city>Somewhere</v1:city>
          <v1:state>CO</v1:state>
          <v1:zipCode>80021</v1:zipCode>
          <v1:phone>5555555555</v1:phone>
          <v1:email>email@email.com</v1:email>
        </v1:ship>
      </v1:contact>
      <v1:reqAmt>099</v1:reqAmt>
      <v1:usrDef>
        <v1:name>firstname</v1:name>
        <v1:val>John</v1:val>
      </v1:usrDef>
      <v1:indCode>1</v1:indCode>
      <v1:tranFlags>
        <v1:dupChkTmPrd>6000</v1:dupChkTmPrd>
        <v1:convFeeAcptd>N</v1:convFeeAcptd>
      </v1:tranFlags>
      <v1:tax>
        <v1:idcr>0</v1:idcr>
      </v1:tax>
    </v1:SendTranRequest>
  </soapenv:Body>
</soapenv:Envelope>

Here is my create request and read response

 WebRequest webRequest = WebRequest.Create("url");
 HttpWebRequest httpRequest = (HttpWebRequest)webRequest;
 httpRequest.Method = "POST";
 httpRequest.ContentType = "text/xml; charset=utf-8";
 httpRequest.Headers.Add("SOAPAction: http://tempuri.org/");
 httpRequest.ProtocolVersion = HttpVersion.Version11;
 httpRequest.Credentials = CredentialCache.DefaultCredentials;

 //build xml

 var xmlWriterSettings = new XmlWriterSettings
    {
        NewLineHandling = NewLineHandling.None,
        Encoding = Encoding.ASCII
    };

    using (var requestStream = httpRequest.GetRequestStream())
    using (var writer = XmlWriter.Create(requestStream, xmlWriterSettings))
    {
        xml.WriteTo(writer);
    }
    //Get the Response    
    HttpWebResponse wr = (HttpWebResponse)httpRequest.GetResponse();
    StreamReader srd = new StreamReader(wr.GetResponseStream());
    string resulXmlFromWebService = srd.ReadToEnd();
user1740003
  • 57
  • 1
  • 3
  • 10

1 Answers1

11

I would recommend looking at the HttpWebRequest and the HttpWebResponse classes. The HttpWebRequest class will allow you to set the body, headers, credentials, and other things for making the request. And the HttpWebResponse should allow you to read in whatever information you need.

Hope this helps some, but your question is a unclear as to what you need to do. But the following code will download an XML document from a provided endpoint that you have posted the request XML to.

var requestXml = new XmlDocument();

// build XML request 

var httpRequest = HttpWebRequest.Create("https://www.website.com/");
httpRequest.Method = "POST";
httpRequest.ContentType = "text/xml";

// set appropriate headers

using (var requestStream = httpRequest.GetRequestStream())
{
    requestXml.Save(requestStream);
}

using (var response = (HttpWebResponse)httpRequest.GetResponse())
using (var responseStream = response.GetResponseStream())
{
    // may want to check response.StatusCode to
    // see if the request was successful

    var responseXml = new XmlDocument();
    responseXml.Load(responseStream);
}

As far as dealing with doing stuff over SSL/TLS there you are in luck, .NET will take care of that for you, you just need to specify https over http in the URL that your provide to HttpWebRequest.Create.


There are a number of ways you construct your XML, one way is to use the XElement, XAttribute, and XNamespace objects within the System.Xml.Linq namespace. Which unless you cannot use at least .NET 3.5 I would recommend using. Since you are creating the application in APS.NET 4.0 this shouldn't be an issue.

When you create an XElement and you need to specify a namespace you'll need to first create an XNamespace object.

var ns = XNamespace.Get("http://tempuri.com");
var root = new XElement(ns + "Root", "Body");

This will result in the following XML:

<Root xmlns="http://tempuri.com">Body</Root>

However, you need to be able to specify a namespace prefix. In order to do this you will need to add an XAttribute object to the XElement you first use the prefix on and specify the prefix through the constructor.

var ns = XNamespace.Get("http://tempuri.com");
var root = new XElement(ns + "Root",
    new XAttribute(XNamespace.Xmlns + "prefix", ns)
    "Body"
);

This will result in the following XML:

<prefix:Root xmlns:prefix="http://tempuri.com">Body</prefix:Root>

Here is a portion of your XML constructed using those objects.

var id = 9000;
var regKey = "RegistrationKey";
var inType = 1;
var prodType = 5;
var tranCode = 1;

var soapNs = XNamespace.Get("http://schemas.xmlsoap.org/soap/envelope/");
var v1Ns = XNamespace.Get("http://postilion/realtime/merchantframework/xsd/v1/");

var xml= new XElement(soapNs + "Envelope",
    new XAttribute(XNamespace.Xmlns + "soapenv", soapNs),
    new XElement(soapNs + "Body",
        new XElement(v1Ns + "SendTranRequest",
            new XAttribute(XNamespace.Xmlns + "v1", v1Ns),
            new XElement(v1Ns + "merc",
                new XElement(v1Ns + "id", id),
                new XElement(v1Ns + "regKey", regKey),
                new XElement(v1Ns + "inType", inType),
                new XElement(v1Ns + "prodType", prodType)
            ),
            new XElement(v1Ns + "tranCode", tranCode)
        )
    )
);

This results in the following XML:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
        <v1:SendTranRequest xmlns:v1="http://postilion/realtime/merchantframework/xsd/v1/">
            <v1:merc>
                <v1:id>9000</v1:id>
                <v1:regKey>RegistrationKey</v1:regKey>
                <v1:inType>1</v1:inType>
                <v1:prodType>5</v1:prodType>
            </v1:merc>
            <v1:tranCode>1</v1:tranCode>
        </v1:SendTranRequest>
    </soapenv:Body>
</soapenv:Envelope>

To include the XML into the body of your HttpWebRequest do:

var xmlWriterSettings = new XmlWriterSettings
{
    NewLineHandling = NewLineHandling.None
};

using (var requestStream = httpRequest.GetRequestStream())
using (var writer = XmlWriter.Create(requestStream, xmlWriterSettings))
{
    xml.WriteTo(writer);
}

One thing of note here is the creation of the XmlWriter with the XmlWriterSettings, this allows you to not include any whitespace between the XML elements. If you need whitespace you can create the XmlWriter by just calling XmlWriter.Create(stream)


If you cannot use .NET 3.5 or higher, you can use the XmlDocument and XmlElement objects in the System.Xml namespace.

For your purposes, constructing the desired XML will be easy with the XmlDocument and XmlElement but it will be more code. To create an XmlElement you will need an XmlDocument to create the object. The XmlDocument.CreateElement function has an overload that allows you to specify both the namespace prefix and the namespace, so that is a little more straight forward.

One thing to note with using XmlDocument and XmlElement is you will need to manually append the XmlElement to the appropriate object after it has been constructed. Another thing is you cannot specify the body of an XmlElement during construction either, so that will need to be done after creation as well.

The order of the operations for the construction of the XML in this manner do not matter. It is mostly making sure you are appending the XmlElement to the right parent, and setting the InnerText on the right XmlElement object.

var soapPrefix = "soapenv";
var soapNs = "http://schemas.xmlsoap.org/soap/envelope/";

var v1Prefix = "v1";
var v1Ns = "http://postilion/realtime/merchantframework/xsd/v1/";

var xmlDoc = new XmlDocument();

var envelope = xmlDoc.CreateElement(soapPrefix, "Envelope", soapNs);
xmlDoc.AppendChild(envelope);

var body = xmlDoc.CreateElement(soapPrefix, "Body", soapNs);
envelope.AppendChild(body);

var sendTranRequest = xmlDoc.CreateElement(v1Prefix, "SendTranRequest", v1Ns);
body.AppendChild(sendTranRequest);

var merc = xmlDoc.CreateElement(v1Prefix, "merc", v1Ns);
sendTranRequest.AppendChild(merc);

var idElement = xmlDoc.CreateElement(v1Prefix, "id", v1Ns);
idElement.InnerText = id.ToString();
merc.AppendChild(idElement);

var regKeyElement = xmlDoc.CreateElement(v1Prefix, "regKey", v1Ns);
regKeyElement.InnerText = regKey;
merc.AppendChild(regKeyElement);

var inTypeElement = xmlDoc.CreateElement(v1Prefix, "inType", v1Ns);
inTypeElement.InnerText = inType.ToString();
merc.AppendChild(inTypeElement);

var prodTypeElement = xmlDoc.CreateElement(v1Prefix, "prodType", v1Ns);
prodTypeElement.InnerText = prodType.ToString();
merc.AppendChild(prodTypeElement);

var tranCodeElement = xmlDoc.CreateElement(v1Prefix, "tranCode", v1Ns);
tranCodeElement.InnerText = tranCode.ToString();
sendTranRequest.AppendChild(tranCodeElement);

This results in the same XML as above.

When using an XmlDocument to construct your XML request, there are two XmlDocument.Save functions that you could use for your purposes. One accepts a Stream the other accepts a XmlWriter. If you can omit whitespace use the overload that accepts a XmlWriter and adding that to the HttpWebRequest would be:

using (var requestStream = httpRequest.GetRequestStream())
using (var writer = XmlWriter.Create(requestStream, xmlWriterSettings))
{
    xmlDoc.Save(writer);
}

If you need to include the whitespace use:

using (var requestStream = httpRequest.GetRequestStream())
{
    xmlDoc.Save(requestStream);
}
JG in SD
  • 5,427
  • 3
  • 34
  • 46
  • Thank you, I will try it out and see what happens. The payment provider hasn't been very helpful but that is who this company wants to use so I will see what I can do. – user1740003 Apr 10 '13 at 22:31
  • @user1740003 I believe so, but it will take more work. Take a look at http://stackoverflow.com/questions/5396671/how-to-send-receive-soap-request-and-response-using-c-sharp – JG in SD Apr 10 '13 at 22:56
  • Ok JG that post makes sense but some comment said not to build the xml using strings. From what I read you can't build a SOAP request with XML writer. How do I build the SOAP request? – user1740003 Apr 11 '13 at 21:40
  • @user1740003 You can build XML using strings, but it is suggested to build XML using one of the XML APIs (XDocument, XmlDocument, XmlWriter, etc) to avoid any errors that could occur if you used strings. If you post an example of the SOAP XML request I can help you with the code to build the XML. – JG in SD Apr 11 '13 at 21:57
  • I posted the soap request above. Thank you for the help. – user1740003 Apr 12 '13 at 15:37
  • hello again, sorry I haven't responded, I went out of town for the last 10 days but now I am back at it. Anyway I think I have it all setup but I am getting an error server actively refuses request. Stupid question but what url am I supposed to be using when I create httprequest? – user1740003 Apr 24 '13 at 18:05
  • @user1740003 The URL you'll need to use I would hope has been supplied by the company that you need to send the SOAP request to. If you do not have one, I would ask the same person/group/entity you got the SOAP request example from, to provide you with the URL that you'll need to use. – JG in SD Apr 24 '13 at 18:39
  • Ok I got that url but what goes in the SOAP action in the header. `httpRequest.Headers.Add("SOAPAction: http://tempuri.org/");` – user1740003 Apr 25 '13 at 18:19
  • @user1740003 again that is something that should have been supplied to you by the company that you need to post the SOAP request to. – JG in SD Apr 25 '13 at 21:46
  • Ok Thanks, this is my first time doing anything like this and they gave me some documentation but they don't have any help on the c# side of things. Does the rest of my request / response look ok, I posted it above. I am getting an error `An existing connection was forcibly closed by the remote host` on the getresponse call – user1740003 Apr 26 '13 at 17:28
  • @user1740003 Everything looks like it should work, I would recommend to make sure are using `using` blocks on the `HttpWebResponse`, `StreamReader`, and the `Stream` from `wr.GetResponseStream()` objects. I would also recommend using `HttpWebRequest.Create` over `WebRequest` to avoid the casting. But those things should not stop the request from being processed. – JG in SD Apr 26 '13 at 19:12
  • @user1740003 As far as the connection being forcibly closed by the remote host. The message suggests that something somewhere along the line of communication to the endpoint is rejecting the request. You'll want to verify you have the correct URL, along with any other settings. If all that is correct, if possible verify that the communication is able to make it onto the Internet. If all that is good, then you may need to get the company hosting the endpoint involved, as they may need to set something up on their end to allow the traffic. – JG in SD Apr 26 '13 at 19:19
  • Ok go easy on me I am still trying to wrap my head around all this but I have a WSDL that I am supposed to use. Does that mean I need a web service also to make this request? – user1740003 Apr 29 '13 at 16:10
  • @user1740003 well if you have a WSDL then a lot of your work can be done with generated code. Please see: [How to generate the client from a WSDL file in .NET](http://stackoverflow.com/questions/1573202/how-to-generate-the-client-from-a-wsdl-file-in-net?rq=1) – JG in SD Apr 29 '13 at 20:17