Quickly create docker container for Dynamics 365 Business Central

If you work with Dynamics 365 Business Central as a developer then you more than likely know about the excellent BContainerHelper used to download artifacts and create containers.

Wanting a quick way to utilize this, I created my own module than leveraged this – well today it got an overdue update.

Mine can be found here, installing it is a mere command away

Install-Module -Name bc365-create-container

Using it, simple, in its simplest form, the following will get you going

New-BC365Container -ContainerName *name* -Auth NavUserPassword

Simply specify your container name, then follow through the prompts to select type (OnPrem/Sandbox), language version etc and it will do the work for you.

In the recent update however, I’ve added commands to get the preview and the insider builds (if you’re a Partner like us, and have access to them).

For the preview, just add -Preview $true, so

New-BC365Container -ContainerName *name* -Auth NavUserPassword -Preview $true

For insider builds, it would be

New-BC365Container -ContainerName *name* -Auth NavUserPassword -Insider $true

Simple as that. As a final note, when my containers have been created I always like to run the following to make sure the containers don’t auto start with windows each time

docker update *name* --restart=no

ASPNET Core – asp-append-version for remote images

Solving the asp-append-version problem with remote files in aspnet core with a custom TagHelper

I recently came across an issue where the site wasn’t refreshing images that the customer has updated even though they had changed them. Obviously browser caching was the original thought – which it was.

Some background, the is hosted on Azure and provided a back end portal for customers (B2B) to be able to order products via the website, these in turn are then pushed to the customers Microsoft Dynamics NAV instance (also known now as Microsoft Dynamics 365 Business Central). This has been developed my my Consultancy company in the UK – TAIG Solutions

In this instance the product images are actually stored seperately to the Azure site – they are hosted on the customers own on-prem server this makes it easier for the designers to update the images, they can just overwrite the image with a new one…. and here lies the problem…

One of the tools we have available is the asp-append-version tag which, when applied to the img tag basically adds a hash value of the file onto the end of the url, so for example

<img src="yourdomain.com/image.png?v=1234567890" />

The ?v=1234567890 being key, normally each time the file is served a hash is generated based on the file, so if the image changes, so does the hash and the browser will force a refresh of the image and not use the cached image.

However, this doesn’t work with files that are stored remotely, as we found out. There are a couple of solutions to this problem, but the easier we chose was to use the same versioning, but generate our own hash value – but not based on the file, we’d use the date (in this case they change the images so often we decided to do it on a day-by-day basis, but you could do something not as regular).

So how do we do this, we create our own TagHelper of course.

In your project, create a new class with the following code:

using Microsoft.AspNetCore.Razor.TagHelpers;
using System;

namespace TAIG.Solutions.WebPortal.TagHelpers
{
    [HtmlTargetElement("static-image-file", TagStructure = TagStructure.WithoutEndTag)]
    public class StaticImageTagHelper : TagHelper
    {
        // Can be passed via <static-image-file image-src="..." />. 
        // PascalCase gets translated into kebab-case.
        public string ImageSrc { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "img";    // Replaces <static-image-file> with <a> tag

            // create a version
            string version = DateTime.Now.ToString("yyyyMMdd"); // caching for a day - could use a setting in future?

            // generate url
            string url = $"{ImageSrc}?v={version}";

            output.Attributes.SetAttribute("src", url);
        }
    }
}

Now, in your _ViewImports.cshtml file we need to add the following

@addTagHelper TAIG.Solutions.WebPortal.TagHelpers.StaticImageTagHelper, TAIG.Solutions.WebPortal

Obviously if you changes the class name you need to adjust it, and make sure you change the namespace to the one you are using.

The result now, is we can now use our own tag instead of image, so instead of

<img src="yourdomain.com/image.png?v=1234567890" />

We can now use

<static-image-file image-src="yourdomain.com/image.png" />

Now code code will add a ?v= along with a date value which changes each day.

Problem solved. Yes, if they change an image during the day then, if you have viewed the page already you would have to wait until the following day for it to change, but that is good enough for us.

The Service Principal Name (Delegation) configuration has been set incorrectly – Microsoft Dynamics NAV 2017

The Service Principal Name (Delegation) configuration has been set incorrectly using Microsoft Dynamics NAV 2017

