Strange errors come during change SourceExpr value in NAV report designer...
02 July 09 09:14 AM | gediminb | 0 Comments   

Our colleague raised problem: why he receives strange error during report compile, after he changed SourceExpr value for some control in report designer in NAV 2009.

Error message was:

Error while validating RDL content:
The Value expression for textbox “CompanyInfo” refers to the field ‘PricesInclVAT_YesNo’. Report Item expressions can only refers to fields within the current data set scope or, if inside an aggregate, the specified data set scope.

Error itself looks very strange because:
1. It comes from validating RDL content, but we changed nothing in it.
2. Changed was SourceExpr in NAV classic client report designer>sections>control property, and it has no relations to field mentioned in error. Actually what was changed: report 204 – Sales-Quote; control 116; SourceExpr had value "Sales Header"."Prices Including VAT" and now it has value FORMAT("Sales Header"."Prices Including VAT").

If we change back value – error disappears.

After deeper analyze we found that RDL dataset has field ‘PricesInclVAT-YesNo’, but after report designer change SourceExpr value by adding FORMAT – this field disappears from dataset. So problem really is in the SourceExpr value, however value itself is correct. And after few more research we found there is control 167 – name PriceIncVAT_YesNo which has exactly the same SourceExpr value - FORMAT("Sales Header"."Prices Including VAT").

Conclusion: only one source expression is pushed to RDL, if there are few controls with the same SourceExpr, only first will be in RDL, other will not appears there.

 

I asked NAV architects about this issue and they answered:

The field names that we show in the RDL dataset do NOT come from the SourceExpr property "directly". Each control on a report has a DatasetFieldName property, which is what we use to build the field names in the RDL dataset.

 

The DatasetFieldName property is then derived from the SourceExpr property the first time you open Visual Studio for a report using the View --> Layout menu item. After this, if you change the SourceExpr, the DatasetFieldName does not get changed. (The whole purpose of this property is to fix the dataset field name so even if you change your SourceExpr, you won’t need to redesign your RDL). This should cover most of the user scenarios.

 

In a few scenarios, you are not covered though: one is, if you move sections or controls in the layout, and if two controls have the same SourceExpr value, the control we choose to export to the report dataset may change with another one with the same SourceExpr. Since they have different DatasetFieldName properties, your RDL will break. We don’t cover this scenario and we don’t believe that we could fix this easily.

 

In another scenario: if you change the SourceExpr, and the data type of the new field is different than the old one, RDL compilation may fail due to the expressions used on that field - as these are data type dependent.

So, during report design be very careful with modifying 2 properties: SourceExpr and DataSetFieldName. Changes could impact RDL very much and result could be not you are expecting. Of course this is important if you already have RDL report prepared, if you will create new layout by using "Laoyout suggestion", problems will not come, because new RDl laoyout will be created regarding earlier described rules.

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Special thanks to John Vestergaard from Logica Danmark A/S for pointing us to this feature.

Gedas Busniauskas

Microsoft Lithuania
Microsoft Customer Service and Support (CSS) EMEA

 

Where is the zup file again?
01 July 09 10:12 AM | Lohndorf | 1 Comments   

I keep forgetting where the CustomSettings.config, ClientUserSettings.Config etc files are. So I keep looking it up again in "Where is the zup file". This time, I collected the location of these files in a NAV form so I don't have to look them up anymore. In addition to this you can edit the files from the form directly. It looks like this:

 

ZupForm 

 

The first time you run the form it will insert a record with the default settings. If your installation is in different folders, then you can of course just modify this. You can also create new records in case you have multiple NAV2009 installations / config files.

Note: If you run on Vista / Win2008 and want to update the config files from here, then you may have to start your NAV client as Administrator, or you may get "access denied" when clicking the update button.

 

RunasAdmin

 

I hope this makes it simpler to change setup settings. Objects attached are:

Type ID Name
Table 74250 NAV2009 Config Files
Form 74250 NAV2009 Config Files Card

 

Instructions for use: Run form 74250. 

As always, these postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Lars Lohndorf-Larsen

Microsoft Dynamics UK

Microsoft Customer Service and Support (CSS) EMEA

Filed under:
Attachment(s): zup.fob
How to manage NAV DBCS data using C#
16 June 09 07:26 AM | dtacconi | 0 Comments   

 

It is known that NAV CC (Classic Client) does not support natively DBCS (Double-Byte Character Set) and so does the new NAV 2009 RTC (Role Tailored Client).

Due to differences in how the CC and RTC check the code page isn’t still possible to enable DBCS in the RTC but this is possible for the CC by implementing new fin.stx file.

This last sentence is duly written and explained in KB 915374.

How to enable and to display double-byte character sets in Microsoft Dynamics NAV
https://mbs.microsoft.com/knowledgebase/KBDisplay.aspx?scid=kb;EN-US;915374

Following  the KB link is possible to enable DBCS for several NAV versions included NAV  2009.

… But what if we want to develop a simple WinForm project in VC# that access the database in order to retrieve and write information in the same way NAV does?

The following example will guide you through the creation of a simple Form using VS (Visual Studio ) and transforming Japanese characters in their “NAV equivalent” in order to deal correctly with the DBCS data management inside the NAV database.

The example proposed has been developed using the following scenario:

1.       Windows Server 2008

2.       SQL Server 2008

3.       Visual Studio 2008 SP1

4.       NAV 2009 RTM W1

ENABLE DBCS IN NAV 2009

a.       Download and install a copy of NAV 2009 W1 RTM.

Install the sample database and the Classic Client.

The SQL sample database should use Windows Collation for Afrikaans, Basque, Catalan, Dutch, English, Faeroese, German, Indonesian, Italian, Portuguese.

This can be easily checked in NAV by checking the collation tab in

File > Database > Alter

b.      In Windows Server 2008 select Japanese as language for non-Unicode programs.

Control Panel > Regional and Language Options > Administrative tab

Change the current language for non-Unicode programs to: Japanese (Japan)

(you will be prompted to reboot the machine)

c.       Download the zip file contained in KB 915374

d.      Extract the fin.stx file from the folder NAV 2009

e.      Substitute the fin.stx file that is located in the Classic client folder with the brand new one extracted.

E.g. Path for Classic Client folder:

C:\Program Files (x86)\Microsoft Dynamics NAV\60\Classic

f.        Substitute the fin.stx file that is located in the ENU folder of the Classic Client with the brand new one extracted.

