Ethisys Blog

The latest news from Ethisys

Get a product from Microsoft Dynamics 365 Commerce – .NET Core Tutorial

Third party systems consuming D365 Commerce data is a frequent requirement, and with very little information existing on this, we’re sharing a tutorial of how we do this at Ethisys using .NET Core API development:

After configuring your D365 environment, and setting up a .NET Core API solution in Visual Studio with the ‘Microsoft.Dynamics.Commerce.RetailProxy’ and ‘Microsoft.Dynamics.Commerce.KeyVault.Contracts’ NuGet packages, the first step is to add our Retail Server configuration to appsettings.json:

"365Settings": {
    "RetailServerRoot": "https://ID_HERE.cloud.retail.dynamics.com/Commerce",
    "OperatingUnitNumber":"INSERT_UNIT_NUMBER",
    "Resource": "" 
  }

Following this we can create a controller, we’ll call this ProductsController with an Action called ‘GetProduct’:

namespace Ethisys.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class ProductsController : ControllerBase
    {
        private readonly ILogger<ProductsController> _logger;
        private readonly IProductRepository _productRepository;

        public ProductsController(ILogger<ProductsController> logger, IProductRepository productRepository)
        {
            _logger = logger;
            _productRepository = productRepository;
        }


        [HttpGet]
        [Route("[action]/{id?}")]
        public async Task<Product> GetProduct(string id) =>
         await _productRepository.GetProduct(id);

    }
}

We’ve refactored the CRUD operations into a repository to keep things abstract and decouple our API from the D365 product, thus enabling any Commerce provider to be swapped into the solution later along the line. Next comes the repository source. We can create a D365 Product repository with the following constructor:

namespace Ethisys.Repositories.Products.D365
{

    public class Dynamics365ProductRepository : IProductRepository
    {
        private readonly IConfiguration Configuration;
        private ManagerFactory _managerFactory;
        private ChannelConfiguration _channelConfiguration;
        private SimpleProductMapper _simpleProductMapper = new SimpleProductMapper();

        string _serverRoot;
        string _unitNumber;

        public Dynamics365ProductRepository(IConfiguration configuration)
        {
            _serverRoot = configuration["365Settings:RetailServerRoot"];
            _unitNumber = configuration["365Settings:OperatingUnitNumber"];

            Configuration = configuration;
            RetailServerContext context = RetailServerContext.Create(new Uri(_serverRoot), _unitNumber);

            _managerFactory = ManagerFactory.Create(context);

            IOrgUnitManager orgUnitManager = _managerFactory.GetManager<IOrgUnitManager>();
            _channelConfiguration = orgUnitManager.GetOrgUnitConfiguration().Result;
        }
    }
}

Note the serverRoot and unitNumber from our appsettings.json file which allow us to set up a RetailServerContext. Now we’ve successfully added configuration to connect to the D365 Commerce environment, we can add an simple Task to get a product by the id. For the purpose of the tutorial we’re manually setting the channelId to ’77’:

        public async Task<Models.Product> GetProduct(string id)
        {
            IProductManager prodManager = _managerFactory.GetManager<IProductManager>();

            long pId = 0;
            if (long.TryParse(id, out pId))
            {
                var product = prodManager.GetById(pId, 077).Result;

                if (product == null)
                {
                    return null;
                }

                return _simpleProductMapper.Map(product);
            }

            return null;
        }

We’re calling a mapping class to map the data to a Commerce product type but you can map this however you wish to do so. Our repository class in full now appears as follows:

using System;
using System.Threading.Tasks;
using Microsoft.Dynamics.Commerce.RetailProxy;
using Microsoft.Extensions.Configuration;


namespace Ethisys.Repositories.Products.D365
{

    public class Dynamics365ProductRepository : IProductRepository
    {
        private readonly IConfiguration Configuration;
        private ManagerFactory _managerFactory;
        private ChannelConfiguration _channelConfiguration;
        private SimpleProductMapper _simpleProductMapper = new SimpleProductMapper();

        string _serverRoot;
        string _unitNumber;

        public Dynamics365ProductRepository(IConfiguration configuration)
        {
            _serverRoot = configuration["365Settings:RetailServerRoot"];
            _unitNumber = configuration["365Settings:OperatingUnitNumber"];

            Configuration = configuration;
            RetailServerContext context = RetailServerContext.Create(new Uri(_serverRoot), _unitNumber);

            _managerFactory = ManagerFactory.Create(context);

            IOrgUnitManager orgUnitManager = _managerFactory.GetManager<IOrgUnitManager>();
            _channelConfiguration = orgUnitManager.GetOrgUnitConfiguration().Result;
        }


        public async Task<Models.Product> GetProduct(string id)
        {
            IProductManager prodManager = _managerFactory.GetManager<IProductManager>();

            long pId = 0;
            if (long.TryParse(id, out pId))
            {
                var product = prodManager.GetById(pId, 077).Result;

                if (product == null)
                {
                    return null;
                }

                return _simpleProductMapper.Map(product);
            }

            return null;
        }
    }
}

We can deploy the .NET Core API to an Azure Service for example, and observe the output when calling our API endpoint (hostname/products/getproduct/PRODUCTID). A sample output of basic mapped data from _simpleProductMapper.Map would appear as follows:

{
  "descriptionPlainText": "A description from the test product",
  "responsibility": null,
  "name": "Sample Product 1",
  "descriptionHtml": "<p>A description from the test product</p>",
  "id": "SOME_GUID",
  "category": {
    "name": "Category 1",
    "id": "SOME_GUID"
  },
  "type": {
    "name": "Type 1",
    "id": "SOME_GUID"
  }

You can extend your repository by adding useful methods such as GetProductPrice, GetAllProducts, GetAllProductTypes etc from the SDK.

Ethisys are Microsoft Silver Partners – If you’d like to know more about quality Microsoft Dynamics 365 Commerce implementations, contact us today.

Leave a Reply

%d bloggers like this: