A Framework for Unified Dynamics Mobile Business Application Development

This framework shows how we can build a cross-patform unified solution that can be used with most of the Microsoft Dynamics products.

It is also a starting point in a contest endorsed by Microsoft Dynamics Academic Alliance Advisory Council for students from different countries for developing simple business processes as mobile extensions to Dynamics products.

What is UniDynApps?

There is no such a thing as an information system suitable for every conceivable process from a company.

Many of these processes need to take place in the field, thus mobile device based solutions could be a suitable approach solving the informational needs of the workers involved in these processes.

The Microsoft Dynamics solutions are very flexible, and allow development of extensions suitable to each processes that need to be integrated in the system.

Our approach shows how we can build a unified solution that can be used with most of the Dynamics products, without too many modifications on the client side.

For this reason we built a framework that can connect to each of the Dynamics products and allows a unified client interface to be used.

The purpose of this framework is mainly educational, and can be used in different courses related to information systems and mobile applications.

Another area where this framework would be useful is as starting point in a contest for developing cross-platform mobile extensions to the Dynamics products.

Designed for developers

Time saver

Focused on mobile business processes

Cross-platform

Easy to customise

Encourages new UX designs

Features

Get Started

The middleware

A middleware is used for hiding the differences between the different Dynamics platforms.

It implements a unified REST web API that can be consumed from the mobile clients.

At the moment the following three APIs are partially implemented:

  • Login
  • Clients
  • Sales Orders

Below are some details of how are these implemented.

Login

    interface IApiProvider
    {
        UserModel User { get; set; }
    }

    interface IAuthenticationProvider
    {
        bool Login(UserModel user);
    }

    class AXAuthenticationProvider : IAuthenticationProvider
    {
        public bool Login(UserModel user)
        {
            try
            {
                NetworkCredential credential = new NetworkCredential(user.name, user.password, user.domain);

                AXLoginService.LoginClient loginClient = new AXLoginService.LoginClient();
                loginClient.Endpoint.ListenUri = new Uri(Globals.AXLoginServices);
                loginClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.AXLoginServices);
                loginClient.ClientCredentials.Windows.ClientCredential = credential;

                AXLoginService.CallContext loginContext = new AXLoginService.CallContext();
                loginContext.Company = "usmf";

                var login = loginClient.find(loginContext, null);
                ResponseModel response = new ResponseModel(login, "success");

                return (response.error == null);
            }
            catch (Exception e)
            {
                Console.WriteLine("Error " + e.Message);
                return false;
            }
        }
    }

    class NAVAuthenticationProvider : IAuthenticationProvider
    {
        public bool Login(UserModel user)
        {
            try
            {
                NetworkCredential credential = new NetworkCredential(user.name, user.password, user.domain);

                Login_PortClient service = new Login_PortClient();
                service.Endpoint.ListenUri = new Uri(Globals.NAVLoginService);
                service.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.NAVLoginService);
                service.ClientCredentials.Windows.ClientCredential = credential;

                var login = service.Read(user.name);
                if (login == null)
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error " + e.Message);
                return false;
            }
            return true;
        }
    }
                    