E.g. Path for Classic Client folder:

C:\Program Files (x86)\Microsoft Dynamics NAV\60\Classic\ENU

Now you should be able to manage Japanese characters like those ones…

NAV with DBCS enabled

WHAT TYPE OF ENCODING?

Roughly speaking regarding what we have done is merely enabling the Japanese characters to be stored into SQL Server but… not directly!

The Japanese code page is 932 (Shift-JIS) while we are using the  Latin1 code page 1252 to store the data. To know more about Windows Collation Designators you can check:

http://msdn.microsoft.com/en-us/library/aa176553.aspx

This means that while we are typing Japanese chars in the NAV classic Client (using code page 932), this have been reverted (translation encoded) in their respective characters using code page 1252 and stored in this way in the SQL Server field.

This means that while we are seeing this in NAV :

ラドクリフ、マラソン五輪代表に1m出場にも含み

… those are the characters effectively stored in SQL Server …

ƒƒhƒNƒŠƒtAƒ}ƒ‰ƒ\ƒ“ŒÜ—Ö‘ã•\‚É1–œmoê‚É‚àŠÜ‚Ý

Then the solution can come out clearly: use C# encoding function to manage the ‘translation’ between one set of character to another.

LET’S BUILD WinFormNavDBCS

1.       Open Visual Studio 2008

2.       Create a brand new Visual C# project

Go to File > New > Project

Select project types: Visual C# > Windows > Windows Forms Application

Give the project a Name: WinFormDBCS

Click OK

3.       Design your form like this (2 TextBox, 1 Button)

clip_image004

4.       Add this code to your form:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

 

namespace WinFormDBCS

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            //Create a new variable of type Encoding and

            // assign it the Latin

     //  code page 1252

            //To know more about it

            // http://msdn.microsoft.com/en-us/library/system.text.encoding_members.aspx

            Encoding nav = Encoding.GetEncoding(1252);

           

            //Create a new variable of type Encoding and assign it the Japanese

     //  code page 932

            Encoding unicode = Encoding.GetEncoding(932);

 

            //Populate a byte variables withe the value of the first TextBox written

     //  in Japanese characters using the Japanese code page 932

            byte[] unicodeBytes = unicode.GetBytes(textBox1.Text);

 

            //Display in the second TextBox the result of the encoding conversion of

     //  the byte stored in Japanese directly in the Latin code page equivalent

            //Tip: you can substite the mere text display with some simple code that

     //  writes directly this value into a NAV Text field

            textBox2.Text = nav.GetString(unicodeBytes);

        }

    }

}

5.       Press F5 to start debugging your project.

6.       Insert this Japanese string (or whatever Japanese sentence you want to) in the first TextBox:

ラドクリフ、マラソン五輪代表に1m出場にも含み

 

7.       Press the Transform Data button and… see the results:

clip_image006

8.       To check if NAV ‘digest’ those newly created string you have to select the whole string converted in the second TextBox and copy it:

 clip_image008

9.       Open SQL Server Management Studio and paste it into the “Address 2” field of customer 01121212.

Expand “Demo Database NAV (6-0)”

Expand “Tables”

Search for “CRONUS International Ltd_$Customer” table

Right click on “CRONUS International Ltd_$Customer” and click on “Edit top 200 rows”

Search for customer 01121212

Place the cursor in the “Address 2” field and paste the content in this field

clip_image010

10.   Browse to the next record and close SQL Server Management Studio.

CHECK THE FINAL RESULT

Open NAV and… go to customer 01121212.

clip_image012

 

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Best Regards,

Duilio Tacconi

Microsoft Dynamics Italy

Microsoft Customer Service and Support (CSS) EMEA

 

Special thanks to Kenny Vaes of Helios-IT

Filed under:
What do SPNs actually do - NAV 2009
15 June 09 01:36 PM | Lohndorf | 0 Comments   

Three terms keep coming up when setting up NAV 2009 when NAV-server (middle tier) runs on a different machine than SQL Server:
  - Delegation / Impersonation
  - Kerberos
  - SPN

Delegation / Impersonation is what it says it is. Kerberos is handled more or less automatically by Windows. But what do SPNs actually do....

(un)fortunately SPN can't be explained without first explaining Delegation and Kerberos.

 


Delegation / Impersonation:
The end-user (RTC) logs on to the NAV-Server which then logs on to the SQL Server - using the end-user's credentials (impersonating the end-

user). All logins here are Windows logins. Impersonation would also be a nice way for a hacker to gain access, so therefore Windows requires

that a domain administrator specifically allows the NAV-server to impersonate users on the SQL Server.

This is only when the NAV-Server and SQL Server runs on two different machines. When they run on the same machine, then Windows has already

authenticated the end-user when they connected to the NAV-Server. So when the NAV-Server logs on to the SQL Server (on the same machine),

Windows has already knows the end-user. So in this case there is no need to set up delegation, and hence no need to worry about Kerberos and

SPNs.

But with two machines, delegation is needed. Delegation requires Kerberos.

 

Kerberos:
Connections between two users happen all the time. What Kerberos adds to such a connection is a certificate (ticket) which ensures that each

of the two users can trust the identity of the other user. This is actually a kind of countermeasure against a user (hacker) impersonating

another user. Windows requires that before it allows delegation, that the connection being delegated is a Kerberos connection. In this way,

Windows has assurance that the user credentials being forwarded are valid. So when RTC connects to the NAV-server, it has to do this with a

Kerberos connection.

A Kerberos connection is between two Windows user accounts. A user doesn't know (shoulnd't know) what user account the NAV-server runs under.

This is where SPNs come in. So, finally we get to the SPNs:

 

SPN:
SPN (Service Principal Name) is a simple table that maps a service to a user account. Think of it as a table with two fields: Service-name,

and Windows User name. When the NAV client wants to start a Kerberos connection to the NAV-server, it will connect to for example

DynamicsNAV\Nav-Server:7046. Kerberos requiring a user name will then look this up in the SPN table and find the user name there. So, only if

an SPN has been created for the account that runs the NAV-service, will Windows be able to then start a Kerberos connection. And the user will

never need to know which that account the NAV-server is running under.

When setting up SPNs, make sure that:
  1) The account that runs the NAV-service has an SPN that contains what the NAV client will connect to (Server name in the right format),and
  2) Quite a common probem: Make sure that there are no duplicate SPNs. If you change the NAV-service to run under a different account you must set up SPNs for the new account. Then make sure to also remove the SPNs for the old account.

 


