Export (0) Print
Expand All

Talking with Navision: Exposing .NET Components to Navision

 

Manuel Oliveira
Microsoft Portugal

November 2006

Applies to:
   Microsoft Navision
   Microsoft Dynamics NAV

Summary: This article gives you some guidance on how to bring the Navision and .NET worlds together. (10 printed pages)

Contents

Introduction
Overview
First Example: Consuming a Web Service
Second Example: Using a .NET-Based Timer
Conclusion

Introduction

As a former Navision developer, I ran into several scenarios in which Navision had to interoperate with business-specific third-party applications. Fair enough. But when some of these were .NET apps or ASP.NET Web services, I felt as if I were wasting my time talking SOAP or developing connectors that relied upon named pipes, sockets, or message queues for communication purposes, instead of being able to use the exposed functionality seamlessly.

This paper provides guidance for developing .NET components bound for Navision consumption, so that Navision is kept away from the implementation details as much as possible. For this purpose, two examples will be used:

  • A Web-service consumer
  • A .NET timer exposing properties, methods, and events

Overview

Both of the examples share the same model, which consists in developing a COM-visible library that Navision will instantiate. Only the relevant elements are made visible, and the functionality lies within the .NET library.

Instead of having to interact directly with the .NET reality, Navision would only need to exercise a small set of components whose main responsibility would be the establishment of a bridge with the .NET world.

Figure 1. The COM world and the .NET world

First Example: Consuming a Web Service

For this example, we'll create a tiny Web service with only two Web methods: the classic "Hello, world" method, and an integer-adding Web method.

This is what the Web service might look like.

using System;
using System.ComponentModel;
using System.Web.Services;

namespace SimpleWebService
{

  public class SimpleWebService : System.Web.Services.WebService
  {
    public SimpleWebService()
    {
      //CODEGEN: This call is required by the ASP.NET Web Services Designer
      InitializeComponent();
    }

    #region Component Designer generated code
    
    //Required by the Web Services Designer
    private IContainer components = null;
        
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
    }

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if(disposing && components != null)
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }
    
    #endregion

    [WebMethod]
    public string HelloWorld()
    {
      return "Hello Navision World";
    }

    [WebMethod]
    public int Sum (int op1, int op2)
    {
      return op1 + op2;
    }
  }
}

Now that we have the Web service, we need the part that both knows how to call the Web methods in an elegant fashion and exposes itself to COM in a way that Navision recognizes it.

