Using Web Services to Manage the Dynamics NAV Management Portal Programmatically

In this blog post, we will explain how to access and work with the Dynamics NAV Management Portal via web services.
The Dynamics NAV Management Portal has a full set of web services that will allow you to create applications, versions, services, tenants, backups (and much more!) programmatically. We will provide you with some basics about Dynamics NAV web services and illustrate how to use them by creating an example application, application version, and application service. We will use Windows PowerShell for the examples, but it is almost the same with other languages like C#.
If you already know how Dynamics NAV Web services work, how to login into them, or you just want to take a look at the code, you can jump to the Creating an Application using PowerShell section. If after reading that section, you are a bit lost, then you are always welcome to come back!
All the code is gathered together at the end, so if you are looking for a specific detail, you can go there directly.

As you may have already figured out by now, the Dynamics NAV Management Portal looks like a typical Dynamics NAV client application. This is because it has been made using the Dynamics NAV Development Environment! This means that a lot of the things we will see here apply to Dynamics NAV web services, independent of Dynamics NAV Management Portal.

The portal exposes SOAP web services for all the operations that you can do in the portal manually. It should be noted that OData web service are not exposed. You can view a list of the available SOAP web service in Web Services page. To open this page, type Web Services in the Search field, and then choosing the relevant link. The Web Services window lists a URL to manage each entity.

For example, if you want to manage tenants, you can access the equivalent of this URL:
https://corfuservicedemo44y.cloudapp.net:7047/NAV/WS/Fabrikam/Page/ApplicationTenant?tenant=fabrikam

If you want to manage Tenant Users, you can access the equivalent of this URL:
https://corfuservicedemo44y.cloudapp.net:7047/NAV/WS/Fabrikam/Page/ApplicationTenantUser?tenant=fabrikam

By default in Dynamics NAV, web service URLs have the following format:
https://[partnerURL]:7047/[server_instance]/WS/{Company]/[Page|Codeunit]/[WebServiceName]?tenant=[tenant]
Tip:
You can also see a list of web services by opening the following URL directly in the browser: https://[partnerURL]:7047/NAV/WS/[Company Name]/Services. This requires that you create a web service access key first. See the next section for instructions.

How can I log on to the Dynamics NAV Management Portal Web Services?

If you try to access one of those addresses for the first time, you will probably find out that your O365 credentials don’t work, and you will get a message that the page cannot be displayed.
To log in into the web services, you need to create a Web Service Access Key, which you will use asuse as your password for accessing the web services. To create a Web Service Access Key in the portal, choose Web Service Access, and then choose Generate.
A key is automatically generated. Copy the key because you will need it later.
Note:
At any point in time, there can be only one key enabled for each user. This means that if you generate a new key, the old one will stop working immediately. Keys are passwords, so it is a good idea to give them an expiration date.
Now, we are ready to log on to the web services. Let’s start with the Application web service.

  1. Go back to the Web Services page, and choose the URL for the Application service.
  2. In the User name field, enter the user name in the format tenant\user name
    tenant is the tenant name for your portal as it appears in the portal’s URL after the tenant=  parameter.
    User name is the name that is assigned to your Dynamics Managment Portal  account by Microsoft. You can see your user name by choosing the icon in the upper right corner of the portal.
  3. In the Password field, enter the Web Service Access Key that you generated previously.

Bingo! A huge, hard-to-read XML document appears !

This XML is called WSDL (Web service Description Language). You can read more information about WSDL in the MSDN Library at Understanding WSDL. But in simple terms, it is a contract that describes what a web service is capable of doing. In our case, the WDSL file defines a type (Application), its properties (such as Name, Description, etc.) and methods or actions (such as Create, ReadMultiple, ToggleOffice365Authenticationregistration, etc.).

As you might have noticed, these properties and actions are the same that you can find on the Application page in the portal:

Installing Windows PowerShell and the Microsoft Azure PowerShell Module