So in short: Delegation / Impersonation requires Kerberos. Kerberos connection to a service running an unknown account, requires SPN. And,

visa versa, if SPNs have not been set up correctly, then Kerberos won't work so then Delegation wont work either.


 

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

 

Best regards


Lars Lohndorf-Larsen

Microsoft Dynamics UK


Microsoft Customer Service and Support (CSS) EMEA

Filed under:
Setting up NAV 2009 on Three machines
12 June 09 02:38 PM | Lohndorf | 0 Comments   

Setting up delegation and SPNs for NAV 2009 on three machines (when the NAV Server and SQL Server are on two seperate machines) is described in "Walkthrough: Installing the Three Tiers on Three Computers". But in addition to this, also be aware of the following:

  • The syntax of SPNs has changed since KB 968189
  • You may need to set UserAccountControl flag in Active Directory

Also thanks to our German colleagues for already posting this information here and here.

  

Syntax of SPNs has changed since KB 968189

After installing KB 968189 for NAV 2009 (Build 6.0.28795.0) the SPNs now have this format:
<Instance>/<server host>:<port>
<Instance>/<server FQDN>:<port>


So for example if the SPNs used to be set like this:

NAV-SERVER_DynamicsNAV/NAV-SERVER.Domain.com:7046
NAV-SERVER_DynamicsNAV/NAV-SERVER:7046

From this build and later they have to be set like this:
DynamicsNAV/NAV-SERVER.Domain.com:7046
DynamicsNAV/NAV-SERVER:7046


About KB 968189 itself, it solves a very specific problem where it may not be possible to connect if the domain has multiple DNS Suffixes, which is quite unusual. Most installations are not affected by this. You can check whether you are affected by running ipconfig from a command prompt, and see if it lists more than one domain name under "Connection-specific DNS Suffix".

 

Setting UserAccountControl flag

In some cases you have to set UserAccountControl as described in KB 305144. You set this flag by running ADSIEDIT.msc, go to properties of the user account running your NAV Server, and then select UserAccountControl. Setting it to 17301504 means TRUSTED_FOR_DELEGATION+TRUSTED_TO_AUTH_FOR_DELEGATION

 

 

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

 

Best regards


Lars Lohndorf-Larsen

Microsoft Dynamics UK


Microsoft Customer Service and Support (CSS) EMEA

Filed under:
SQL Query to show tables, their indexes and index usage
04 June 09 02:11 PM | Lohndorf | 2 Comments   

The SQL query below shows a list of tables sorted by the largest tables first. For each table, the indexes in the table are shown. For each index it shows when the index was last used. The query is designed to collect various pieces of information in one place, and give an overview to help supporting decisions when doing index tuning.

The left hand columns show data for the table (No. of receords, data- and index size) to have a view of the impact of having indexes on the table.

The right hand columns show data for each index, including Updates (costs) and Reads (benefits) and when it was last used sine the last time SQL Server was restarted.

 

Further comments:

  • The query only works on SQL Server 2005 and later.
  • The numbers in the query are reset every time SQL Server restarts.
  • The query may take up to a few minutes to run.
  • The query is provided "as is", with no warranties and confers no rights. You assume all risk for your use.

 

If you have comments or feedback, please feel free to post them here.

 

 

Best regards


Lars Lohndorf-Larsen

Microsoft Dynamics UK


Microsoft Customer Service and Support (CSS) EMEA

 

 

--use NavisionDatabase

IF OBJECT_ID ('z_IUQ2_Temp_Index_Keys', 'U') IS NOT NULL

DROP TABLE z_IUQ2_Temp_Index_Keys;

-- Generate list of indexes with key list

create table z_IUQ2_Temp_Index_Keys(

[l1] [int] NOT NULL,

[F_Obj_ID] [int] NOT NULL,

[F_Schema_Name] [nvarchar] (128) NULL,

[F_Table_Name] [nvarchar] (128) NOT NULL,

[F_Row_Count] [int] NULL,

[F_Reserved] [int] NULL,

[F_Data] [int] NULL,

[F_Index_Size] [int] NULL,

[F_UnUsed] [int] NULL,

[F_Index_Name] [nvarchar] (128) NOT NULL,

[F_Index_ID] [int] NOT NULL,

[F_Column_Name] [nvarchar] (128) NOT NULL,

[F_User_Updates] [int] NULL,

[F_User_Reads] [int] NULL,

[F_Last_Used] [datetime] NULL,

[F_Index_Type] [nvarchar] (128) NOT NULL,

[F_Index_Column_ID] [int] NOT NULL,

[F_Last_Seek] [datetime] NULL,

[F_Last_Scan] [datetime] NULL,

[F_Last_Lookup] [datetime] NULL,

[Index_Key_List] [nvarchar] (MAX) NULL

)

go

CREATE NONCLUSTERED INDEX [Object_ID_Index] ON [dbo].[z_IUQ2_Temp_Index_Keys]

([F_Obj_ID] ASC

)

go

CREATE NONCLUSTERED INDEX [Index_ID_Index] ON [dbo].[z_IUQ2_Temp_Index_Keys]

([F_Index_ID] ASC

)

go

CREATE NONCLUSTERED INDEX [RowCount_ID_Index] ON [dbo].[z_IUQ2_Temp_Index_Keys]

([F_Row_Count] ASC

)

go

 

insert into

z_IUQ2_Temp_Index_Keys

SELECT

(row_number() over(order by a3.name, a2.name))%2 as l1,

a1.object_id, ---

a3.name AS [schemaname],

a2.name AS [tablename],

a1.rows as row_count,