The following code (a C# class library) presents one such possibility.

using System;
using System.Runtime.InteropServices;

namespace NavWSClient
{
  [ClassInterface (ClassInterfaceType.AutoDual)]
  [ProgId ("NavWSClient")]
  [ComVisible (true)]
  public class NavWSClient
  {
    ws.SimpleWebService ws;

    public NavWSClient()
    {
      ws = new ws.SimpleWebService ();
    }

    public int wsSum (int op1, int op2)
    {
      return (ws.Sum (op1, op2));
    }

    public string wsHello ()
    {
      return (ws.HelloWorld ());
    }
  }
}

You must add a Web reference to the Web service (I named it ws). Look, no SOAP, no unnecessary mechanisms—just plain C# code calling Web methods as if they were common methods!

Notice the attributes that we're using for the class. Aside from these, this could be a very simple client for our Web service. Without such attributes, however, we wouldn't be able to talk about COM interop, and Navision wouldn't be able to use the service.

For more information about these attributes, browse to the following:

Don't forget to go to Project Properties and set the Register for COM Interop option to True, as depicted in Figure 2.

Figure 2. Registering the project's output file for use with COM components

Finally, let's open Navision, create a new codeunit, and start using the Web service!

Figure 3. Creation of the codeunit and use of the SimpleWebService

After the Automation variable has been declared, all we need is to instantiate it and start using its COM-visible methods. It takes only three lines of code.

Figure 4. Code for instantiation of Automation variable

Now, try it. You'll see two message boxes: one says Hello Navision World and the other one displays a 5. Cool, right?

Second Example: Using a .NET-Based Timer

This example is a little bit more complex than the previous one, as it shows how to make .NET events visible to Navision. In technical terms, Navision must register itself as a sink for the .NET class events.

For the sake of simplicity, our timer has one:

  • Public property—the timer interval.
  • Public method—the start method.
  • Event—the elapsed event.

By using the following code, Navision should be able to instantiate the timer interval, start the timer, and then capture the events, responding to them in some way.

using System;
using System.Timers;
using System.Runtime.InteropServices;

namespace COMTimer
{

  // A delegate type for when the timer elapses.
  public delegate void TimerElapsed();

  [Guid ("1533D027-C22A-585E-058E-56A218149D23")]
  [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
  public interface TimerEvents
  {
    [DispId (0x60020000)]
    void Elapsed();
  }

  [ComVisible(true)]
  public interface ICOMTimer
  {
    double Interval {get; set;}
    void Start ();
  }

  /// <summary>
  /// The COMTimer class consists of an internal System.Timers.Timer instance
  /// whose behaviour is made COMVisible
  /// </summary>
  [ClassInterface(ClassInterfaceType.None),
                  ComSourceInterfaces(typeof(TimerEvents))]
  [ProgId ("COMTimer")]
  public class CCOMTimer : ICOMTimer
  {
    /// <summary>
    /// The internal System.Timers.Timer instance
    /// </summary>
    private Timer mTimer;

    /// <summary>
    /// The interval at which the timer elapses
    /// </summary>
    private double mInterval;

    /// <summary>
    /// An event that clients can use to be notified whenever the
    /// internal timer elapses
    /// </summary>
    public event TimerElapsed Elapsed;

    ///<summary>
    /// Invoke the Changed event; called whenever the internal timer elapses
    /// </summary>
    protected virtual void OnElapsed(EventArgs e)
    {
      Elapsed();
    }

    /// <summary>
    /// Default constructor.
    /// </summary>
    public CCOMTimer()
    {
      mTimer = new Timer ();
      mTimer.Elapsed += new ElapsedEventHandler(mTimer_Elapsed);
    }

    /// <summary>
    /// Public property for setting the timer interval
    /// </summary>
    public double Interval
    {
      get { return mInterval; }
      set
      {
        mInterval = value; 
        mTimer.Interval = mInterval;
      }
    }

    /// <summary>
    /// Starts the internal timer
    /// </summary>
    public void Start ()
    {
      mTimer.Start ();
    }

    /// <summary>
    /// Whenever the internal timer elapses, an event must be fired
    /// </summary>
    private void mTimer_Elapsed(object sender, ElapsedEventArgs e)
    {
      OnElapsed (EventArgs.Empty);
    }
  }

Again, here are two online references about the attributes that we used in this example:

As stated earlier, our class has one public property and one method (made COM-visible through the ICOMTimer interface) and one public event (made visible through the TimerEvents interface).

This particular example is based on a small yet great paper in the MSDN Library entitled Raising Events Handled by a COM Sink.

Let's see how to use this functionality in Navision. Some of you might say that there's no use for this timer in Navision, as there's a 'Navision Timer 1.0'.Timer ready for use. I couldn't agree more. However, I'm using this example for simplicity, and you can use these principles as needed.

Let's start by creating a new codeunit and adding a global variable of type Automation for our timer. When you set the WithEvents property to Yes, you'll see that the event handler is added automatically to the code window, as depicted below.

Figure 5. The event handler, added automatically to the code window

Don't forget to set the codeunit's SingleInstance property to Yes, too! If you don't set this property, the variables' scope is limited to the execution of the OnRun() method (we'd like our timer to last for some time, in order to see some action).

Figure 6. Setting the codeunit's SingleInstance property to Yes

Now, let's write some code for testing our timer. All we need to do is to set an interval, start the timer, and add some code for when the timer elapses.

Figure 7. Code for testing the timer

Finally, save your codeunit and try it! Be ready to close Navision any time, as this will bother you every 5 seconds with a Timer elapsed message box. That might be funny, unless you're trying to do something useful at the same time.

Conclusion

As we're bringing the .NET world into the world in which Navision lives, we are in fact bringing tons of new options when it comes to integration. Be sure, though, that some difficulties might also stem from such possibility. If, for instance, you need to use complex data types, you'd better start thinking about ways to make them Navision-bound (you can always pack the data into XML files and then instantiate the XML DOM objects that Navision is able to interpret...).

These two examples show you how to open the door between both worlds. Now, here's your chance to unleash the enormous power of .NET from within Navision!

 

About the author

Manuel Oliveira is an Application Development Consultant working at Microsoft Portugal. He's the author of two other MSDN articles that you have probably heard of: Talking with Navision: Say Hello to Navision and Expect Navision to Be Polite and Talking with Navision: Accessing Navision Business Layer through a Web Service.

Show:
© 2014 Microsoft