Clients

    interface ICustomerProvider : IApiProvider
    {
        object GetCustomerList();
        object GetCustomer(string id);
        bool CreateCustomer(JObject data);
        bool DeleteCustomer(string id);
    }

    public class AxCustomerProvider : ICustomerProvider
    {
        private static AXCustomerListService.CustomerServiceClient customerListClient;
        private static AXCustomerService.CustomerServiceClient customerClient;

        public UserModel User { get; set; }

        public AxCustomerProvider(UserModel user)
        {
            User = user;
            NetworkCredential credential = new NetworkCredential(user.name, user.password, user.domain);

            customerListClient = new AXCustomerListService.CustomerServiceClient();
            customerListClient.Endpoint.ListenUri = new Uri(Globals.AXCustomerListServices);
            customerListClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.AXCustomerListServices);
            customerListClient.ClientCredentials.Windows.ClientCredential = credential;

            customerClient = new AXCustomerService.CustomerServiceClient();
            customerClient.Endpoint.ListenUri = new Uri(Globals.AXCustomerServices);
            customerClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.AXCustomerServices);
            customerClient.ClientCredentials.Windows.ClientCredential = credential;
        }

        public bool CreateCustomer(JObject data)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public bool DeleteCustomer(string id)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomer(string id)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomerList()
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }
    }

    public class NavCustomerProvider : ICustomerProvider
    {
        private Customer_PortClient service;
        public UserModel User { get; set; }
        public NavCustomerProvider(UserModel user)
        {
            User = user;
            NetworkCredential credential = new NetworkCredential(user.name, user.password, user.domain);
            service = new Customer_PortClient();
            service.Endpoint.ListenUri = new Uri(Globals.NAVCustomerService);
            service.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.NAVCustomerService);
            service.ClientCredentials.Windows.ClientCredential = credential;
        }

        public bool CreateCustomer(JObject data)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public bool DeleteCustomer(string id)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomer(string id)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomerList()
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }
    }    
                    
Sales Orders

    interface ISalesOrderProvider : IApiProvider
    {
        object GetCustomerSalesOrderList(string customerId);
        object GetCustomerSalesOrder(string customerId, string salesOrderId);
        bool CreateCustomerSalesOrder(JObject data);
        bool DeleteCustomerSalesOrder(string customerId);
    }

    class AxSalesOrderProvider : ISalesOrderProvider
    {
        private static AXSalesOrderListService.SalesOrderServiceClient salesOrderListClient;
        private static AXSalesOrderService.SalesOrderServiceClient salesOrderClient;
        public UserModel User { get; set; }

        public AxSalesOrderProvider(UserModel user)
        {
            User = user;
            NetworkCredential credential = new NetworkCredential(user.name, user.password, user.domain);

            salesOrderListClient = new AXSalesOrderListService.SalesOrderServiceClient();
            salesOrderListClient.Endpoint.ListenUri = new Uri(Globals.AXSalesOrderListServices);
            salesOrderListClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.AXSalesOrderListServices);
            salesOrderListClient.ClientCredentials.Windows.ClientCredential = credential;

            salesOrderClient = new AXSalesOrderService.SalesOrderServiceClient();
            salesOrderClient.Endpoint.ListenUri = new Uri(Globals.AXSalesOrderServices);
            salesOrderClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.AXSalesOrderServices);
            salesOrderClient.ClientCredentials.Windows.ClientCredential = credential;
        }

        public bool CreateCustomerSalesOrder(JObject data)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public bool DeleteCustomerSalesOrder(string customerId)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomerSalesOrder(string customerId, string salesOrderId)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomerSalesOrderList(string customerId)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }
    }

    class NavSalesOrderProvider : ISalesOrderProvider
    {
        private SalesOrder_PortClient salesOrderListClient;
        public UserModel User { get; set; }
        public NavSalesOrderProvider(UserModel user)
        {
            User = user;
            NetworkCredential credential = new NetworkCredential(user.name, user.password, user.domain);
            salesOrderListClient = new SalesOrder_PortClient();
            salesOrderListClient.Endpoint.ListenUri = new Uri(Globals.NAVSalesOrderService);
            salesOrderListClient.Endpoint.Address = new System.ServiceModel.EndpointAddress(Globals.NAVSalesOrderService);
            salesOrderListClient.ClientCredentials.Windows.ClientCredential = credential;
        }
        public bool CreateCustomerSalesOrder(JObject data)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public bool DeleteCustomerSalesOrder(string customerId)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomerSalesOrder(string customerId, string salesOrderId)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }

        public object GetCustomerSalesOrderList(string customerId)
        {
            // Please register to the UniDynApps Contests to be able to access the sample implementation
        }
    }
                    

The cross-platform client


                    

The native cross-platform client


                    

Full Documentation/Source Code

To be able to access the full source code and some guidelines, please register to the UniDynApps Contests

More on GitLab

License

All the framework and samples are licensed under the following license (even if some of the files do not include yet the notice):

Copyright 2015-2016 UniDynApps

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.