Performing the work described in the following sections requires the use of Windows PowerShell and the Azure PowerShell. For more information about the installation of these components, see:

Connecting to Web Services using Windows PowerShell

To access SOAP web services by using PowerShell, you can use the New-WebServiceProxy Cmdlet as follows:

$link = "https://navmanagementportal.navcloudapptest.net:7047/NAV/WS/Fabrikam/Page/Application?tenant=fabrikam" $credential = Get-Credential $applicationWebService = New-WebServiceProxy -uri $link -Credential $credential -Namespace NAVPortal.Application

Note:

Remember that the user name is in the format tenant\username, and your password is the web service access key.
You can find more info about New-WebServiceProxy cmdlet in the TechNet Library.

When you run this code, you will create a new namespace called NAVPortal.Application. Taking a closer look, you will see two other classes that we are more interested in: Application and Application_Service.

Creating an Application using PowerShell

Now that we know how to find the web services, how to log on to them, and how to connect to them by with PowerShell, we can (finally) create a new application. To create an application from PowerShell, run the following commands:

# Create the web service proxy
$link = "https://navmanagementportal.navcloudapptest.net:7047/NAV/WS/Fabrikam/Page/Application?tenant=fabrikam"
$credential = Get-Credential
$applicationWebService = New-WebServiceProxy -uri $link `
                                                  -Credential $credential `
                                                  -Namespace NAVPortal.Application

# Create the application object
$newApplication = New-Object -TypeName "NAVPortal.Application.Application"
 
# Set the application properties
$newApplication.Name = "NAV Demo"
$newApplication.Community_Link    = "mailto:admin@mycompany.com"
$newApplication.Feedback_Link     = "mailto:admin@mycompany.com"
$newApplication.Legal_Link        = "mailto:admin@mycompany.com"
$newApplication.Privacy_Link      = "mailto:admin@mycompany.com"
$newApplication.Sign_In_Help_Link = "mailto:admin@mycompany.com"
 
 
# Create the application in the portal
$applicationWebService.Create([ref] $newApplication)

 

As you can see, it is very easy to interact with the portal web services:

  • First, we create the proxy class that will allow us to interact with the server.
  • Then, we create an object of type Application, where we set all the parameters that we would set if we would do it manually in the portal.
  • And the last step is to use the proxy class to send the new application to the server.

The Create method in the previous code asks for an Application object, but the object is passed by reference. What does it change in the object that we sent? Well, it looks something like this:

PS C:\Users\navteam> $newApplication
Key                            : 24;WR8AAAJ7/0EAOQA3ADAAMQ==7;15308400;
Name                           : MyNewApplication
Description                    :
Display_Name                   : MyNewApplication | Powered by Microsoft
Login_Screen_Image_Info        : Browse
Splash_Screen_Image_Info       : Browse
Splash_Screen_Narrow_ImageInfo : Browse
Legal_Link                     : mailto:admin@mycompany.com
Feedback_Link                  : mailto:admin@mycompany.com
Privacy_Link                   : mailto:admin@mycompany.com
Community_Link                 : mailto:admin@mycompany.com
Sign_In_Help_Link              : mailto:admin@mycompany.com
License_File                   : Browse
O365AuthenticationStatus       : Not registered

Notice that some properties (like Display Name) have been set with their default values. There is also a property called Key. This property is used to handle concurrency conflicts. It is a hash of the record ID and the timestamp of when a record was last modified. The key value changes every time you update the record.

Uploading a license and login screen image to an Application

For small files, like the license file or the login screen images, uploading is done directly to the portal by using the following command:

$LicenseData = [convert]::ToBase64String((get-content $LicenseFilePath -encoding byte))
$applicationWebService.UploadLicense($newApplication.key,$LicenseData)

There are two important details here. First, the files need to be encoded to base 64. Second, when an action is done in the web service proxy class, most of the time you only need to provide the key of the entity, not the entire entity.

Creating an Application Version using PowerShell