(a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved,

a1.data * 8 AS data,

(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS index_size,

(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS unused,

-- Index Description

SI.name,

SI.Index_ID,

index_col(object_name(SIC.object_id),SIC.index_id,SIC.Index_Column_ID),

-- Index Stats

US.user_updates,

US.user_seeks + US.user_scans + US.user_lookups User_Reads,

case

when (ISNULL(US.last_user_seek,'00:00:00.000') >= ISNULL(US.last_user_scan,'00:00:00.000')) and (ISNULL(US.last_user_seek,'00:00:00.000') >= ISNULL(US.last_user_lookup,'00:00:00.000')) then US.last_user_seek

when (ISNULL(US.last_user_scan,'00:00:00.000') >= ISNULL(US.last_user_seek,'00:00:00.000')) and (ISNULL(US.last_user_scan,'00:00:00.000') >= ISNULL(US.last_user_lookup,'00:00:00.000')) then US.last_user_scan

else US.last_user_lookup

end as Last_Used_For_Reads,

SI.type_desc,

SIC.index_column_id,

US.last_user_seek,

US.last_user_scan,

US.last_user_lookup,

''

FROM

(SELECT

ps.object_id,

SUM (

CASE

WHEN (ps.index_id < 2) THEN row_count

ELSE 0

END

) AS [rows],

SUM (ps.reserved_page_count) AS reserved,

SUM (

CASE

WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)

ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)

END

) AS data,

SUM (ps.used_page_count) AS used

FROM sys.dm_db_partition_stats ps

GROUP BY ps.object_id) AS a1

LEFT OUTER JOIN

(SELECT

it.parent_id,

SUM(ps.reserved_page_count) AS reserved,

SUM(ps.used_page_count) AS used

FROM sys.dm_db_partition_stats ps

INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)

WHERE it.internal_type IN (202,204)

GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)

INNER JOIN sys.all_objects a2 ON ( a1.object_id = a2.object_id )

INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)

inner join sys.indexes SI ON (SI.object_id = a1."object_id") ---

inner join sys.index_columns SIC ON (SIC.object_id = SI.object_id and SIC.index_id = SI.index_id)

left outer join sys.dm_db_index_usage_stats US ON (US.object_id = SI.object_id and US.index_id = SI.index_id)

WHERE a2.type <> N'S' and a2.type <> N'IT'

order by row_count desc

go

-- Populate key string

declare IndexCursor cursor for

select F_Obj_ID, F_Index_ID from z_IUQ2_Temp_Index_Keys

for update of Index_Key_List

declare @objID int

declare @IndID int

declare @KeyString VARCHAR(MAX)

set @KeyString = NULL

open IndexCursor

set nocount on

fetch next from IndexCursor into @ObjID, @IndID

while @@fetch_status = 0 begin

set @KeyString = ''

select @KeyString = COALESCE(@KeyString,'') + F_Column_Name + ', '

from z_IUQ2_Temp_Index_Keys

where F_Obj_ID = @ObjID and F_Index_ID = @IndID

ORDER BY F_Index_ID, F_Index_Column_ID

set @KeyString = LEFT(@KeyString,LEN(@KeyString) -2)

update z_IUQ2_Temp_Index_Keys

set Index_Key_List = @KeyString

where current of IndexCursor

fetch next from IndexCursor into @ObjID, @IndID

end;

close IndexCursor

deallocate IndexCursor

go

-- clean up table to one line per index

delete from z_IUQ2_Temp_Index_Keys

where [F_Index_Column_ID] > 1

go

select

[F_Table_Name] TableName,

[F_Row_Count] No_Of_Records,

[F_Data] Data_Size,

[F_Index_Size] Index_Size,

[F_UnUsed] UnUsed_Space,

[F_Index_Name] Index_Name,

[F_User_Updates] Index_Updates,

[F_User_Reads] Index_Reads,

[F_Last_Used] Index_Last_Used,

[F_Index_Type] Index_Type,

[Index_Key_List] Index_Fields

from z_IUQ2_Temp_Index_Keys

order by F_Row_Count desc, F_Table_Name, [F_Index_ID]

 

 

 

Filed under:
How to use WCF Performance Counters with NAV 2009 Server
19 May 09 11:06 AM | Lohndorf | 1 Comments   

NAV Server (middle tier) utilises Windows Communication Foundations (WCF), which includes a number of performance counters that you can use to monitor NAV Server performance in real-time. This example shows how to monitor "Calls Per Second" for NAV Server to get some idea of how busy it is over a working day / over time. Many other counters are available.

Enable Counters

First, enable WFC Performance Counters as described in this article WCF Performance Counters:

1)  Use Notepad to edit "Microsoft.Dynamics.Nav.Server.exe.config" in the NAV Service folder (default is C:\Program Files\Microsoft Dynamics NAV\60\Service).

 

2)  Add the section below, marked with Red:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings file="CustomSettings.config" />
  <system.diagnostics>
    <assert assertuienabled="false" />
  </system.diagnostics>

  <system.serviceModel>
      <diagnostics performanceCounters="All" />
  </system.serviceModel>

</configuration>

 

3)  Restart NAV Server.

 

Watch Counters

Use Windows Performance Monitor to select and view counters from NAV Server:

1)  Start Windows Performance Monitor (Start -> Run -> Perfmon.exe)

 

2)  Add a Counter, then from available categories, select ServiceModelService. This will list the NAV Server, so select this. Then add the counter(s) you are interested in - in this example "Calls Per Second":

Perfmon

 

I found that in a stand-alone situation, the only counter that really shows anything is "Calls Per Second". But in a multi user system, this could well be very different - please share your experiences here.

 

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

 

Best regards


Lars Lohndorf-Larsen

Microsoft Dynamics UK


Microsoft Customer Service and Support (CSS) EMEA

Upgrading to Dynamics NAV 2009
18 May 09 03:10 PM | jvukovic | 3 Comments   

Upgrade procedure to Dynamics NAV 2009 is not very different from upgrade procedures we had in previous versions, but some differences do apply, depending on what we want to achieve with the upgrade.

First scenario is executables only upgrade, which is the same as traditional executables upgrade in NAV. That means upgrading classic NAV client to NAV 2009 version by opening previous database versions with new client, and selecting yes when prompted to convert database, without any object changes or data transfer. Or alternatively, creating a new database with NAV 2009 client, and restoring a backup of customer's database.

This will, as before, upgrade the version of executables running NAV to 2009 version (builds 6.0 and higher) and create necessary system tables, but this will not automatically open up for using new NAV 2009 functionality (like RTC client or Web Services). Running the first scenario is a mandatory part of any upgrade scenario, just as it was in previous versions.

Beware of few issues that can rise from this scenario, see the link below for description.

http://blogs.msdn.com/nav_developer/archive/2009/05/08/upgrading-older-databases-to-nav-2009-runtime.aspx

Another scenario is doing an executable upgrade that would open up for using Web services, but would not include any object upgrade or data transfer.

This is where 3-tier scenario enters stage and a Dynamics NAV server should be set up and connected to the database (this is the normal installation/setup process of the service). Dynamics NAV Web service should also be installed, see Dynamics NAV documentation for installation and setup of different components.

