This post is based on KB article 861762 which was previously published on PartnerSource. This post is an updated version, and available to a wider audience (no PartnerSource login required).
It describes the basics of what Navision Application Server (NAS) does, and an example of how to build a NAS application in less than 30 minutes. The KB article continued with an example of how to use NAV Communication Components and BusAdapter. This part of the KB article is in the post Comcom and the Bus adapter.
What is NAS?NAS is a client without a user interface (GUI), running as a service. That’s all it is. When it starts, it will run a function in codeunit 1, passing on the Start-up parameter that has been set up. That’s all it does. There are two prerequisites for this function in codeunit 1:
It must have ID 99 (the name of the function is irrelevant) It must have one parameter Text 250. The name of this parameter is also irrelevant.
NAS on its own does not do anything else. So on its own it is a very simple component. But the application you build around it can, off course, be as complicated as any other application.
This tutorial will take you through the steps of building a simple application using NAS. After having completed the tutorial, I hope you will be comfortable with NAS, how to use it, and how to set it up.
1: Setting NAS
In this tutorial we will run NAS on a SQL Server. Just like with a normal client you can do the same things against a Native server. Just use Nas.exe instead of NasSQL.exe. I assume that you already have a NAV database running on a SQL Server, and that you can open this database with a normal NAV client.
Install NAS from the product CD.
Installing NAS will automatically create two services [Machinename-CLASSIC] and [Machinename-SQL] (display name is “Navision Application Server [Machinename]-CLASSIC/SQL”). Go to services and check that you can see these two services. These services are ready to use but just for the practise, the first thing we will do is to remove these two services and create our own service.
There are three interfaces you can use to administer NAS: Navision Application Server Manager (an MMC snapin) Windows Registry Command prompt
There are only two tasks that you can only achieve from the command prompt: Removing an instance (service) of NAS and adding an instance of NAS. All other tasks for administering NAS can be achieved using either of these three tools.
Remove the two services and add your own service:For this task, you need to use the command prompt. Go to the folder where you installed NAS. Notice that, in this folder you will find two .exe files: Nas.exe and Nassql.exe. In the following section, use nassql.exe since we are running on a SQL Server. If you were running NAV on Native server, you would use nas.exe. But each file has the same functionality.
Also note, that if you are running on Windows Vista, then opening a normal command prompt may not give you enough permissions. So, if running on Vista, open the command prompt from the Start Menu -> All Programs -> Accessories, then right-click on "Command Prompt", and select "Run as Administrator".
To remove a service, from the command prompt in the NAS folder, type: Nassql appservername=[machinename]-CLASSIC, uninstallasservice . This will remove the service with the name [machinename]-CLASSIC that was installed when you installed NAS.
In the same way, remove the [Machinename]-SQL service.
To add a service, type: Nassql appservername=NAS, installasservice
This will add a service called NAS. This is the service that we will use in this tutorial. You can add as many instances of NAS as you like – each one will appear as a service. If you want to run NAS from a different folder, then just copy the NAS files into that folder, and run the command prompt commands from there.
Set up the NAS service;Once you have an instance (service) of NAS, you will need to set it up. You can do this from the command prompt, but it is easier to user either the NAS manager, or Windows Registry. If you want to use Registry (Regedit), go to the key HKEY_LOCAL_MACHINE/SYSTEM/CurrentConotrolSet/Services and look for your service here. We will use the NAS Manager.
Remember from the previous step, that the name of your NAS is "NAS". But in Services, the display name will be "Application Server for Microsoft Dynamics NAS" if you are using version 5. Or "Navision Application Server NAS" if you are using version 4. In the next steps, use the name NAS.
To start NAS Manager, click Start, Programs, Microsoft Dynamics NAV, Navision Application Server Manager. Rightclick on "Application Server for Microsoft Dynamics NAV", and select New -> Application Server. Then type in the name of your NAS service ("NAS").
The parameters you need to set up are: Database Server Name: This is your SQL Server. Database: The NAV database. Company Name: Specify the name of the Navision company. NAS must be set up to run in a specific company. If you have more than one company, you need one NAS for each company. Start-up parameter: Specify any text string here. You can use this parameter to distinguish between multiple instances of NAS. For now, just specify “NAS”. Net type: Select Default. Object Cache: Specify Object Cache, or leave it as default.
Once this is done, click Apply these settings.
One more thing you have to do, is to associate your NAS service with a Windows account. Do this by going into services, right-click the NAS service and select Properties. On the “Log On” tab, under “Log on as:”, click This Account, and select an account. For now, you can just select the Administrator Account. In a real installation it is recommended that you create a new Windows Account and use that just for NAS. NAS can only use Windows Authentication. It cannot use database login.
NAS has now been set up.
2: Changes needed in NAV In NAV, create a Windows LoginIn the previous section you set up NAS to use a Windows Account. You need to give access in NAV for this account. Go to Tools, Security, Windows Logins and specify that account here. For this exercise, click Roles and give this account role ID SUPER. Make sure to synchronize permissions (Tools -> Secutiry -> Synchronize all logins).
Modify codeunit 1The last step is to create a function in codeunit 1. As mentioned before, NAS runs a function in codeunit 1 with the ID 99 and a parameter (text 250). In a standard NAV database, this function is called NASHandler. The code in this function depends on which version of NAV you are running, but in recent versions, it will contain a section that looks like this:
IF CGNASStartedinLoop = FALSE THEN CASE Parameter OF 'OSYNCH','JOBQUEUE': BEGIN IF NOT JobQueueSetup.GET THEN BEGIN JobQueueSetup.INIT; JobQueueSetup.INSERT; END;
This part of the code tells NAS to do, if it logs on with Startup Parameter OSYNCH or JOBQUEUE. So, add your own parameter here, like this:
IF CGNASStartedinLoop = FALSE THEN CASE Parameter OF 'NAS': BEGIN // This is your new section, and where you will tell your NAS what to do. END; 'OSYNCH','JOBQUEUE': BEGIN IF NOT JobQueueSetup.GET THEN BEGIN JobQueueSetup.INIT; JobQueueSetup.INSERT; END;
You now have your NAS application, but at the moment it’s not doing anything. Let’s make the simplest application in the world: Put one line in this new section: MESSAGE(‘NAS Has logged in!’);Close (and safe) the codeunit.
Test it!Now it’s time to see if everything has been set up correctly. Because NAS doesn’t have a user interface, it cannot open a message box. Instead, it will put any messages from the MESSAGE command as a message in the application log (Event Viewer). Check that NAS is working by following these steps:
1) Go to Services, and (re)start the NAS Service. Just because NAS starts, it doesn’t necessarily mean that it works!2) Open the Even Viewer (Start, Programs, Administrative tools, Even Viewer. Click “Application Log” and check the latest messages here. If you see a message saying ‘NAS Has logged in!’ it means that NAS has successfully run the function in codeunit 1.
Make an Application using the timer trigger:
Create a new codeunit. Declare one variable:
Name Datatype SuntypeNavisionTimer Automation 'Navision Timer 1.0'.Timer
Set the property WithEvents to Yes on this variable. Notice the new trigger that was created.
Add this code:OnRun()IF ISCLEAR(NavisionTimer) THEN CREATE(NavisionTimer);
NavisionTimer.Interval := 3000;NavisionTimer.Enabled := TRUE;
NavisionTimer::Timer(MilliSecounds : Integer)MESSAGE('Time is %1',TIME);
Run the codeunit and see that Nothing happens. – why is that?
Design the codeunit again, go to codeunit properties and set the property Singleinstance to Yes.Run the codeunit again and see the difference that this property made. SingleInstance means that the codeunit will keep running, waiting to be triggered by something - in this case, the timer.
The only way to stop a SingleInstance codeunit, is to close or reopen the company (Ctrl+O).
Now go back to codeunit 1, and replace the code in function 99 with this line:
Because of Object Cache, NAS may not pick this change up until you restart the service. So do that, and if everything works OK, you should now get the time in your application log every three seconds.
Remember that NAS is just a client without a user interface. So the simplest way to troubleshoot NAS, is to run whicever codeunit it runs from a normal NAV client. You can then better see what it is doing, and you can use the normal debugging features.
Microsoft Dynamics UK
I just want to point you to the whitepaper describing the changes done for the Microsoft Dynamics NAV 5.0 SP1 SQL Option:
With the release of Microsoft Dynamics NAV 5.0 SP1, major changes have been made to Microsoft Dynamics NAV™ with Microsoft SQL Server. This document outlines these changes and shows how these changes can help you improve the Microsoft Dynamics NAV customer experience. This document will only cover changes to Microsoft Dynamics NAV with SQL Server.
Martin Nielander (martinni)Program Manager
This post is the first in a planned series to describe various "modern" methods for troubleshooting performance problems with Microsoft Dynamics NAV on SQL Server. The idea is also to make the best out of information that already exists, either in other places on this blog or anywhere else.
Modern Troubleshooting:The idea about "Modern Troubleshooting" is:
I want to make it clear that with "Troubleshooting", I mean "Trouble". And the methods I describe here will be quick-fixes for when something has gone wrong already. I don't mean to reduce the need for thorough performance- or scalability reviews, which can still require lots of work and understanding of the customers business. So I definitely don't want the "Modern Troubleshooting" to replace specialist consulting and ongoing (especially pro-active) performance tuning. Of course it is always better to avoid Trouble in the first place.
Identifying Trouble-queries:One of the most useful queries I have used for performance troubleshooting recently, is the "TOP 30"- query described here:Simple query to check the recent performance history
It returns the queries that are currently in SQL Server's plan cache, sorted with the queries causing most reads at the top. Every time SQL Server generates a query plan, then this plan is stored in this cache. And every time SQL Server (re)uses this plan it will also update some statistics about the plan, like execution_count, number of reads, etc. It is this information that the "TOP 30" query gives you.
SQL Server's plan cache is changing all the time, depending on what queries SQL Server runs, so you may get different results depending on what time of the day you run the query. The plan cache is also reset when SQL Server restarts, or you can reset the cache by running DBCC FREEPROCCACHE.
The result of the "TOP 30"-query is easy to copy into an Excel spreadsheet for further analysis, or to send to someone else. So it is simple data to collect, as long as the customer is on SQL2005 or later (Being based on Dynamic Management Views (DMW) which was introduced in SQL Server 2005, it not work for SQL Server 2000).
What to look at:After receiving the result of the query - preferably in an Excel spreadsheet - these are the things I look at:Being sorted by "max_logical_reads", you have the "worst" query at the top. But also look at execution_count. If a query ran just once, it might have been a batch job, or something else that is not really causing any problems. Of course, queries that have an execution_count in the 100s or 1.000s may be more relevant to look at. Also see if the queries (stetement_text) look similar, or if many of them look to be in the same area (same tables).
The column diff_quota shows max_logical_reads divided with min_logical_reads. If this number is high, it means that the query plan is inconsistent. This can be either because of inconsistent use of NAV (for example users applying different filters on the same table). Or, because a query plan is good for some queries but bad for others. In this case, some times you can affect the way that SQL Server creates query plans, either by adding RECOMPILE hints, plan guides or index hints. Or by upgrading to a newer version of NAV client (for example see the post "SQL Pre-processing in Microsoft Dynamics NAV 5.0 SP1" for how NAV 5 SP1 will cause different query plans).
If diff_quota is low, it means that the query plan is just consistently bad, which means that it is more likely that the query itself is bad. And, you will have to look for reasons why that query consistently causes the number of reads that it does. The "TOP 30"-query can't really help finding out why a query is causing many reads. But at least it can some times identify which queries to investigate first, which can be a very time consuming task otherwise (collecting and analysing profiler traces, etc).
You can also look at max_elapsed_time, but keep in mind that when a query takes a long time to run because it is being blocked, then the real problem is somewhere else (in the blocking query). So, if a query has a high max_elapsed_time, then see if the query contains a lock (WITH UPDLOCK). If it does, then you are most likely looking at a blocking problem which requires a wider look, and which often cannot be solved by the query you see.
So the "TOP 30"-query is always a good place to start. Some times it won't help you solving any problems, but then you will know that without spending much time. Other times, the query tells you right away which queries are causing problems, which can save you a lot of time. So I would always run this query first. And only if it doesn't help, then begin to look at collecting further information.
Lars Lohndorf-Larsen (Lohndorf)Escalation Engineer
When time passes by and people started to update their Office environments with the latest Office release, we immediately saw an increase of cases coming in that state that with Office 2007, E-mail logging refuse to log E-mails when using the Application Server while this worked in earlier releases of Office. This seems to relate to the way Office 2007, or better Outlook 2007, deals with security that is in the Trust Center. If there is no antivirus solution installed, then Office 2007 seems to act differently causing the whole confusion why E-mail logging does not work at once.
We at Microsoft do think that everyone now has an antivirus solution installed on their client PC's. Well I have news about that: not everyone does have a client with an antivirus solution installed. This is a misconception from our side. For example: in demo environments using virtualizations without Internet access, there is no absolute immediate need to install an antivirus solution. But we sometimes see PC's where this is indeed true: no antivirus solution installed or one that is installed but is actually expired.
In all those scenario's when using NAS, there are no error message and the QUEUE Public Folder is building up. As we all know already, when using NAS in combination with MAILLOG in NAV 4.0 or JOBQUEUE in NAV 5.0, we need to configure the Outlook Security Settings template in a Public Folder when using Exchange 2003. For later releases, GPO can do this for you, but that is out of scope of this blog.
Outlook 2007 can use either public folder security forms or Group Policy to manage security for attachments and for add-ins. The ability to use Group Policy object (GPO) settings to store security settings is a new feature in Outlook 2007. If your environment uses public folders, and if you use public folder security forms in earlier versions of Outlook, you can continue to use public folder security forms. You can do this after you make a minor change to the appropriate registry settings.
Outlook 2007 is designed to take advantage of the GPO settings to manage security for attachments and for add-ins. Unlike Microsoft Office Outlook 2003, Outlook 2007 does not use the CheckAdminSettings registry data to determine policy settings or to determine trust levels for add-ins. Instead, Outlook 2007 uses the new AdminSecurityMode registry entry to determine the security policy. The AdminSecurityMode registry entry uses the following configuration: Key: HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\12.0\Outlook\Security DWORD value: AdminSecurityMode Values:
0: Use the default Outlook security settings Note This is the default setting if the AdminSecurityMode registry entry is not present. 1: Use the security policy from the Outlook Security Settings public folder 2: Use the security policy from the Outlook 10 Security Settings public folder 3: Use the security policy from the GPO settings Use the AdminSecurityMode registry entry to control the security settings that Outlook 2007 applies. You can configure Outlook 2007 to use the current security settings that are published through the existing Outlook public folder security forms. Alternatively, you can configure Outlook 2007 to use GPO-based security settings.In Office 2007 there is a now a so called Trust Center which you can find in the Tools menu of your Outlook 2007 client. If you click on Tools menu / Trust Center and then select the tab Programmatic Access, then you will see the following options: - Warn me about suspicious activity when my antivirus software is inactive or out-of-date (recommended) - Always warn me about suspicious activity - never warn me about suspicious activity
So, this means that if you do not have antivirus software on your Outlook 2007 machines, then you will get that security dialog box. It is recommended to make sure your antivirus solution is up to date. However, if that is not possible, then you can use a registry setting to override this setting: To deploy the configuration setting for programmatic access security, push out the following registry data Key: HKEY_LOCAL_MACHINE\Software\Microsoft\Office\12.0\Outlook\Security DWORD: ObjectModelGuard Possible Values: 0 (or missing) = "Warn me about suspicious activity when my antivirus software is inactive or out-of-date (recommended)" 1 = "Always warn me about suspicious activity" 2 = "Never warn me about suspicious activity (not recommended)
Marco Mels (mmels )Microsoft Dynamics NL
Microsoft Customer Service and Support (CSS) EMEA
It has come to my attention that in Outlook 2007 by default Contacts are not linked to Tasks. Let's assume you have a salesperson that goes onsite to a specific prospect and that he agrees to follow up. So he creates a Task in Outlook. In Outlook 2003, this was quite easy. You just went to the bottom of the Task window and you pressed on the Contacts button next to Categories.
This Contacts button is not there in Outlook 2007.
To enable this in Outlook 2007, you simply select Tools / Options / Preferences / Contact Options. Now you have the opportunity to links the contacts to every form. The salesperson is now able to create a Task while being onsite and link it to a specific Contact.
After synchronizing to NAV with the new Outlook Synchronization functionality, a ToDo is created for the salesperson with an additional contact added. The Contact should be there as well in NAV. That contact now also has a ToDo.
Marco Mels (mmels)Microsoft Dynamics NL
The command COUNT is pretty simple. But on the SQL option there are a number of different ways to count records, and each can give a different result. This is how the different ways of counting works in NAV on SQL:
There are two commands you can use: COUNT or COUNTAPPROX. As the name suggests, COUNTAPPROX is only designed to give an approximate count. But this does not necessarily mean that COUN is exact (I will come back to this later).
COUNTAPPROX:This command doesn't actually count anything. It only asks SQL Server to make a query plan for a SELECT statement. Then it reads the estimated number of records from the query plan. This is how COUNTAPPROX looks in a profiler trace:
It is the same as if you click on Query -> "Display Estimated Execution Plan (Ctrl+L)" in SQL Server Management Studio, instead of running a query normally (Ctrl+E / F5). This tells SQL Server to only compile a query plan, but not actually run the query. The query plan will contain "estimated number of rows", which in turn is based on SQL Server statistics. This is the number that COUNTAPPROX returns.
COUNT works differently, depending on whether there is a filter on the table or not. Without a filter it can just go to Table-Information, and get the number of records from there. This is quicker than going to the actual table and count every record. On the SQL Side, it means counting the number of rows from the sysindexes table, like this:
But sysindexes is not always up to date! Only just after having updated statistics, can you rely on the numbers in this table. So COUNT, without a filter, will not always give you the correct number.
If you have a filter, for example:
i := Cust.COUNT;
Then the method of just looking up table-information doesn't work. So NAV has to count the records the hard way. In this case we finally get an actual COUNT SQL command:
But even this method of counting is still not necessarily accurate, because it reads uncommitted data. If you run the following code from another client, and leave the CONFIRM-dialog:
OnRun()Cust.INSERT(TRUE);Cust."Currency Code" := 'EUR';Cust.MODIFY;
IF NOT CONFIRM('Continue?') THEN;
Then, the COUNT above will include a record which never existed / was never committed.
The only way to get an exact count, is by applying a lock. For example:
This will give you an exact count, whether you have a filter or not. On the SQL side it will look like this:
Because of the UPDLOCK it only counts committed records. And because of the lock, NAV knows not to just look up the number of records from table information, but to run a SELECT COUNT on SQL Server.
Lars Lohndorf-Larsen (Lohndorf)Microsoft Dynamics UK
This article describes the following procedures:• How to add a non-predefined report in Microsoft Dynamics NAV
• How to make the report available in Employee Portal in Microsoft Dynamics NAV
This article describes these procedures on a computer that is running Microsoft Windows SharePoint Services.
Typically, only some tables are configured for the demonstration site in Employee Portal. These tables include the following tables:• Customer
• Sales Header
The following reports are available to be added to Employee Portal:• Sales Quote (204)
• Order Confirmation (205)
• Quantity Explosion of BOM (99000753)
• Rolled-up Cost Shares (99000754)
• Detailed Calculation (99000756)
Note: This article uses the Service Item table (5940) to show you how to add the "Service Item - Resource Usage" report (5939) to Employee Portal.
How to add a non-predefined report:
To add the "Service Item - Resource Usage" report (5939) to Employee Portal by using the Service Item table (5940), follow these steps: 1. Add a report that is not related to the predefined tables. To do this, follow these steps: a. On the Tools menu, click Object Designer.
b. In Object Designer, click Codeunit, select codeunit 6828, and then click Design.
c. On the View menu, click C/AL Globals, and then add the new ServiceTableBased function.
d. Add the following new global variable: • Name: Service Item
• Data Type: Record
• Subtype: Service Item
e. Add the following line of code to the ServiceTableBased function.
ReturnValue := REPORT.SAVEASXML(ReportID,TempPath,TRUE,"Service Item");
f. Add the following line of code to the CreateReportPreview function.
REPORT::"Service Item - Resource Usage":
ReturnValue := ServiceTableBased(ReportID,TmpFileName,PrintRecordRef);
g. Click Save, and then click Compile.
How to make the report available in Employee Portal:
1. Add the Show Report action to the Action list of the Web part. To do this, follow these steps:a. Click Administration, expand Application Setup, expand Employee Portal, and then click Groups.
b. Select an existing "Web part request" card, and then click Card.
c. Click Table, and then click Card. Or, press SHIFT+F5.
d. Select the required table, and then click Actions.
e. In the EP WP Table Card dialog box, specify the following information:• Type: Show Report
• Target WP Request: Current
• Code: SHOWREPORT
• Target Table No.: 5940
• Report ID: 5939
• In the Caption field, type a new caption for the "Service Item - Resource Usage" report.
2. Add the Web part to Windows SharePoint Services. To do this, follow these steps:a. Open Employee Portal in a Web browser.
b. In the Add Web Parts list, drag a Web part to the location that you want in the window.
c. In the Modify My Web Part box, select the group that contains the Web part.
d. In the Web Part Request list, select the Web part for which you added the actions in step 1 earlier in this section.
Mohamad Vajid (mvajid)
Microsoft Dynamics ME
This article describes how to do the following:• How to configure a table in Microsoft Dynamics NAV 4.0.
• How to make the table available in Employee Portal in Microsoft Dynamics NAV.
This article describes how to do this on a computer that is running Microsoft Windows SharePoint Services.
Typically, Employee Portal has only some tables configured for the demonstration site. These tables include the following tables:• Customer
• Production BOM
Note: This article uses the Job (167) table to show you how to add a table to Employee Portal.
To configure a table in Microsoft Dynamics NAV and then make the table available in Employee Portal, follow these steps:Step 1: Create a new Web part request template card
1. Click Administration, expand Application Setup, expand Employee Portal, and then click Web Part Request Template.
2. Press F3. In the JOBCARD - EP WP Request Template Card dialog box, specify the following settings for the Job (167) table:a. In the Code box, type JOBCARD.
b. In the Description box, type Job Card.
c. Click to select the Editable check box.
d. In the Type list, click Card.
Note: The settings that you specify depend on the table that you are configuring. e. In the Caption field, type Job Card.
f. In the Table No. field, click the lookup arrow, and then click the Job (167) table.
g. In the Header or Line field, click Header.
h. If you want to populate the Web part with the first record from the table, click 1 in the First Record Shown field.
i. In the No. of Records field, click the number of records that you want to display in the Web part.
3. Click Table, and then click Card. Or, press SHIFT+F5.
4. In the JOBCARD - EP WP Table Card dialog box, follow these steps in the Code field for the General row: a. In the Header or Line field, click Header.
b. In the Caption list, click General.
5. Click Tab, and then click Card. Or, press SHIFT+F5.
6. In the JOBCARD 167 Header - EP WP Table Tab Card dialog box, follow these steps: a. Click the lookup arrow for the Field No field.
b. In the Length field, enter the length for each column.
c. In the Appearance field, click one of the following items for each column:• Visible
• Hidden or Editable
d. In the HTML Layout field, click the type of control to which each field belongs. For example, click Text Field, List, or Check Box.
e. Click to select the Required check box for the required field.
f. If you want to sort the table by a specific field, click to select the Sortable check box.
g. If you want to be able to populate a field by using information from another table, select that field in the table. Next, click the Field button, and then click Lookups. Then, click the table that you want to use to populate the field.
7. You can customize tabs such as the POSTING tab and the DURATION tab by following step 1 through step 6.You can now use the new Web part request template card together with existing groups. Or, you can create a new group. The new Web part request template card contains a table and its required columns.
Step 2: Add the Web part request template card to a group
1. Click Administration, expand Application Setup, expand Employee Portal, click Group, and then click SALES.
2. In the SALES - EP Group Card dialog box, click the newly created JOBCARD card in the list of Web part request templates.
Notes• Typically, you add the Web part request template card to a group so that the Web part request template card is available on the Web site.
• You can add the same card to multiple groups.
• You can move between groups by using the Next arrow or by using the Previous arrow on the toolbar.
Step 3: Assign the group to a user
A user who has access to the Sales group will also have access to the JOBCARD card that is created and that is added to the group. Otherwise, you must create a new user.
Step 4: Add the Web part to Windows SharePoint Services
1. Open Employee Portal in a Web browser.
2. In the Add Web Parts list, drag the Card Web Part Web part to the location that you want in the window.
3. In the Modify My Web Part box, click Sales in the Group list.
4. In the Web Part Request list, click Job Card, and then click OK. Then, review the Job Card dialog box to make sure that all the fields and all the tabs that you configured are displayed.
Mohamad Vajid (mvajid)Microsoft Dynamics MEMicrosoft Customer Service and Support (CSS) EMEA
Form tab captions that contain country specific characters (for example, Å in Swedish) will be displayed differently in MS Word/Excel, when using local language version of MS Office. For example, if running Nav 5.0 SE version and Customer card the first tab on the card (General) will be displayed as Allmõnt instead of Allmänt when sent to Word (when using local MS Office version).
A workaround is suggested here for both Word and Excel. To correct this, a character translation is needed, based on conversion of decimal codes of characters exported. The following example illustrates how this could be corrected.
Note, decimal character codes used in this example are character codes for characters õ and ä described in the scenario
õ ansi decimal code 143
ä ansi decimal code 197
and can be found in ANSI character set table referred to at the bottom of the blog.
For style sheets used for Word documents:
Open the style sheet file in notepad, default file is NavisionFormToWord, placed in Stylesheet folder of the Client folder.
Browse to the following section and replace the section
<xsl:variable name="nbsp1"></xsl:variable> <!-- this is ANSI code for character as displayed in Word-->
<xsl:variable name="nbsp2">Å</xsl:variable> <!-- this is ANSI code for character, as seen on Nav form-->
Then browse to the following section
find the first occurance of the following line and replace the line
For style sheets used for Excel documents:
Open the style sheet file in notepad, default file is NavisionFormToExcel, placed in Stylesheet folder of the Client folder.
<xsl:variable name="DecimalSeparator" select="Object/DecimalSeparator"/>
Then browse to the following section and replace the section
Finally, find the following section and replace the section
<Cell ss:StyleID="tabCaption"> <Data ss:Type="String"> <xsl:value-of select="@caption"/> </Data> </Cell>
<Cell ss:StyleID="tabCaption"> <Data ss:Type="String"> <xsl:value-of select="translate(@caption,$nbsp1,$nbsp2)"/> </Data> </Cell>
Note that a variable can be added for each character this applies to.
So to correct 2 such characters one can for example add 4 variables (one for ansi code of each character as shown in Nav and Office).
And translate functions can be nested, so the line
is then replaced with
The following link contains character table for ANSI.
Jasminka Vukovic (jvukovic )
Microsoft Dynamics NOMicrosoft Customer Service and Support (CSS) EMEA
This post is starting of a summary of style sheet issues reported in Dynamics NAV 5.0 when using send-to Excel/Word functionality, and attempt to provide workaround suggestions for as many of these issues as possible.
Most issues are related to regional settings and use of decimal separator and or/date format. In 5.0, when xml file with data is created by application, only values displayed on form are passed, along with the decimal separator sign used. Style sheets are determining the field type based on the format of the field value. As different date formats are used in different places, along with different decimal separator/thousand delimiter combinations, this can lead to number of issues. In newer versions, 'data type' attribute is passed along with decimal separator and field value, to avoid ambiguous formatting issues.
Keep in mind that matrix forms and forms like Customer Sales History are not supported by style sheets at all.
The list below contains three of the issues reported on 5.0, some corrected in 5.0 SP1 version, and a suggestion for possible workaround.
Other reported issues will be handled in coming blogs.
1. When running forms that contain several subforms (example form 521, Application Worksheet), and selecting Send to Excel, the following error is reported in excel:
Problems came up in the following area during load: Workbook Setting...
Table box names created in excel should be added a counter value to the name to avoid this issue. To do this:
Open the style sheet file in notepad, default file is NavisionFormToExcel, placed in Stylesheet folder of the Client folder.
Browse to the following section and replace the marked line :
<xsl:template match="Control[@type='TableBox']"> <Worksheet xmlns="urn:schemas-microsoft-com:office:spreadsheet"> <xsl:attribute name="ss:Name"> <xsl:variable name="TableBoxCaption"> <xsl:value-of select="//Object/@caption"/> </xsl:variable> <xsl:value-of select="substring($TableBoxCaption,1,30)"/> <-- REPLACE THIS LINE --> </xsl:attribute>
with the following line:
<xsl:value-of select="substring($TableBoxCaption,1,28)"/><xsl:value-of select="position()"/>
2. Error when exporting date fields to excel.
If a form contains date fields and date format is dd.mm.yy or dd.mm.yyyy , following error occurs when running send-to excel, with Decimal Separator equals ‘.’:
Problems came up in the following area during load: Table...
If value of decimal separator is '.', style sheet interprets all fields containing numeric values (only) and '.' as decimals. Dates are then interpreted as invalid decimal values. One way of solving this in 5.0 is to check for number of dots, and number of places between the dots, 2 implying the value is a date. To do this:
<xsl:when test="$DecimalSeparator = '.'">
<xsl:when test="$DecimalSeparator = ','">
<xsl:when test="$DecimalSeparator = '.'">
<xsl:attribute name="ss:Type">String</xsl:attribute> <xsl:value-of select="@value"/>
<xsl:when test="$DecimalSeparator = ','">
3. Date fields exported as decimals when Decimal Separator equals ‘,’.
The same method of workaround could be applied here as for the previous issue. Checking for number of dots and number of digits between the dots and reading value 2 would normally imply that the value is a date.
1. Open the style sheet file in notepad, default file is NavisionFormToExcel, placed in Stylesheet folder of the Client folder.
2. Browse to the following section and replace the section:
<xsl:when test="$DecimalSeparator = ','">
Microsoft Dynamics NO
In some situations, using the SQLIndex property on a key in Microsoft Dynamics NAV can harm performance. In this blog I
describe what to be careful about, and why the use of this property has been removed in the NAV 5 SP1 application.
The property is still available and it is still a valuable tool in performance tuning. But from SP1, it is not used anymore
in the standard application. The document "Changes in NAV 5 0 SP1.doc" on the SP1 product CD lists the 72 tables where the
SQLIndex has been removed (Change A222).
Background:The key-property SQLIndex was introduced in NAV version 4 SP1. The idea of the property is to make it possible to change
the index on the SQL Server while maintaining the same application (same sorting) in NAV.
The main use of the property is to make the SQL index more selective. In the NAV application there are many keys that begin
with an option which is not very selective, for example the primary key "Document Type","No." on the Sales Header table.
"Document Type" - having only 6 possible options - is not very selective, and SQL Server might choose not to use it. If the
index was changed to be the other way around ("No.","Document Type"), it would be much more selective and more effecient
for SQL Server to use in SELECT statements.
The other benefit of this property is to enable "covering indexes", so that you can have a few indexes to cover for most
searches, and then disable the maintenance of other indexes. For example an index on the "Sales Header" table beginning
with "No." can be used effeciently with many different filters, reducing the need to have one key for every possible exact filter.
Problems:When you have a query which includes an "ORDER BY"-clause, SQL Server has to return the reords in the order specified by
that clause. If SQL Server doesn't have a matching index, it has to retrieve data using a different index and then do some
internal sorting to return data in the correct order. If there are no good indexes, then SQL Server may choose to
use the clustered index which can be bad enough. But when the query also has an index hint, then SQL Server is forced to use the
index specified by the hint, and this can lead to large amounts of reads.
Example:In a recent support case, the customer had generally bad performance. In this case, the "SELECT TOP 30"-query from the post "Simple query to check the recent performance history" showed that out of the top 30 "worst" queries, 26 were similar to this one
SELECT TOP 501 * FROM "Reservation Entry" WITH (UPDLOCK, INDEX("$1")) WHERE (("Source ID"=@P1)) AND (("Source Ref_
No_"=@P2)) AND (("Source Type"=@P3)) AND (("Source Subtype"=@P4)) AND (("Source Batch Name"=@P5)) AND (("Source Prod_ Order
Line"=@P6)) AND (("Reservation Status"=@P7)) ORDER BY "Source ID","Source Ref_ No_","Source Type","Source Subtype","Source
Batch Name","Source Prod_ Order Line","Reservation Status","Shipment Date","Expected Receipt Date","Entry No_","Positive"
The query itself looks good enough: WHERE-clause and "ORDER BY"-clause match each other, and there were no immediate
reasons why this query should cause more reads than the number of records in the table. But in the standard application, the SQLIndex property for this key was:
"Source ID","Entry No.",Positive
The idea with this is SQLIndex is to have an index which can cover more situations, and in that way reduce the number of indexes that
need to be maintained on SQLServer. And the SQLindex is fine for the SELECT-part of the query. The problem is, that the
index can't be used for the "ORDER BY"-part of the query.
So what happens, is:
SQL Server may have planned to use the clustered index to read all data and then do some internal sorting. But in this
case, the Index Hint forces SQL Server away from that plan. The result is that SQL Server is forced into doing a very
difficult task while being restricted by the index speicifed by the index hint.
In this case we designed the "Reservation Entry"-table and removed the SQLIndex property from the key, and performance went
Conclusion:When you see a query which causes many reads, even if SQL Server has a good index, then also consider if the index is
good for the "ORDER BY"-part of the query. The "ORDER BY"-part of the query depends on the key in NAV. But if the SQLIndex
property has been set for this key, then by definition, the "ORDER BY" and the SQL index will not be matching.
You should still consider the use of the SQLIndex property as part of tuning performance of a system. But just be aware that it can also cause problems as described here.
Lars Lohndorf-Larsen (Lohndorf)
This post describes how you can automate importing and exporting of Microsoft Dynamics NAV objects with C/Front.
To make a basic C/Front project, see the post Beginners guide: How connect to NAV from a .net project, using C/Front. This post only describes the additional code needed to import or export NAV objects.
The line below will export Tables 1..10 to the file "C:\x\ExportFob.fob":
The filter has to be in the same syntax as used in the "DataItemTableView" in a report. The simplest way to create the filter is to make a new report in NAV, based on the Object Table. Then in the DataItem Properties, specify a filter in DataItemTableView, and copy that into your C/Front code.
The file that you export is a normal .fob file, which can be imported back in the usual way (File -> Import from Object Designer), or via C/Front as described next.
C/Front has a special datatype "NavisionImportMode" to control the actions when the objects you import conflict with existing objects. The possible settings are Overwrite, Skip and ThrowError. The code needed to re-import the object we exported before, is:
ImportMode = NavisionImportMode.Overwrite;
You can only export objects as binary .fob files. It is not possible to export objects as text.
In SP1 for NAV version 5, C/Front will no longer check for license permissions when importing files. So the import-functionality works just like importing objects manually, which means that the license file is not checked. In previous versions it was not possible to import new objects or tables with new fields unless the NAV license would allow the user to create those objects or fields manually.
This post describes the simplest possible way to get started with creating a .net project in Microsoft Visual Studio, and use C/Front in c# code to connecct to a Microsoft Dynamics NAV database. The example here is based on the sample from the product CD, which will install to this folder: C:\Program Files\Microsoft Dynamics NAV\SDK\CFRONT\DotNetSampleApplication. More details can be seen from that sample, and I will also make further blog posts to describe further use of C/Front. For this post, all we want to do is to make a connection.
The example here was made in Visual Studio 2008. You can do the same in Visual Studio 2005. The NAV database in this example is running on SQL Server. To make it connect to a Native NAV database you nee to adjust NetType and DriverType.
Time to complete: Approximately 20 minutes.
C/Front is part of SDK (Software Developers Kit), which also includes the Communication Components. If you haven't installed it already, then install SDK from the NAV product CD. Then follow the steps below:
1) Open Microsoft visual Studio 2005/2008
2) Create a new project (File -> New -> Project). As project type, select "Visual c#", then select "Windows Forms Application". Type in a name and click OK.
3) Include C/Front to your project by rightclicking on "References" on the right hand side, under "Solution Explorer", and select "Add Reference". Go to the Browse-tab, and select Microsoft.Navision.CFront.CFrontDotNet.dll. As default this is installed in this folder: C:\Program Files\Microsoft Dynamics NAV\SDK\CFRONT\.
4) Now, add a button to your Form (View -> Toolbox, then double-click a button to add it). Also add a TextBox so we have a place to display data from C/Front. Double-click on the button to get to the code.
5) At the top of the code-window where Visual Studio has already added a number of "using"-commands, also add a line for C/Front: using Microsoft.Navision.CFront;
6) All the preparations done, we are now ready to program with C/Front. Go back down the the function "private void button1_Click", and copy in the code below. Just adjust values NavisionPath, ServerName and CompanyName to match your system:
// Declare specific C/Front variables
NAVText = Data;
textBox1.Text = NAVText.ToString();
7) Save the project. As default it will save to this folder: C:\Users\[UserName]\Documents\Visual Studio 2008\Projects\CFrontSampleVS2008\[ProjectName]
8) Finally, copy the files CFront.dll and CFrontSQL.dll from the C/Front folder (default C:\Program Files\Microsoft Dynamics NAV\SDK\CFRONT) into the project sub-folder bin\Debug
Now try to run it. Build the project first (Buld -> Build [ProjectName]), and check that it builds without errors. Then run it (Debug -> Start Debugging - F5). If succesful, it will display the customer name of the first customer on the form.
Always set the NavisionPath and point it to a NAV client folder of the same version as C/Front. This is where C/Front will locate essential files like dlls, flf and stx files. If you don't set this path, you are likely to get error 2 in module 1 ("The system cannot find the file specified.").
C/Front requires granule 1,800 C/FRONT. It connects just like a normal client, so it will also consume a normal user session while connected.
Lars Lohndorf-Larsen (Lohndorf )
Dynamics NAV 2009 contains a new subsystem for dealing with Web Services. This feature has been well received by partners and customers alike. Partners have expressed interest in having web services available for earlier versions of Dynamics NAV. This feedback resulted in a technology talk at Directions2007 in Florida, where the topic was what could be done to day. The conclusion of the talk was that everything we where intending to deliver was already possible today, yes some code is needed but strictly from function/feature perspective all of it is possible, and it is not even all that ugly. Dynamics NAV 2009 will provide out-of-the-box programmatic web service access to the application and will therefore remove the need for this additional technology plumbing described here.
I have to say that the response to my talk has been tremendous. After the response to my talk on Web Services in NAV 5.0 and previous versions I decided to write this blog post and make the source files available.
This post is about how to bridge the gap between the need for web services now and the current platform, it will help you understand how you can provide Web Services directly from Dynamics NAV today, in a “simple” and flexible way, already today.
To work with the samples in this post you will need: Visual Studio 2005, Dynamics NAV 5.0 and .Net 3.0 installed on your system. This sample should work on Dynamics NAV 4.0 to but has not been tested on that version.
The system we will build contains 4 different components/moving parts: Web Service Listener, Event Dispatcher, Codeunit Eventhandler and XMLPort for stream handling.
Any client that understands how to communicate with Web Services; like InfoPath, Visual Studio, SharePoint or any custom application written by you.
Is the physical communication port that the WCF listens to.
Defines the data contracts and service contracts for the Web Service, it also implements the concrete service and opens for listening in the WCF subsystem, it then delegates the requests to the COM Event Dispatcher component.
This component provides the hookups for Dynamics NAV, both to activate the service and to register event sinks. It defines 2 IDispatch interfaces the IServiceEvents and the IWebServiceListner, as well as the concrete implementation of the IWebServiceListner in the WebServiceListner class that provides the actual code for hooking up the WCF Web Service to Dynamics NAV.
We are using the CLR runtime for writing our Web Service component and our COM plugin. Some of this blog entry is about interop between Dynamics NAV and .NET through COM.
Is responsible for starting up the WCF Web Service through the COM interface, it then registered for events coming from the WCF Web Service Component. The events routed to XMLPort for processing.
It deals with the actual business logic and data coming from or going to the Web Service.
The implementation is in 2 programming languages: C# and C/AL.
Please take a look at the provided code sample, for the rest of the information contained in the posting. It can be found here: http://code.msdn.microsoft.com/nav/Release/ProjectReleases.aspx?ReleaseId=896
I have included comments in the code that should explain what is going on, if you feel something is missing, first look at the documentation for the WCF or post a comment to this post and I will try to answer it.
To deploy the sample you will first have to download it, unpack it.
Then open it up with Visual Studio and compile.
Then import the codeunit.txt and xmlport.txt into your NAV installation and compile those objects, starting with the XMLPort
To run the service simply open the Object Designer in NAV, find the Codeunit that you just imported and press run.
There is no dependency on IIS or other external components. No further deployment steps should be needed.
In the Visual studio solution is a ConsoleTestApp project. After you have followed the steps above you can run that project, it will test if your install was successful, as well as provide sample on how to use the web service.
In this sample I’m using XMLPort to handle the XML stream that is provided.
You can take many different approaches to this, and still reuse large please of the code provided in the sample.
To use the XMLPort as handler you will have to set the encoding property to UTF-8. This is due to a null termination bug in stream handler in NAV.
With this approach you can already today, incorporate web services in your projects in straightforward way.
The appropriate usage is whenever you need to give external application access to Dynamics NAV data or business process.
For any questions or comments please feel free to ask them in the comment section of this blog post. I will answer questions to best of my ability on this post in the comments section as well.
One last thing: This is a sample code. It has not been tested, you should thoroughly test this code before usage.
Best regards,Kris Rafnsson
Bulk Inserts is a new feature in NAV 5.0 SP1 which is designed to improve performance when inserting multiple records by delaying the physical inserts on the SQL Server.
Before this change, inserts happen in the order that the C/AL code is running. With Bulk Insert, the NAV-client delays the actual inserts until the last possible moment in the transaction. This means that tables get locked later, so it reduces the amount of time that a table is locked.
"The last possible moment", means that the inserts will take place just before COMMIT. Or, if you use the return value of the INSERT command (IF Rec.INSERT THEN;). NAV also has to do the inserts if you run any MODIFY, DELETE or FIND methods on the table. So to take full advantage of this feature, you have to consider this when designing a NAV process.
Note: This feature has nothing to do with the Transact SQL command "BULK INSERT". The Bulk Insert all happens on the client. It is not using any special SQL Server features.
Note: This feature has nothing to do with the Transact SQL command "BULK INSERT". The Bulk Insert all happens on the client. It is not using any special SQL Server features.
The Pseudo-code below illustrates how you will see the effect of Bulk Insert in a SQL Profiler trace. Without Bulk Insert, the SQL updates may look like this:
INSERT INTO "NAV5"."dbo"."CRONUS International Ltd_$G_L Entry"
SELECT TOP 1 FROM "NAV5"."dbo"."CRONUS International Ltd_$Cust_ Ledger Entry"
SELECT TOP 1 FROM "NAV5"."dbo"."CRONUS International Ltd_$G_L REgister"
With Bulk Insert, the same C/AL code would look lilke this:
So, you will see exactly the same SQL updates. But with Bulk Insert, the inserts will be accumulated and run at the end of the process.
Lars Lohndorf-Larsen (Lohndorf),