Monday, August 18, 2014

Angular.JS Service to Download Data Generated in Browser

I ran into a situation where I wanted to be able to download data that was generated in the browser. There are several libraries that handle this scenario, but I thought it should have been simpler than those large libraries.

Below is the result. It supports IE 10+ (potentially 9 haven't tested), FireFox, and Chrome.
angular.module('FileDownload')
.service('SaveFileService', [function () {
        this.Save = function(data, filename, mimeType) {
            var blob = new Blob([data.join('\n')], {type: mimeType});
            if (/\bMSIE\b|\bTrident\b|\bEdge\b/.test(navigator.userAgent)) {
                window.navigator.msSaveOrOpenBlob(blob, filename);
            } else {
                var url  = window.URL || window.webkitURL,
                    link = document.createElementNS("http://www.w3.org/1999/xhtml", "a"),
                    event = document.createEvent("MouseEvents");
                
                link.href = url.createObjectURL(blob);
                link.download = filename;

                event.initEvent("click", true, false);
                link.dispatchEvent(event);
            }
        };
    }]);
Basically, the Save function does a couple things. For IE browsers, it creates the blob and calls the msSaveOrOpenBlob (the msSaveBlob function would make IE only display a save dialog and not give the user the option to open it). For all other browsers, it creates the blob, generates a link element, creates a mouse click event, and has the link dispatch the created event.

To use the service, just inject the service into the controller and call the Save function w/ the needed parameters.

UPDATE 2015-09-28: Per Kevin's feedback, I have updated the regular expression to catch the Edge browser (so much for Microsoft making a standards evergreen browser). I have verified that the above change works as advertised.

Wednesday, August 13, 2014

First Data Global Gateway Integration and the HTTP 401 Unauthorized Error

A project recently required integrating with First Data for payment processing. This isn't my first rodeo integrating with a payment processor, but it was the first time I interfaced with First Data. Sounds easy enough, right? Following the Global Gateway version 6 documentation shouldn't be very difficult. Except when it isn't.

The documentation is terribly antiquated. The setup assumes you are on Windows XP and using IIS5/6. Thankfully have developed application in that environment and felt confident that I could translate the instructions to Windows 8.1 and IIS Express.

The first obstacle was getting the certificates. The original email I had said that I would receive the certificates in my email. When it didn't arrive, I was slightly confused. I called support and they instructed me to jump into the Virtual Terminal and download them there. I was back on track with the documentation.

I was able to use the Certificate MMC snap-in to import the P12 certificate into the Computer Account/Personal store. I then used the WinHttpCertCfg tool to grant the needed users access to the Certificate. The documentation specifies the IWAM_MachineName user, but knowing that doesn't exist, I opted to grant IIS_IUSRS, IUSR, NETWORK SERVICE, and my own account (because IIS Express runs under the users permissions). You may need to grant permission to "DefaultAppPool" if you are using IIS 7.5. Essentially, whatever user the application is going to run as, needs access to the certificate.

The next obstacle was getting the WSDL. Accessing the WSDL link from the documentation, https://ws.merchanttest.firstdataglobalgateway.com/fdggwsapi/services/order.wsdl, yielded SSL/TLS authentication handshake connection errors. It didn't matter which browser I was using.

After verifying that my setup followed the documentation and Google not finding anything that I hadn't already tried, I called support again. I was told that I was pointing to the wrong address and instead should point to the following addresses:

https://www.staging.linkpointcentral.com/fdggwsapi/services/order.wsdl
https://www.staging.linkpointcentral.com/fdggwsapi/schemas_us/v1.xsd
https://www.staging.linkpointcentral.com/fdggwsapi/schemas_us/a1.xsd
https://www.staging.linkpointcentral.com/fdggwsapi/schemas_us/fdggwsapi.xsd

At this point my confidence in the documentation was extremely low. These URLs were accessible so I felt good and was back on track with the documentation. I was able to generate the web reference and reworked the example to fit my environment. It compiled and I pointed my unit test to my shiny new payment service. What could possibly go wrong?

Well, I received a WebException HTTP 401: Unauthorized error. I probably should have expected another issue, but I try to be optimistic. After a LOT of googling and trying any suggestion I could find related to First Data and this exception. There were a lot of results; obviously I wasn't the only one experiencing this. The last option that I found was requesting the certificates to be regenerated. After exhausting all the other fruitful paths forward, I called support again.

I got a support person named Derek and requested to have the certificates regenerated. He ran the existing certificates through their test process and found that they worked. I told him about my environment and the other issues that I was having. He said that the WSDL URL I was told to use was not correct and that I should use the ones in the documentation (now my confidence was pretty thoroughly gone). After some testing, further information gathering, and research, he found that Windows 8 requires extra steps to get the WSDL. The end result was that he was going to send me the needed WSDL and XSDs and an unpublished document (hopefully they publish it soon) detailing the steps needed to setup the environment. Once I received the files I created a new web reference using the new WSDL/XSDs and used the documentation URLs.

https://ws.merchanttest.firstdataglobalgateway.com/fdggwsapi/services/order.wsdl
https://ws.merchanttest.firstdataglobalgateway.com/fdggwsapi/schemas_us/fdggwsapi.xsd
https://ws.merchanttest.firstdataglobalgateway.com/fdggwsapi/schemas_us/v1.xsd
https://ws.merchanttest.firstdataglobalgateway.com/fdggwsapi/schemas_us/a1.xsd
https://ws.merchanttest.firstdataglobalgateway.com/fdggwsapi/services

I updated my code, compiled and ran my unit tests. Then, I received a failed transaction because the card information I submitted was expired. It meant that it worked! I changed the expiration to a point in the future, tried again, and received an APPROVED response. What a great feeling! Derek stayed on the line through the whole process (which took quite a while). Thank you Derek.

Later I went through the unpublished document and specifically the part about getting the WSDL file. Basically, the P12 file needs to be imported into the browser. To do that do the following:
  1. Open Internet Explorer
  2. In the menu, click Tools->Internet Options
  3. Click the Content tab
  4. Click Certificates
  5. Click Import
  6. Select the P12 file
  7. Enter the password
  8. Click Next, then Finish
You may need to restart the browser. Now I could access the WSDL from all browsers.

I can't believe that I have had to call support so many times. Perhaps I was making up for not needing to call support before. I would include the documentation that I received, but it will get stale over time. The steps in this post are pretty thorough and should be sufficient. Good luck.