http://msdn.microsoft.com/en-us/library/dd301130.aspx

To be able to use Web Services after doing an upgrade of executables and setting up a NST and Web service, one must also import and populate web service form (810) from a NAV 2009 client. This will open up for exposing codeunits (and also pages, but at this stage, pages are not yet present in database).

To further enable using RTC, one should also import tables 9050-9060, these are cue tables used in role centers of RTC. If you are creating and running custom Role Center pages, remember to create a record in each table by specifying any value as primary key (or follow code examples from standard Role Center pages that will insert a record if table is empty). A record in any of these tables will be automatically inserted when using standard NAV Role Page (based on that table).

In addition, reports should be 'transformed' to add RDLC layer and forms should be transformed to pages. You can also run reports with classic engine form RTC (that is run classic NAV report in RTC), in which case no object upgrade is necessary for reports. Note though, to run reports with classic engine on RTC client, each machine running RTC client (and classic reports) needs to have Classic client installed as well.

Furthermore, Role Center pages should be created or standard ones imported from NAV 2009 client (pages in range 9000-9020). Finally, PROFILE table (table 2000000072) should be populated with standard (or custom) profiles, and role center pages tied to these.

Last, but not least, you must make sure the existing code is modified to run in both scenarios (see MSDN documentation on code considerations for NAV 2009). 

However, the job needed in this last scenario (specially transforming forms and reports) is not much different than using full database upgrade . In full upgrade version, objects in standard and custom version of NAV (version we are upgrading) would be merged with standard NAV 2009 objects to create custom NAV 2009 database. Note, all forms in standard NAV 2009 version are transformed to pages, so it is advisable to run Form transformation to create pages, once forms are merged to NAV 2009 object version. Also, one should 'upgrade' reports to add RDLC layer, once custom reports are merged to NAV 2009 version.

No data transfer would occur from W1 5.0 to W1 NAV 2009 version, as there are no changes to table structure from 5.0 version. Upgrading from earlier version would still imply data transfer using Upgrade Toolkit.

 

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

 

Best regards,


Jasminka Vukovic

Microsoft Dynamics NO


Microsoft Customer Service and Support (CSS) EMEA

 

 

 

 

 

Running an older databases in NAV 2009 runtime
08 May 09 03:31 PM | Lohndorf | 3 Comments   

It's quite normal to upgrade the runtime (executables) to newer versions while leaving the database (application) as it is. This will enable the new runtime features such as Web Services. Recently we have seen a number of questions about whether you can upgrade older databases to NAV 2009. As such, NAV 2009 is just another version, so the default answer would be that yes, you can do that.

Just remember a few additional things to be avare of:

1)  There is one potential issue: NAV 2009 has a change from older versions that comparing characters in a CASE structure is case sensitive. For example:

CodeVar := 'A';

CASE CodeVar OF

  'a':

    MESSAGE('xyz');

END;

In version 5 you will get the message. In NAV 2009 you won't. This has one specific implication in the standard application. Most matrix forms have a function called "DimCodeToOption". As an example is Form 113 Budget. The function has a parameter "DimCode" which in version 5 was type Code. This has to be changed to Text. Otherwise, the case sensitive comparison will fail, and Matrix forms will not show any data. So make this change in Form 113 and other forms, for example Form 554 "Analysis by Dimensions". And if you find other matrix forms have stopped working, then check this first.

2)  If you want to run RTC, then of course you would also have to import pages or run transformation first.

3)  Once you upgrade objects to NAV2009 runtime, you cannot use the objects in previous versions again, even if you export them and import into for example a NAV 5 database. NAV2009 adds new properties to objects which older versions will not be able to handle.

 

A number of customers have already made the change to NAV 2009 runtime, and to my knowledge no other issues have been reported regarding running the older database in a newer runtime. If you do find any issues not mentioned here, then please do add a comment below,

 

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

 

Best regards


Lars Lohndorf-Larsen

Microsoft Dynamics UK


Microsoft Customer Service and Support (CSS) EMEA

Dynamics NAV, customizing style sheets for export to MS Excel
22 April 09 05:48 PM | jvukovic | 0 Comments   

A while a go we posted a blog decribing how to make some basic customizations to style sheets used for export to Excel.

http://blogs.msdn.com/nav_developer/archive/2009/02/18/customizing-style-sheets-for-ms-excel.aspx

This is an update to that blog. You can download updated sample objects from the link below

In addition to changes described there (customizing font styles, conditional formatting and adding totals), this will allow adding some basic document properties, choosing to display zero decimal fields as blank, and adding header and footer to the exported document. In addition, code changes added here would allow user to run send to excel, apply described customizations directly in exported document, then import the document to automatically generate customized style sheet. The objects are attached.

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

All feedback regarding issues or suggestion to this post are very welcome!  

Jasminka Vukovic, Lars Lohndorf-Larsen

Microsoft Dynamics NO


Microsoft Customer Service and Support (CSS) EMEA

 

 

Filed under: ,
Attachment(s): xlt.fob
Beware the SQL Index property on NAV 5.0 SP1
10 April 09 02:16 PM | lalake | 3 Comments   

The discussion of the changes starting with Microsoft Dynamics NAV version 5 regarding the use of Dynamic cursors has already been addressed in the article titled "Cursor Types" on the SE Blog - http://blogs.msdn.com/microsoft_dynamics_nav_sustained_engineering/

However, we are seeing more and more cases where the use of the SQL Index property in NAV 5.0 SP1 is causing performance issues, so the purpose of this blog is to explain in more detail from an application perspective how this property can affect performance.

From version 5.0 we are using Dynamic cursors, which means that SQL server will tend to choose an index that fits the ORDER BY clause more than the WHERE clause. This is not a problem as long as there is no conflict between the ORDER BY and the WHERE clause. This is where the SQL Index property comes in.

SQL server should be able to choose the optimal index IF we create an index which matches the ORDER BY or the filter/range perfectly. NAV constructs the ORDER BY based on the NAV Key specification not the SQL Index specification. If a SQL Index value is specified on the NAV key and the fields do not exactly match the fields and the order in which they were specified in the Key, then there could be a conflict between the ORDER BY and the WHERE clauses.

How does the issue present itself in the application? These are just a couple of examples we have seen of the impact the SQL Index specification can have on the application…

Poor performance on large tables like Ledger Entry tables, if a user selects Sort on the form and changes from the primary key to a secondary key which has a SQL Index specification.