I’ve recently been working on a Microsoft Dynamics NAV 2017 installation, to which I was setting up the web client which hadn’t been used before. Now I’ve done many of these setups and they all worked fine, but this one..

Well I got the following error:

Error accessing Website Microsoft Dynamics NAV 2017 Web Client
Raw Url: /live/WebClient/SignIn.aspx?ReturnUrl=%2flive%2fWebClient%2f
Url: https://localhost/live/WebClient/SignIn.aspx?ReturnUrl=%2flive%2fWebClient%2f
Type: Microsoft.Dynamics.Nav.Types.NavSecurityNegotiationException
Message: The Service Principal Name (Delegation) configuration has been set incorrectly. Server connect URL: “net.tcp://localhost:7046/live/Service”. SPN Identity: “DynamicsNAV/localhost:7046”

There was plenty more in the event log, but not of use here. At first I thought it was an SPN issue, but turns out to just need a small change on IIS.

To fix this, open IIS, then expand the server. Now go into Application Pools.
Open Advanced Settings on the Microsoft Dynamics NAV 2017 Web Client entry, then scroll down and find Load User Profile.

Change this to False.

Restart IIS, now it should work.

Enjoy.

Dynamics N.A.V and Homogenous AppDomain Error

Homogenous AppDomain Error within Microsoft Dynamics N.A.V.

What an earth I hear you ask.. well that’s what I thought too.

Background

So I have doing some development, basically I have an incoming Json feed from a Shopify Web-hook, my initial thought was to create a C# Object which I could reference as a DotNet variable in Dynamics N.A.V. the using Newtonsoft deserialize into this object.. easy.. and to be honest it was…

Until that is I got sent a request from Shopify that had an unexpected reference. Originally when I built the object class I used the samples provided by Shopify, turns out though that the sample doesn’t contain everything, so the first time a shipment notification came through that contained an order with a refund…. bam! It broke.

My original object didn’t have a Refunds section, so when I tried to deserialize it, well it didn’t know what to do.

So… I thought I would simply use a dynamic objectthen just map info I actually needed, ignoring what I didn’t, then pass this back into Dynamics N.A.V.

I added an overloaded constructor to my c# class which now looked like;

///
<summary>
/// Ctor +1
/// </summary>
/// <param name="jsonText"></param>
public FulfillmentNotice (string jsonText)
{
    dynamic t = JsonConvert.DeserializeObject<dynamic>(jsonText);

    id = t.id;
    order_number = t.order_number;
    billing_address = t.billing_address.ToObject<Address>();
    shipping_address = t.shipping_address.ToObject<Address>();

    payment_gateway_names = new List<string>();
    foreach (string s in t.payment_gateway_names)
        payment_gateway_names.Add(s);

    // init list
    shipping_lines = new List<Shipping_Lines>();
    foreach (dynamic shipline in t.shipping_lines)
        shipping_lines.Add(shipline.ToObject<Shipping_Lines>());

    // init list
    fulfillments = new List<Fulfillment>();
    foreach (dynamic fulLine in t.fulfillments)
        fulfillments.Add(fulLine.ToObject<Fulfillment>());

    // init list
    discount_codes = new List<Discount_Codes>();
    foreach (dynamic disLine in t.discount_codes)
        discount_codes.Add(disLine.ToObject<Discount_Codes>());

}

So now I call the new constructor passing in the Json text, worked nicely, now it completely ignores anything unexpected, great!

Next I altered my codeunit within Dynamics N.A.V. to use the new code, complied then ran the function, unfortunately I got..

A call to ShopifyFulfillmentReceiver.Library.FulfillmentNotice failed with this message: Dynamic operations can only be performed in homogenous AppDomain.

Well I wasn’t really expecting that, though I thought I had seen it before.

The Solution

So what do you need to do? You need to remove/change the following file in the Microsoft.Dynamics.Nav.Server.exe.config file. Find the section <runtime> and you should see a line <NetFx40_LegacySecurityPolicy enabled=”false”/> and change it to false, restart the NST and it should work –  if the section exist, put the below withing the <configuration> section

<runtime>
<NetFx40_LegacySecurityPolicy enabled="false"/>
</runtime>

As always, you should check it on a dev instance before rolling out to a live instance, making sure it doesn’t affect anything!