Stupid error on a friday :)

Today I upgraded a virtual machine running NAV2015 from Update 5 to Update 6. Not a big deal, but during the process I managed to delete the CustomSettings.config file – Stupid mistake on my part.

This file holds the entire configuration for the NAV Service Tier, from authentication of client to SQL Server connection and more.

But the real question I’m left with is:

Why does NAV keep its setting files under C:\Program Files ?

With the introduction of Longhorn (Windows Vista/Windows Server 2008) and UAC – Writing inside c:\Program Files became a elevated operation, so only users with Administrator rights could write there. After that, most programs began to use c:\ProgramData or storing setup and data under c:\Users. There is even a blog from Microsoft on the subject.

Funny enough, SQL Server still defaults its location for DATA under c:\Program files unless changed during the install. They properly keept it there for historic reasons – It has been that way since SQL Server 6.5.

But NAV does not have that history restriction, so from my perspective, this can be added to Luc’s  Lets clean up NAV list.

Anyway, that was my friday rant 🙂

User documentation of a NAV solution

In this series of articles I will explain a alternative method of handling user documentation for Microsoft Dynamics NAV 2015 code.

In E Foqus we use this for our ISV product Foqus Finance, but it can be used for any NAV solution, ranging from a small customer modification to huge ISV solutions (as Foqus Finance)

We have tried to solved a series of challenges with documentation:

First challenge: Documentation is dead the minute you’re finish writing it. Code changes, customers want it work differently, change requests keeps popping up. And the documentation (if any) stays at the initial level

Second challenge: Documentation is kept in documents (Word/PDF) sitting on local drives, attached to email, stored on file shares, often in multiple versions without any clear version strategy.

Third challenge: Customer want F1 help, and this has historical been an nightmare to create with NAV – from compiling CHM files with 3rd party tools to distribute files to clients.

Fourth challenge: New formats comes along all the time, creating an ebook with the help would be a very modern thing to do.

Read on for our solution to all this:

Step 1 – Organizing the input text
Step 2 – Getting structure into our documentation
Step 3 – Graphical Layout
Step 4 – Updating the Help Server Table Of Content (ToC.XML)
Step 5 – Editing and storing help text with NAV Code
Step 6 – Running the whole thing

Download the current version of the help toolkit:

EFoqusHelpToolkit 0.03

Further development:

Step 7 – Producing automated screenshots from NAV

Update the NAV2015 ToC.XML

The ToC.XML is a simple recursive structure with entries like this:

<?xml version="1.0" encoding="utf-8"?>
<Node Name="DynamicsHelp" DisplayName="Help" Page="conGettingStarted.htm">
    <Node Name="TechRef" DisplayName="Technical Reference" Page="conTechnicalReference.htm">
      <Node Name="CSIDERef" DisplayName="C/SIDE Reference Guide" Page="conCSIDEReferenceGuide.htm" />
      <Node Name="DevEnvCmds" DisplayName="Development Environment Commands" Page="conDevelopmentEnvironmentCommands.htm" />
      <Node Name="CSIDEwindows" DisplayName="Windows Overview" Page="conWindowOverviews.htm" />
    <Node Name="Upgrade" DisplayName="Upgrading to Microsoft Dynamics NAV 2015" Page="oriUpgradingToNAVCrete.htm">
      <Node Name="MigratingToMultitenancy" DisplayName="Migrating to Multitenancy" Page="conMigratingTenantDatabases.htm" />

Just a name, a title and a page, and that looks very similar to the structure we already have in place from the manual. So we do here, is run through our own Structure.XML, and inserts matching entries into the ToC.

This is the main piece of code that will generate the html files, and update the ToC at the same time:

public bool GenerateAllContentAsHtml()
            XDocument TOC = XDocument.Load(ConfigurationManager.AppSettings["input-toc"]);

            XElement root = (from xml2 in TOC.Descendants("Node")
                             where xml2.Attribute("Name").Value == ConfigurationManager.AppSettings["projectname"]
                             select xml2).FirstOrDefault();
            if (root == null)
                root = GetNode(ConfigurationManager.AppSettings["projectname"], Data.manual.Title, ConfigurationManager.AppSettings["projectname"] + ".htm");
            root.Nodes().Remove(); // If we already have our stuff in this TOC remove it first

            StringBuilder ChapterList = new StringBuilder();
            foreach (var chapter in Data.manual.Chapters)
                string str = "<a href=\"" + ConfigurationManager.AppSettings["projectname"] + "_" + chapter.No + ".htm\" xmlns=\"\">";
                str += chapter.Title + "</a><br>";

            Article preface = Data.Articles.Find(m => m.ID == Data.manual.Preface.ID);
            if (preface == null)
                preface = new Article()
                    ID = Data.manual.Preface.ID,
                    Text = "TODO: Article " + Data.manual.Preface.ID,
                    Title = "TODO: Article Caption " + Data.manual.Preface.ID
            StringBuilder topic = new StringBuilder(File.ReadAllText(ConfigurationManager.AppSettings["helppage-html"]));
            topic.Replace("$1$", preface.Title);
            topic.Replace("$1$", preface.Title);
            topic.Replace("$2$", ConvertMarkdown(preface.Text, "html") + ChapterList);
                ConfigurationManager.AppSettings["output-path-helpserver"] + @"\" +
                ConfigurationManager.AppSettings["projectname"] + ".htm", topic.ToString());

            return false;