OK, no more talking. Let’s go directly to the code:

# Create the web service proxy class
$link = "https://navmanagementportal.navcloudapptest.net:7047/NAV/WS/Fabrikam/Page/ApplicationVersion?tenant=fabrikam"
$credential = Get-Credential
$applicationVersionWebService = New-WebServiceProxy -Uri $link `
                                               -Credential $credential `
                                               -Namespace NAVPortal.ApplicationVersion
 

# Create a new Application Version
$newApplicationVersion = New-Object -TypeName "NAVPortal.ApplicationVersion.ApplicationVersion"
$newApplicationVersion.Name = "NAV Demo v1"
$newApplicationVersion.ApplicationName = "NAV Demo"
$newApplicationVersion.Description = "NAV Demo database"

$applicationVersionWebService.Create([ref] $newApplicationVersion)

 

Up until this point, there is nothing new – we just created a new application version named NAV Demo v1 inside the application named NAV Demo (which we created in the previous section).

Now, we need to upload the .bacpac files for the application and tenant databases. For this, the portal will first provide us with SAS (Shared Access Signature) tokens that will allow us to upload these big files to Microsoft Azure Storage. A SAS token is a URL that points to a blob in Azure storage. Here is the code:

# Get SasToken for app bacpacs
$appSasTokenUploadUri = $applicationVersionWebService.GetUploadAppUri($newApplicationVersion.Key);

If you use OneDrive, Office 365, or any other cloud storage system, you probably have used “Get Shared Link”, where you get a link to a picture or file that you can send to a friend. Then, whoever has that link, can download or see the picture or file.

The same mechanism applies for Azure Storage. You can get links (called SAS Tokens) that include some more advanced features, like an expiration date, or specific permissions (read, insert, modify, delete).

Now that we have a bacpac and a SAS token, how do we upload the file? For that, we will create a little helper function in PowerShell:

function Set-BlobContent
{
    param(
        [Parameter(Mandatory=$true)]
        [string] $BlobURI,
 
        [Parameter(Mandatory=$true)]
        [string] $FilePath
    )
 
    $BlobURI -match 'https:\/\/([a-z0-9]*).blob.core.windows.net\/([a-z0-9]*)\/([a-z0-9.\/]+)(\?.*)$' | out-null
 
    $storageAccountName = $Matches[1]
    $containerName = $Matches[2]
    $blobName = $Matches[3]
    $sasToken = $Matches[4]
 
    # Upload blob
container in '$storageAccountName' storage..."
    $storageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -SasToken $sasToken
    Set-AzureStorageBlobContent -File $FilePath -Container $containerName -Blob $blobName -Context $storageContext -Force
}

 

 

Now we just have to put all the pieces together:

# Get SasToken for the app bacpac   
$appSasTokenUploadUri = $applicationVersionWebService.GetUploadAppUri($newApplicationVersion.Key);
 
# Upload the bacpac to Azure
Set-BlobContent -BlobURI $appSasTokenUploadUri -FilePath $ApplicationBacpacPath

# Get SasToken for the tenant data bacpac
$appSasTokenUploadUri = $applicationVersionWebService.GetUploadTenantUri($newApplicationVersion.Key);
 
# Upload the tenant bacpac to Azure
Set-BlobContent -BlobURI $appSasTokenUploadUri -FilePath $TenantBacpacPath

Note:

The SAS tokens created by the portal have an expiration time of 2 hours. That is why you should try to keep as close as possible the GetUploadTenantUri and Set-BlobContent.

We are almost there – just one more small task to go.

The bacpacs are uploaded directly to Azure Storage, so the portal does not know when we are done uploading the files. That is why our last step will be to tell the portal that the .bacpac files are ready for use:

$operationID = $applicationVersionWebService.BeginSetUploaded($newApplicationVersion.Key)

At this point, the portal will check the databases, and it will try to extract the compatibility level. Because  the method name starts with Begin, this operation is asynchronous – see the next section.

