Connecting to NAV Web Services from C# using Service Reference (code version)


You should read the post about connecting to NAV Web Services from C# using Service Reference (config file version) before continuing here.

Code is king

As you saw in the other post, the config file was pretty complicated and although it is editable by hand and as such could be modified at installtime or whatever, I actually prefer to capture a number of these settings in code and only have very specific values in a config file (like f.ex. the base URL).

In NAV you would never have the full Service URL on all services in a config file. This would mean that you would have to change company in a number of locations in a config file – that just doesn’t fly.

If we have a look at the config file once more, you will see that there is a Binding configuration, specifying a BasicHttpBinding with a couple of settings. If we want to create this binding in code, it would look like:

// Create a NAV comatible binding
BasicHttpBinding navWSBinding = new BasicHttpBinding();
navWSBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
navWSBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

Having this binding class, we can now create a systemService Service Client simply by:

SystemService_PortClient systemService = new SystemService_PortClient(navWSBinding, new EndpointAddress(baseURL + "SystemService"));

Specifying the endpoint address to the constructor.

The only other thing we need to specify is the endpoint behavior to allow delegation. This is done in code by:

systemService.ClientCredentials.Windows.AllowedImpersonationLevel = 
     System.Security.Principal.TokenImpersonationLevel.Delegation;
systemService.ClientCredentials.Windows.AllowNtlm = true;

Using code like this actually makes the app.config obsolete and you can delete the config file totally when running the below application.

The entire application

The following is a listing of the full console application using code to set all properties and no app.config is necessary (nor used at all):

using System;
using System.Net;
using testAppWCF.SystemServiceRef;
using testAppWCF.CustomerPageRef;
using System.ServiceModel;

namespace testAppWCF
{
    class Program
    {
        static void Main(string[] args)
        {
            string baseURL = "
http://localhost:7047/DynamicsNAV/WS/";

            // Create a NAV compatible binding
            BasicHttpBinding navWSBinding = new BasicHttpBinding();
            navWSBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
            navWSBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;

            // Create the SystemService Client
            SystemService_PortClient systemService = new SystemService_PortClient(navWSBinding, new EndpointAddress(baseURL + "SystemService"));
            systemService.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
            systemService.ClientCredentials.Windows.AllowNtlm = true;

            Console.WriteLine("Companies:");
            string[] companies = systemService.Companies();
            foreach(string company in companies)
                Console.WriteLine(company);
            string cur = companies[0];

            string customerPageURL = baseURL + Uri.EscapeDataString(cur) + "/Page/Customer";
            Console.WriteLine("\nURL of Customer Page: "+customerPageURL);

            // Create the Customer Page Service Client
            Customer_PortClient customerService = new Customer_PortClient(navWSBinding, new EndpointAddress(customerPageURL));
            customerService.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
            customerService.ClientCredentials.Windows.AllowNtlm = true;

            Customer customer10000 = customerService.Read("10000");
            Console.WriteLine("\nName of Customer 10000: "+customer10000.Name);

            Customer_Filter filter1 = new Customer_Filter();
            filter1.Field = Customer_Fields.Country_Region_Code;
            filter1.Criteria = "GB";

            Customer_Filter filter2 = new Customer_Filter();
            filter2.Field = Customer_Fields.Location_Code;
            filter2.Criteria = "RED|BLUE";

            Console.WriteLine("\nCustomers in GB served by RED or BLUE warehouse:");
            Customer_Filter[] filters = new Customer_Filter[] { filter1, filter2 };
            Customer[] customers = customerService.ReadMultiple(filters, null, 0);
            foreach (Customer customer in customers)
                Console.WriteLine(customer.Name);

            Console.WriteLine("\nTHE END");
            Console.ReadLine();
        }
    }
}

If you need to specify a different username / password it is done in the same way as it was done for Service References using config files.

This application will output exactly the same as the application using Service References and a config file, in the end the config file is just a number of settings which will be used to instantiate a number of classes from – giving the same result.

I hope this is helpful.

Good luck

Freddy Kristiansen
PM Architect
Microsoft Dynamics NAV

Comments (7)

  1. himanshu.navision says:

    I created project it is working fine on same computer where navision installed.

    when i tried to run from another computer in network (i updated string and credintial) i got authorization 401 error.

    can you tell what i missed?

  2. FreddyDK says:

    if you open a browser from the other computer and type in the URL of the WSDL – does this work?

  3. himanshu.navision says:

    Hello sir i work done with all the card and list view i am got success with your help and my modules are working fine.

    I made dynamic form generation with the use of web service.

    Sir if you want i can send you my code and snapshot if you want.

    you can review it give me feedback

    THANKS

    Himanshu

  4. vladimir.smart says:

    Hello,

    I have the same problem with 401 error.

    [MessageSecurityException: The HTTP request is unauthorized with client authentication scheme ‘Negotiate’. The authentication header received from the server was ‘Negotiate’.]

    Can You or Mr. Himanshu post some code or link to correct solution.    

    PS. Freddys Blog is the best place for NAV ideas…:)

  5. himanshu.navision says:

    hi  Vladimir

    did you set default credintial?

    I think you will find usedefaultcredintial = true;

  6. vladimir.smart says:

    Yes, but if I need to use other windows account.

    I have web application with form autentification and whan i try to connect to web service i need to set some windows account to it. Now if I use usedefaultcredintial = true; then service will ask me to enter some windows account to connect…

  7. vladimir.smart says:

    Problem resolved.

    If the service WebServicesUseNTLMAuthentication property set to false i need to comment customerService.ClientCredentials.Windows.AllowNtlm = true;

    It was simple but required a lot of my time to solve it.Thank you for your response.

Skip to main content