Use WSDL and dotnet interop in the Role Tailored Client

I have been working with the dotnet interop and consuming soap web services.  I wrote about a dotnet interop based way to communicate with soap web services in a previous blog but now I want to demonstrate another way that requires just a few lines of code.

I would like to find a web service that is open so everyone can do their own testing.  I found a web service that will look up a country by an IP address.

The first step is to start Microsoft Visual Studio and create a new project.  The language that you choose is not important.

I delete Class1.cs.  Then go to Project menu and Add Service Reference.  Click Advanced… and Add Web Reference…  Look in my previous blog for more details.

I paste the web service URL in to Visual Studio and select a name for the web reference.

I go to Project and GeoIPService Properties to make sure that I am using .NET Framework 3.5 and I choose to create my own key to sign the class.  I also like to add details to the Assembly Information…

I go to Signing and create a new key file with my own password.

Then I save the project and select Build and Build GeoIPService.  In the solution folder I will now find the GeoIPService.dll file.  This file I copy to my Classic Client Add-ins folder.  I start the Classic Client and create a new Codeunit.  I will then add a dotnet global variable with my new class.  I create a variable both for GeoIPService and for GeoIP.

I the need to choose if I would like the service to be run on the client or on the server.  If I choose to run on the client then I need to copy the class file to Role Tailored Client Add-ins folder for every user.  If I choose to run on server I copy the class file to the service Add-ins folder.  I selected to run on server since I do not have to supply my domain user name or any certificates to the service.

The code in the Codeunit is as follows

[code]
GeoIPService := GeoIPService.GeoIPService;
GeoIPService.Url := ‘http://www.webservicex.net/geoipservice.asmx’;
GeoIP := GeoIPService.GetGeoIP(‘93.95.74.198’);
MESSAGE(
‘Return Code: %1\IP Address %2\Country Name: %3\Country Code: %4’,
GeoIP.ReturnCode,
GeoIP.IP,
GeoIP.CountryName,
GeoIP.CountryCode);[/code]

I then start the codeunit in my Role Tailored Client with the Run Object Page that Microsoft supplied in their blog.

Attached is the codeunit, the class library and the Run Object Page from Microsoft.

GeoIPService

Microsoft Connect is working

On July 31, 2012 I posted a patch to codeunit 5895 to be able to execute inventory adjustment with NAS.  I also suggested that this solution should be implemented in NAV and now I am receiving a knowledge base article from Microsoft with ID: 2763255 that handles this issue.

Was Microsoft listening to my comments or did someone else suggest this to Microsoft.  At least I can see that the solution that they provide does not match exactly the solution that I suggested – but a solution anyway.

Change in code for Intercompany Postings

I am using the Intercompany Posting for some of my clients.  I have extended the functionality to make it possible to sell and purchase between responsibility centers within the same company.

I am also using the job queue invoice posting and noticed that the time it took to post an invoice with intercompany posting was not as expected.  I found the code in codeunit 427 that caused the problem.

[code]
ICDocDim."Transaction No." := OutboxTransaction."Transaction No.";
ICDocDim."IC Partner Code" := OutboxTransaction."IC Partner Code";
ICDocDim."Transaction Source" := OutboxTransaction."Transaction Source";
PostedDocDim.SETFILTER("Table ID",’%1|%2′,DATABASE::"Sales Invoice Header",DATABASE::"Sales Invoice Line");
PostedDocDim.SETRANGE("Document No.",SalesInvHdr."No.");
IF PostedDocDim.FIND(‘-‘) THEN
REPEAT
IF PostedDocDim."Table ID" = DATABASE::"Sales Invoice Header" THEN
ICDocDim."Table ID" := DATABASE::"IC Outbox Sales Header"
ELSE
ICDocDim."Table ID" := DATABASE::"IC Outbox Sales Line";
ICDocDim."Line No." := PostedDocDim."Line No.";
ICDim := DimMgt.ConvertDimtoICDim(PostedDocDim."Dimension Code");
ICDimValue :=
DimMgt.ConvertDimValuetoICDimVal(PostedDocDim."Dimension Code",PostedDocDim."Dimension Value Code");
IF ICDim <> ” THEN BEGIN
ICDocDim."Dimension Code" := ICDim;
IF ICDimValue <> ” THEN BEGIN
ICDocDim."Dimension Value Code" := ICDimValue;
ICDocDim.INSERT;
END;
END;
UNTIL PostedDocDim.NEXT = 0;[/code]

I noticed the line

PostedDocDim.SETFILTER("Table ID",'%1|%2',DATABASE::"Sales Invoice Header",DATABASE::"Sales Invoice Line");

that was causing the problem. Add a local variable TableID and change the code as follows to improve the performance.

[code]
ICDocDim."Transaction No." := OutboxTransaction."Transaction No.";
ICDocDim."IC Partner Code" := OutboxTransaction."IC Partner Code";
ICDocDim."Transaction Source" := OutboxTransaction."Transaction Source";
FOR TableID := DATABASE::"Sales Invoice Header" TO DATABASE::"Sales Invoice Line" DO BEGIN
PostedDocDim.SETRANGE("Table ID",TableID);
PostedDocDim.SETRANGE("Document No.",SalesInvHdr."No.");
IF PostedDocDim.FIND(‘-‘) THEN
REPEAT
IF PostedDocDim."Table ID" = DATABASE::"Sales Invoice Header" THEN
ICDocDim."Table ID" := DATABASE::"IC Outbox Sales Header"
ELSE
ICDocDim."Table ID" := DATABASE::"IC Outbox Sales Line";
ICDocDim."Line No." := PostedDocDim."Line No.";
ICDim := DimMgt.ConvertDimtoICDim(PostedDocDim."Dimension Code");
ICDimValue :=
DimMgt.ConvertDimValuetoICDimVal(PostedDocDim."Dimension Code",PostedDocDim."Dimension Value Code");
IF ICDim <> ” THEN BEGIN
ICDocDim."Dimension Code" := ICDim;
IF ICDimValue <> ” THEN BEGIN
ICDocDim."Dimension Value Code" := ICDimValue;
ICDocDim.INSERT;
END;
END;
UNTIL PostedDocDim.NEXT = 0;
END;[/code]

Integration for Sales

I started to use the CRM Integration that was delivered with NAV 2009 R2 for one of my client earlier in this year.  Not for CRM though but for the handheld computers.

One of the functions is to update a parent integration record.  That means that if a user modifies a sales line the sales header is fetched and the modify timestamp for the sales header integration record is updated.

When I update the handheld computers I will search for all modified integration records, update the handheld computers and clear out the modified timestamp from the integration record.

In the standard codeunit 5150 and in InsertUpdateIntegrationRecord function the code always updates the modified time stamp.  This will be executed for every modification for a sales header or a sales line.  I wanted to change this so that the modified time stamp will only be set once.

[code]IF "Modified On" = 0DT THEN BEGIN
"Modified On" := IntegrationLastModified;
MODIFY;
END;[/code]

instead of

[code]"Modified On" := IntegrationLastModified;
MODIFY;[/code]

I think that Microsoft should look into this in the standard code.