Waiting for asynchronous operations in Dynamics NAV Managed Service

All long running operations in the Dynamics NAV Management Portal, like provisioning a service or a tenant, are asynchronous operations.

As we saw in the previous section, the first asynchronous operation that we have to face is when we are done with uploading the .bacpac files of an application version. At that moment, we need to tell the portal that both .bacpac files are ready, so the portal can check the files and extract the compatibility level. If everything is ok, the application version will be active and ready for use on application services.

Every time we have to do an operation whose name starts with Begin, it means that the server will return an OperationID without waiting for the operation to be completed.

If the client needs to wait for the operation to complete, then it has to query the portal and ask for the status of that operation.

To do this, it needs to contact another web service, which is the Operation web service:

# Get the Operation web service proxy
$link = "https://navmanagementportal.navcloudapptest.net:7047/NAV/WS/Fabrikam/Codeunit/Operation?tenant=fabrikam"
$operationWebService = New-WebServiceProxy -Uri $link -Credential $credential
 
# Begin the SetUploaded operation, and get the operation id
$operationID = $applicationVersionWebService.BeginSetUploaded($newApplicationVersion.Key)
 
# Wait until the operation is completed
do
{
  Start-Sleep -Second 5
 
  # Get the operation status based on the operation id
  $status = $operationWebService.GetOperationStatus($operationID)
}
while ($status -ne "Uploaded")

 

As evident in the code, long running operations return an operation ID that the client will use to query the status by using GetOperationStatus.

At this point, we have seen most of the techniques that are used to operate the portal by using web services. From now on, you will see that all the other entities use basically the same tools and processes. Let’s try to provision an Application Service.

Creating and provisioning an Application Service

Since we have seen most of this before, we can just take a look at the code for creating an application service:

# Connect to the Application Service and Operation web services
$link = "https://navmanagementportal.navcloudapptest.net:7047/NAV/WS/Fabrikam/{0}?tenant=fabrikam"

$webServiceName = "Page/ApplicationService"
$applicationServiceWebService = New-WebServiceProxy -uri ($link -f $webServiceName) -Credential $credential
 
$operationWebServiceName = "Codeunit/Operation"
$operationWebService = New-WebServiceProxy -uri ($link -f $webServiceName) -Credential $credential

# Create a new Application Service
$newApplicationService = New-Object -TypeName "$($applicationServiceWebService.GetType().Namespace).ApplicationService"
 
$newApplicationService.Name = $Name
$newApplicationService.TypeSpecified = $true
$newApplicationService.Azure_Location_Name = "North Europe"
$newApplicationService.ApplicationName = $ApplicationName
$newApplicationService.ApplicationVersionName = $ApplicationVersionName
$newApplicationService.PlatformVersionName = $PlatformVersionName
$newApplicationService.Enable_SOAP = $true
$newApplicationService.Enable_SOAPSpecified = $true
$newApplicationService.Enable_OData = $true
$newApplicationService.Enable_ODataSpecified = $true
 
$applicationServiceWebService.Create([ref] $newApplicationService)
 
# Get a token used to check the status of the Provision operation
$token = $applicationServiceWebService.BeginProvision($newApplicationService.Key);
 
do
{
  Start-Sleep -Seconds 30
  $operationStatus = $operationWebService.GetOperationStatus($token);
} while(($operationStatus -like "provisioning") -or ($operationStatus -like "starting"));

 

Similar to the application version, this code does the following:

  1. Creates the proxy classes.
  2. Creates an object of type ApplicationService.
  3. Creates the object in the portal using Create method.
  4. Begins provisioning the service, and gets the operation ID.
  5. Waits until the service is in Starting status.

Summary

You hopefully have an understanding of you can use the exposed SOAP web services to perform Dynamics NAV Management Portal operations programmatically. We plan on providing more examples in the future. For general information about web services in Dynamics NAV, you can see Web Services in the MSDN Library.