In this article by Stefano Demiliani, the author of the book Building ERP Solutions with Microsoft Dynamics NAV, we will experience the quick solution to solve complex technical architectural scenarios and create external applications within a blink of an eye using Microsoft Dynamics NAV.
(For more resources related to this topic, see here.)
Imagine a requirement where many Microsoft Dynamics NAV instances (physically located at different places around the world) have to interact with an external application. A typical scenario could be a headquarter of a big enterprise company that has a business application (called HQAPP) that must collect data about item shipments from the ERP of the subsidiary companies around the world (Microsoft Dynamics NAV):
The cloud could help us to efficiently handle this scenario. Why not place the interface layer in the Azure Cloud and use the scalability features that Azure could offer? Azure App Service could be the solution to this.
We can implement an architecture like the following schema:
Here, the interface layer is placed on Azure App Service. Every NAV instance has the business logic (in our scenario, a query to retrieve the desired data) exposed as an NAV Web Service. The NAV instance can have an Azure VPN in place for security.
HQAPP performs a request to the interface layer in Azure App Service with the correct parameters. The cloud service then redirects the request to the correct NAV instance and retrieves the data, which in turn is forwarded to HQAPP. Azure App Service can be scaled (manually or automatically) based on the resources requested to perform the data retrieval process.
Azure App Service is a PaaS service for building scalable web and mobile apps and enabling interaction with on-premises or on-cloud data. With Azure App Service, you can deploy your application to the cloud and you can quickly scale your application to handle high traffic loads and manage traffic and application availability without interacting with the underlying infrastructure. This is the main difference with Azure VM, where you can run a web application on the cloud but in a IaaS environment (you control the infrastructure like OS, configuration, installed services, and so on).
Some key features of Azure App Service are as follows:
Azure App Service offers different types of resources for running a workload, which are as follows:
Azure App Service has the following different service plans where you can scale from depending on your requirements in terms of resources:
Regarding the application deployment, Azure App Service supports the concept of Deployment Slot (only on the Standard and Premium tiers). Deployment Slot is a feature that permits you to have a separate instance of an application that runs on the same VM but is isolated from the other deployment slots and production slots active in the App Service.
Always remember that all Deployment Slots share the same VM instance and the same server resources.
Our solution is essentially composed of two parts:
The following steps will help you retrieve the required data from an external application:
I’ve changed the name of the field No. in Sales Shipment Line in DataItem as ItemNo because the default name was in used in Sales Shipment Header in DataItem.
Let’s start writing our service code.
We create a class called SalesShipment that defines our data model as follows:
public class SalesShipment
{
public string No { get; set; }
public string CustomerNo { get; set; }
public string ItemNo { get; set; }
public string Description { get; set; }
public string Description2 { get; set; }
public string UoM { get; set; }
public decimal? Quantity { get; set; }
public DateTime? ShipmentDate { get; set; }
}
In next step, we have to define our service contract (interface). Our service will have a single method to retrieve shipments for a NAV instance and with a shipment date filter. The service contract will be defined as follows:
public interface INAVService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate =
"getShipments?instance={NAVInstanceName}&date={shipmentDateFilter}"]
List<SalesShipment> GetShipments(string NAVInstanceName, string
shipmentDateFilter); //Date format parameter: YYYY-MM-DD
}
The WCF service definition will implement the previously defined interface as follows:
public class NAVService : INAVService
{
}
The GetShipments method is implemented as follows:
public List<SalesShipment> GetShipments(string NAVInstanceName, string shipmentDateFilter)
{
try
{
DataAccessLayer.DataAccessLayer DAL = new
DataAccessLayer.DataAccessLayer();
List<SalesShipment> list = DAL.GetNAVShipments(NAVInstanceName,
shipmentDateFilter);
return list;
}
catch(Exception ex)
{
// You can handle exceptions here…
throw ex;
}
}
This method creates an instance of a DataAccessLayer class (which we will discuss in detail later) and calls a method called GetNAVShipments by passing the NAV instance name and ShipmentDateFilter.
To call the NAV business logic, we need to have a reference to the NAV OData web service (only to generate a proxy class, the real service URL will be dynamically called by code) so right-click on your project (WCFServiceWebRoleNAV) and navigate to Add | Service Reference.
In the Add Service Reference window, paste the OData URL that comes from NAV and when the service is discovered, give it a reference name (here, it is NAVODATAWS).
Visual Studio automatically adds a service reference to your project.
The DataAccessLayer class will be responsible for handling calls to the NAV OData web service. This class defines a method called GetNAVShipments with the following two parameters:
According to NAVInstanceName, the method retrieves from the web.config file (appSettings) the correct NAV OData URL and credentials, calls the NAV query (by passing filters), and retrieves the data as a list of SalesShipment records (our data model).
The DataAccessLayer class is defined as follows:
public List<SalesShipment> GetNAVShipments(string NAVInstanceName, string shipmentDateFilter)
{
try
{
string URL =
Properties.Settings.Default[NAVInstanceName].ToString();
string WS_User = Properties.Settings.Default[NAVInstanceName +
"_User"].ToString();
string WS_Pwd = Properties.Settings.Default[NAVInstanceName + "_Pwd"].ToString();
string WS_Domain = Properties.Settings.Default[NAVInstanceName + "_Domain"].ToString();
DataServiceContext context = new DataServiceContext(new Uri(URL));
NAVODATAWS.NAV NAV = new NAVODATAWS.NAV(new Uri(URL));
NAV.Credentials = new System.Net.NetworkCredential(WS_User, WS_Pwd, WS_Domain);
DataServiceQuery<NAVODATAWS.ItemShipments> q = NAV.CreateQuery<NAVODATAWS.ItemShipments>("ItemShipments");
if (shipmentDateFilter != null)
{
string FilterValue = string.Format("Shipment_Date ge datetime'{0}'", shipmentDateFilter);
q = q.AddQueryOption("$filter", FilterValue);
}
List<NAVODATAWS.ItemShipments> list = q.Execute().ToList();
List<SalesShipment> sslist = new List<SalesShipment>();
foreach (NAVODATAWS.ItemShipments shpt in list)
{
SalesShipment ss = new SalesShipment();
ss.No = shpt.No;
ss.CustomerNo = shpt.Sell_to_Customer_No;
ss.ItemNo = shpt.ItemNo;
ss.Description = shpt.Description;
ss.Description2 = shpt.Description_2;
ss.UoM = shpt.Unit_of_Measure;
ss.Quantity = shpt.Quantity;
ss.ShipmentDate = shpt.Shipment_Date;
sslist.Add(ss);
}
return sslist;
}
catch (Exception ex)
{
throw ex;
}
}
The method returns a list of the SalesShipment objects. It creates an instance of the NAV OData web service, applies the OData filter to the NAV query, reads the results, and loads the list of the SalesShipment objects.
Now that your service is ready, you have to deploy it to the Azure App Service by performing the following steps:
These are the packages that must be deployed to Azure. To do so, you have to log in to the Azure Portal and navigate to Cloud Services | Add from the hub menu at the left.
In the next window, set the following cloud service parameters:
Finally, you can click on the Create button to create your cloud service.
Now, deploy the previously created cloud packages to your cloud service that was just created. In the cloud services list, click on NAVAZureCloudService, and in the next window, select the desired slot (for example, Production slot) and click on Upload as shown in the following screenshot:
In the Upload a package window, provide the following parameters:
You can take a look at the preceding parameters in the following screenshot:
Select the Start deployment checkbox and click on the OK button at the bottom to start the deployment process to Azure.
Now you can start your cloud service and manage it (swap, scaling, and so on) directly from the Azure Portal:
When running, you can use your deployed service by reaching this URL:
http://navazurecloudservice.cloudapp.net/NAVService.svc
This is the URL that the HQAPP in our business scenario has to call for retrieving data from the various NAV instances of the subsidiary companies around the world.
In this way, you have deployed a service to the cloud, you can manage the resources in a central way (via the Azure Portal), and you can easily have different environments by using slots.
In this article, you learned to enable NAV instances placed at different locations to interact with an external application through Azure App Service and also the features that it provides.
Further resources on this subject:
At Packt, we are always on the lookout for innovative startups that are not only…
I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…
Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…
Once we learn how to deploy an Ubuntu server, how to manage users, and how…
Key-takeaways: Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…
While developing a web application, or setting dynamic pages and meta tags we need to deal with…