Problem:
Fedex has changed their API so I need to change some Access VBA code to interface with their new web service API.
Given:
Linked Access 2003 database with lots of tables and forms.
Fedex has changed their API so I need to change some Access VBA code to interface with their new web service API.
Given:
Linked Access 2003 database with lots of tables and forms.
- Some of the forms use code that interfaces the Fedex shipping services - place order, track shipment, cancel, close shipment, request signature proof. The old Fedex API apparently requires a long request string with a bunch of numeric codes that seem to be a hassle to program, maintain and debug.
Fedex WSDL files
- Ship, Track, Close, etc
Fedex sample projects to access the web services. These are available in a bunch of languages, from VB.NET to PHP. Documentation is available also, as well as a technical help number to call.
- For development, Fedex provides a special testing server and requires you to register to access the web services (https://wsbeta.fedex.com:443/web-services/...)
What I did and tried:
I registered as a Fedex developer and got key/pwd/account/meter numbers, and inserted them into corresponding fields in the sample projects to make them work.
The web services I have used before were given as a link that you could navigate to in Visual Studio with "Add Web Reference". The .wsdl files still work the same, except I just need to paste the path of wsdl file into add web reference address box.
Access 2003 VB editor does not have "Add Web Service Reference" by default. It is possible to install an add-in that will let you do that. However, what it did for me was create a bunch of classes (in VB 6!!) defined by the wsdl, and several wrapper classes too. It looks like it would work nicely for small and simple projects... But VBA is a pretty old language that I do not care to be an expert in. The generated classes used Variants for a lot of "complex types" that VB 6 did not have the power to create. It was a messy solution and eventually I ran into problems with Variants that I could not figure out. In retrospect, even if I managed to make shipment request part work, I would have ran into even more problems if I tried to add another web reference due to Fedex sometimes using same classes in their wsdl's.
So, I decided to modify the given sample code into a dynamic library with a simple interface that VB 6 could easily access. I made a VB.NET library project, added a COM class and used the sample code to define that class. In the project settings, I enabled the "COM Interop" option. I also added the wsdl reference. This compiles as a COM Dll file.
In Access VB editor, I added a reference to the newly created FedexShipAPI.tlb and updated the code to use this instead of the old API. It works nicely and returns a shipping label.
When I tried to add other Fedex web services to same project (it would be nice to have all Fedex functions in one library, right?) I ran into problems. Apparently the different wsdl files use a lot of same classes and Visual Studio uses namespaces to differentiate them. So far ok, I just needed to sometimes specify the full namespace names and I made a DLL with Ship and Track services. However, in VBA this created a mess because after importing the new DLL reference, most enumerations suddenly went crazy from 'FedexAPI.ServiceType_FEDEX_GROUND' to 'FedexAPI.FedexAPI_FedexShipWebReference_ServiceType_FEDEX_GROUND' and 'FedexAPI.FedexAPI_FedexTrackWebReference_ServiceType_FEDEX_GROUND', and even longer than that. To complicate things, some of them stayed the same since they were not duplicated in original VB.NET project. Although this would probably eventually work, I decided against making single DLL and made a separate DLL for each service. That worked fine.
Problems and TO DOs
International document shipment: there is no sample to do this :( So when I try to modify international commodity shipment - specify package contents to be DOCUMENT_ONLY and do not add any commodity descriptions, the server still returns an error message that says international shipments must have at least one commodity specified.
International Ground shipment (only should work to Canada/Mexico) -- there is no sample code for this too. Seems pretty easy to do though, right? I just changed the recipient address to a valid address in Canada, and set the service type to International_Ground. The server always returns "Invalid service type" error, however.
Calling Fedex help desk on this was no help. The guy suggested I use some numeric values (92) for international ground, which I was supposed to plug in into the XML request file. Looking at the provided documentation, there is NOTHING that makes any reference to using numerical codes to the service or other enumerated types, even when building the xml request files manually. In fact, this seems to be something from the old API, so I think the help guy was incompetent. To the my question why they provide the sample codes at all, he replied that the code is useless, he was not the one to make it, and that I should work with xml.
CustomerReference: I can not add more than 3 customer references! The server returns a schema error if I provide 4 different types of reference (invoice, PO number, dept No, reference No), but no error when I provide any 3 of those. This is not important for me though.
I am having trouble registering the DLL files on the user computer. Forums suggest using RegAsm.exe (I have to use version 4.0.0.something since I made the DLL using .NET 4), something like
> regasm FedexShipAPI.dll /tlb:FedexShipAPI.tlb
but I get Object reference errors when trying to use the library in Access. I will try signing my projects (Project settings -> Signing) and then using /codebase switch:
> regasm FedexShipAPI.dll /tlb:FedexShipAPI.tlb /codebase
I still need to request label certification from Fedex. I don't know whether I should fix the two problems with international shipment first or hope their test cases might clear this for me. The rest of the shipment kinds seem to work fine.
Ground shipping to Canada: I have tried using ServiceType_FEDEX_GROUND instead of ServiceType_INTERNATIONAL_GROUND, and it actually worked! The server apparently recognized Canada was another country and made a label with INTL GRND tag.
ReplyDeleteI want to use Fedex address validation service so should I convert that C# or vbnet sample files to .dll like you did? I only know VBA but might be able to try that if it works.
DeleteIts xml is http://pastebin.com/tiVhi5Vv
Isnt there a way to use their service without .dll?
Yes, you can form and send xml/http requests straight to the server. However, as far as I know, doing that in VBA is painful, error-prone, and difficult to maintain. Any .NET language though should have easy time doing that.
DeleteThe reason I went this way was that I had to use VBA and Fedex samples were in C#. To avoid any extra work, I wrapped their C# code in dll and called the dll from VBA.
Passed Fedex label certification
ReplyDelete