Using the RunFormView and RunFormLink property of a form…If the RunFormView is set to a non-primary key,  SQL might not choose the first key matching the RunFormView if that key has a SQL Index specification. Depending on the keys defined on the table, there may not be another adequate key available, so a suboptimal index may be used. The ORDER BY may no longer match the WHERE clause (RunFormLink), resulting in very poor performance loading the form.

Performance problems when SETCURRENTKEY/SETRANGE is used in code and the key specified has a SQL Index specification that does not match the key or the filters entered (WHERE clause).

************

We are seeing issues mainly with customers who have upgraded to 5.0 SP1 from 5.0, because there were values specified for SQL Index in many tables in the base product in 5.0. Some other customers on pre-5.0 versions might also have issues if someone has done performance tuning on their database. In earlier version of NAV, SQL Index was used to improve performance in certain scenarios. 

The recommendation is that the use of the SQL Index specification should be limited to very specific situations where thorough testing shows performance improvement. In the vast majority of scenarios, SQL will make the correct choice of Index, so the SQL Index specification is not needed and can actually cause poor performance.

For more information on identifying these problematic queries, please see the SE Blog post mentioned at the top of this article.

Laura K. Lake

Microsoft Dynamics NA


Microsoft Customer Service and Support (CSS) North America

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

Filed under: ,
RIM Tool on NAV 2009
03 April 09 07:33 PM | lalake | 0 Comments   

With the release of 5.0 SP1, a new data type conversion routine was introduced with codeunit 5302 - Outlook Synch. Type Conversion. There are several known issues with data migration due to these changes.

The previously published blog for 5.0 SP1 contains a change log of some code suggestions and workarounds for the more common and/or critical issues. 

This blog addresses many of the same issues in NAV 2009. While some corrections were made between the release of 5.0 SP1 and 2009, not all fixes made it into the RTM release of 2009. The following change log can be applied to the 2009 objects.


This change log applies to 2009 RTM application objects ONLY.

Issues addressed by the change log:

1) Overflow on type conversion from Text to Text in Form 8626 when a text field larger than 100 chars is imported.
2) Error on import of fields beginning with a number -1099 Code, etc.- The call to member selectSingleNode failed. msxml6.dll returned the
   following message: Expression must evaluate to a node-set.
3) Imported dates are blank after migration data is applied.
4) Negative decimal values are converted incorrectly, resulting in changed values.
5) Expected token 'EOF' found '$'. Error on fields with $ symbol


Changes are labeled with the associated number above.

 

Form 8626 Migration Records

---------------------------

Before:

CODE

  {

    VAR

      MatrixColumnCaptions@1000 : ARRAY [100] OF Text[100];

      MigrationData@1001 : Record 8615;

      MatrixCellData@1002 : ARRAY [100] OF Text[100];

      MigrationColumnField@1004 : ARRAY [100] OF Integer;

      MatrixColumnOrdinal@1003 : Integer;

      FormCaption@1005 : Text[1024];

      TableNo@1006 : Integer;

      Text001@1007 : TextConst 'ENU=%1 value ''%2'' does not exist.';

 

After:

CODE

  {

    VAR

      MatrixColumnCaptions@1000 : ARRAY [100] OF Text[100];

      MigrationData@1001 : Record 8615;

      MatrixCellData@1002 : ARRAY [100] OF Text[250];                    // changed #1 - changed from Text[100] to Text[250]

      MigrationColumnField@1004 : ARRAY [100] OF Integer;

      MatrixColumnOrdinal@1003 : Integer;

      FormCaption@1005 : Text[1024];

      TableNo@1006 : Integer;

      Text001@1007 : TextConst 'ENU=%1 value ''%2'' does not exist.';

 

 

* XMLport 8610 - Setup DataSchema

---------------------------------

...

NameIn := DELCHR(NameIn,'=','Ù''`');

NameIn := DELCHR(CONVERTSTR(NameIn,'<>,./\+-&()%','            '),'=',' ');

NameIn := DELCHR(NameIn,'=',' ');

 

EXIT(NameIn);

...

 

 

After:

...

NameIn := DELCHR(NameIn,'=','Ù''`');

NameIn := DELCHR(CONVERTSTR(NameIn,'<>,./\+-&()%$','             '),'=',' ');  // Changed - added $ symbol and one additional space between single quotes #5

NameIn := DELCHR(NameIn,'=',' ');

 

IF (NameIn[1] >= '0') AND (NameIn[1] <= '9') THEN                                                      // Added #2

  NameIn := '_' + NameIn;                                                                                                                                     // Added #2

 

EXIT(NameIn);

 

 

 

* Codeunit 8611\Function FieldNodeExists ...

--------------------------------------------

Before:

 

FieldNode := RecordNode.selectSingleNode(FieldNodeName);

 

IF NOT ISCLEAR(FieldNode) THEN

  EXIT(TRUE);

 

After:

 

IF (FieldNodeName[1] >= '0') AND (FieldNodeName[1] <= '9') THEN                                       // Added #2

  FieldNodeName := '_' + FieldNodeName;                                                                                                                      // Added #2

 

FieldNode := RecordNode.selectSingleNode(FieldNodeName);

 

IF NOT ISCLEAR(FieldNode) THEN

  EXIT(TRUE);

 

 

* Codeunit 8611, Function GetElementName

----------------------------------------

Before:

 

...

NameIn := DELCHR(NameIn,'=','Ù''`');

NameIn := DELCHR(CONVERTSTR(NameIn,'<>,./\+-&()%','            '),'=',' ');

NameIn := DELCHR(NameIn,'=',' ');

 

EXIT(NameIn);

...

 

 

After:

...

NameIn := DELCHR(NameIn,'=','Ù''`');

NameIn := DELCHR(CONVERTSTR(NameIn,'<>,./\+-&()%$','             '),'=',' ');  //Changed - added $ symbol and one additional space between single quotes #5

NameIn := DELCHR(NameIn,'=',' ');

 

IF (NameIn[1] >= '0') AND (NameIn[1] <= '9') THEN                                                      // Added #2

  NameIn := '_' + NameIn;                                                                                                                                     // Added #2

 

EXIT(NameIn);

 

 

* Codeunit 8611, Function InsertRecordWithKeyFields

-----------------------------------------------------

Before:

 

VAR

      MatrixData@1001 : Record 8615;

      MigrationTableField@1007 : Record 8616;

      OSynchTypeConversion@1008 : Codeunit 5302;

      RecRef1@1006 : RecordRef;

      KeyRef@1003 : KeyRef;

      FieldRef@1004 : FieldRef;

      KeyFieldCount@1005 : Integer;

      ToValidate@1009 : Boolean;

 

    BEGIN

      MatrixData.SETRANGE(TableID,MatrixRecord.TableID);

      MatrixData.SETRANGE("No.",MatrixRecord."No.");

 

      KeyRef := RecRef.KEYINDEX(1);

      FOR KeyFieldCount := 1 TO KeyRef.FIELDCOUNT DO BEGIN

        FieldRef := KeyRef.FIELDINDEX(KeyFieldCount);

        ValidationFieldID := FieldRef.NUMBER;

        MatrixData.SETRANGE(FieldID,FieldRef.NUMBER);

        IF MatrixData.FIND('-') THEN BEGIN

          MigrationTableField.GET(MatrixData.TableID,MatrixData.FieldID);

          ToValidate := MigrationTableField.Validate AND NOT TestRelation(FieldRef);

          OSynchTypeConversion.EvaluateTextToFieldRef(MatrixData.Value,FieldRef,ToValidate);        

        END ELSE

          IF KeyRef.FIELDCOUNT <> 1 THEN BEGIN

            ERROR(STRSUBSTNO(Text000,FieldRef.NAME,RecRef.NAME + ':' + FORMAT(MatrixData."No.")));

          END

      END;

 

      RecRef1 := RecRef.DUPLICATE;

 

      IF RecRef1.FIND('=') THEN BEGIN

        RecRef := RecRef1;

        EXIT

      END;

 

      RecRef.INSERT(NOT CompanySetupRun);

    END;

 

 

After:

 

VAR

      MatrixData@1001 : Record 8615;

      MigrationTableField@1007 : Record 8616;

      OSynchTypeConversion@1008 : Codeunit 5302;

      RecRef1@1006 : RecordRef;

      KeyRef@1003 : KeyRef;

      FieldRef@1004 : FieldRef;

      KeyFieldCount@1005 : Integer;

      ToValidate@1009 : Boolean;

      Field@1010 : Record 2000000041;                            // Added #3

      Datevalue@1011 : Date;                                     // Added #3

 

   BEGIN

      MatrixData.SETRANGE(TableID,MatrixRecord.TableID);

      MatrixData.SETRANGE("No.",MatrixRecord."No.");

 

      KeyRef := RecRef.KEYINDEX(1);

      FOR KeyFieldCount := 1 TO KeyRef.FIELDCOUNT DO BEGIN

        FieldRef := KeyRef.FIELDINDEX(KeyFieldCount);

        ValidationFieldID := FieldRef.NUMBER;

        MatrixData.SETRANGE(FieldID,FieldRef.NUMBER);

        IF MatrixData.FIND('-') THEN BEGIN

          MigrationTableField.GET(MatrixData.TableID,MatrixData.FieldID);

          ToValidate := MigrationTableField.Validate AND NOT TestRelation(FieldRef);

          //OSynchTypeConversion.EvaluateTextToFieldRef(MatrixData.Value,FieldRef,ToValidate);         //  removed #3

 

          Field.GET(RecRef.NUMBER, FieldRef.NUMBER);                                                   //  Added #3

          IF Field.Type <> Field.Type::Date THEN                                                       //  Added #3

            OSynchTypeConversion.EvaluateTextToFieldRef(MatrixData.Value,FieldRef,ToValidate)          //  Added #3

          ELSE BEGIN                                                                                   //  Added #3

            EVALUATE(Datevalue, MatrixData.Value);                                                     //  Added #3

            FieldRef.VALUE := Datevalue;                                                               //  Added #3

          END;                                                                                         //  Added #3

 

        END ELSE

          IF KeyRef.FIELDCOUNT <> 1 THEN BEGIN

            ERROR(STRSUBSTNO(Text000,FieldRef.NAME,RecRef.NAME + ':' + FORMAT(MatrixData."No.")));

          END

      END;

 

      RecRef1 := RecRef.DUPLICATE;

 

      IF RecRef1.FIND('=') THEN BEGIN

        RecRef := RecRef1;

        EXIT

      END;

 

      RecRef.INSERT(NOT CompanySetupRun);

    END;

 

 

 

 

* Codeunit 8611, Function ModifyRecordWithOtherFields

-----------------------------------------------------

Before:

 

VAR

      MatrixData@1002 : Record 8615;

      MigrationTableField@1000 : Record 8616;

      Question@1003 : Record 8612;

      Field@1007 : Record 2000000041;

      MigrationTable@1009 : Record 8613;

      DataTemplateHeader@1011 : Record 8618;

      QuestionnaireMgt@1006 : Codeunit 8610;

      TemplateMgt@1012 : Codeunit 8612;

      OSynchTypeConversion@1014 : Codeunit 5302;

      FieldRef@1001 : FieldRef;

      OptionInt@1008 : Integer;

      DateFormula@1010 : DateFormula;

      ToValidate@1013 : Boolean;

 

After:

 

 VAR

      MatrixData@1002 : Record 8615;

      MigrationTableField@1000 : Record 8616;

      Question@1003 : Record 8612;

      Field@1007 : Record 2000000041;

      MigrationTable@1009 : Record 8613;

      DataTemplateHeader@1011 : Record 8618;

      QuestionnaireMgt@1006 : Codeunit 8610;

      TemplateMgt@1012 : Codeunit 8612;

      OSynchTypeConversion@1014 : Codeunit 5302;

      FieldRef@1001 : FieldRef;

      OptionInt@1008 : Integer;

      DateFormula@1010 : DateFormula;

      ToValidate@1013 : Boolean;

      DateValue@1500000 : Date;                   // Added #3

 

Before:

 

 

    IF MigrationTableField.FIND('-') THEN

      IF NOT IsKeyField(MigrationTableField.TableID,MigrationTableField.FieldID) THEN BEGIN

        FieldRef := RecRef.FIELD(MatrixData.FieldID);

        IF CompanySetupRun THEN

          ToValidate:= FALSE

        ELSE

          ToValidate := MigrationTableField.Validate AND NOT TestRelation(FieldRef);

        OSynchTypeConversion.EvaluateTextToFieldRef(MatrixData.Value,FieldRef,ToValidate)

      END;

      IF DataTemplateHeader.GET(MigrationTable."Data Template") THEN

        TemplateMgt.UpdateRecord(DataTemplateHeader,RecRef);

 

After:

 

    IF MigrationTableField.FIND('-') THEN

      IF NOT IsKeyField(MigrationTableField.TableID,MigrationTableField.FieldID) THEN BEGIN

        FieldRef := RecRef.FIELD(MatrixData.FieldID);

        IF CompanySetupRun THEN

          ToValidate:= FALSE

        ELSE

          ToValidate := MigrationTableField.Validate AND NOT TestRelation(FieldRef);

 

        //OSynchTypeConversion.EvaluateTextToFieldRef(MatrixData.Value,FieldRef,ToValidate)          // removed #3

 

        Field.GET(RecRef.NUMBER, FieldRef.NUMBER);                                                   // Added #3

        IF Field.Type <> Field.Type::Date THEN                                                       // Added #3

          OSynchTypeConversion.EvaluateTextToFieldRef(MatrixData.Value,FieldRef,ToValidate)          // Added #3

        ELSE BEGIN                                                                                   // Added #3

          EVALUATE(DateValue, MatrixData.Value);                                                     // Added #3

          FieldRef.VALUE := DateValue;                                                               // Added #3

        END;                                                                                         // Added #3

 

      END;

      IF DataTemplateHeader.GET(MigrationTable."Data Template") THEN

        TemplateMgt.UpdateRecord(DataTemplateHeader,RecRef);

 

 

 

* Codeunit 5302, Function TextToDecimal

----------------------------------------

Before:

 

VAR

      PartArray@1003 : ARRAY [2] OF Text[250];

      IntegeralPart@1001 : Integer;

      FractionalPart@1002 : Integer;

 

 

After:

 

VAR

      PartArray@1003 : ARRAY [2] OF Text[250];

      IntegeralPart@1001 : Integer;

      FractionalPart@1002 : Integer;

      Sign@1005 : Integer;                   //add new local variable #4

 

Before:

 

 

DecVar := IntegeralPart + (FractionalPart / POWER(10,STRLEN(PartArray[2])));    

 

 

After:

 

 

IF STRPOS(InputText,'-') = 0 THEN     //added #4

  Sign := 1                           //added #4

ELSE                                  //added #4

  Sign := -1;                         //added #4

DecVar := (Sign * (ABS(IntegeralPart) + (FractionalPart / POWER(10,STRLEN(PartArray[2])))));  //changed #4

 

Laura K. Lake

Microsoft Dynamics NA


Microsoft Customer Service and Support (CSS) North America

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. 

Filed under:
The physical location of .net components
12 March 09 08:50 AM | Lohndorf | 0 Comments   

The virtual table 2000000046 "Automation Server" shows you the physical location of the automation servers (.dll file). But a .net component is not an automation server, so is not listed here. One of the main benefits of .net is exactly to be able to copy and paste files, keep installations simple, and maintain multiple versions. But registering .net components do a lot to hide this simplicity. Windows Explorer also hides the actual structure of the registered .net components.

 To see the real structure, use a command prompt instead. Go to the folder c:\windows\assembly. Windows Explorer Will just list your .net components. But go to the same location from a command prompt, and it is different:

The folder contains sub folders like GAC, GAC_32 and GAC_MSIL. When the .net framework looks for a .net component, it goes into one of these folders - typically GAC_MSIL, but it depends on which version of .net framework is installed.

The next thing the .net framework does when locating a .net component, is to go into the folder with the same name. This folder then contains a folder for each version of this component. If .net is looking for a specific version which does not exist, then if you create a new folder here with this version, then .net will look in this folder. Finally, here you have the actual .net component (dll file) which the .net framework will use.

 

Lars Lohndorf-Larsen

Microsoft Dynamics UK

Microsoft Customer Service and Support (CSS) EMEA

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Filed under:
Report Headers
24 February 09 09:07 PM | Lohndorf | 0 Comments   

In classic reports, adding a header to your report is as easy as just copying the Header section from an existing one.

With reports for RTC you need to do a bit of manual work to get your report header. A standard header contains the following information:

Report Name

Company Name

Time and date (=Globals!ExecutionTime)

Page Caption and Number (=Globals!PageNumber)

User ID (=User!UserID)

Time and Date, Page Number and User ID are automatically defined as global variables in Visual Studio report designer. All you need to do, is: Add a TextBox, right click on it and select "Expression...", then select from the Globals-Menu:

Globals

The other fields (Report Name, Company Name and Page Caption) are labels, and have to be added following the steps described here:

Labels in NAV2009 Report Design

So these are the two ways (Globals and Labels) that you have to add information to your report headers as illustrated here:

 

HeaderBlog

 

 

 

Lars Lohndorf-Larsen

Microsoft Dynamics UK

Microsoft Customer Service and Support (CSS) EMEA

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Labels in NAV2009 Report Design
24 February 09 10:40 AM | Lohndorf | 3 Comments   

When adding fields to a report, the caption is typically added automatically or with a bit of drag and drop from the DataSet in VS Report Layout. But if you want to add additional labels, for example Report Name in the header, then there are a few more steps you must follow.

Of course, you can just add a new TextBox in VS Layout, and type in the value you want to show. This is simple but will not give you Multi Language. Using a label from the classic report design gives you Multi language, but is a bit more complicated. This is what you need to do:


As usual, before you can use it in the layout you must add the label to the report sections, and then specify the caption you want to display. In this case, make sure to also specify a name in the DataSetFieldName-property of the label. For this example, let’s call it Report_Label.
To get the label value (Caption) into the layout, you must first add it to the Table on the Body-part of the layout. Note: It must be part of the table, and not in a TextBox outside of the table. The name of the cell will default to the DataSetFieldName you specified (Report_Label). And the value must be =Fields!Report_Label.Value. You get this value automatically if you drag it from the Data Set into a detail-section of the table. The caption is only here to be available from the header part of the report, so you can set the Visible-property to No.

Finally you can get the label from the table and add it to a header-section in the report layout: Add a new TextBox, then name it something unique, for example Report_Label1, and set Expression = =ReportItems!Report_Label.Value. Note that "Report_Label" refers to the cell you added above, not directly to the label on the sections.

This picture shows the steps needed to get the label to show in the header:

AddLabel

 

 

 

Lars Lohndorf-Larsen

Microsoft Dynamics UK

Microsoft Customer Service and Support (CSS) EMEA

These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use.

Filed under: ,
More Posts Next page »
Page view tracker