Dynamics NAV in C# | Part 2 | Classes (Updated)

Disclaimer: If you are a skilled C# developer, I apologize for any mistakes I made, they we unintentional. ๐Ÿ™‚

UPDATE (29/nov/2014): Based on the feedback from Jason Down I changed the C# code to get the number from the number series class.

Ok, there we go. No more conferences so time to do some actual blogging.

This is part 2 of my NAV in C# series. If you have not done so, please read part 1.

In this episode we will talk about classes.

In C# a class is very powerfull. It’s a datatype that you can form yourself giving it properties and methods. And since C# is object oriented, you can inherit from classes etc.

But let’s not get into these details. The blog series is intended to explain C# from a Dynamics NAV perspective.

So how do we map a class to Dynamics NAV.

Actually you could see a table or a codeunit as a class.

A Table is a Class

Let’s start with that. Let’s have a look at the customer table in NAV. It has a bunch of fields

2014-11-27_21-38-07

So how would something like that look like in C#:

2014-11-27_21-41-27

Each field is a property. You can see that it is a property because it has the { get; set; } syntax

If you would like to code against it you would declare a new customer like this

Customer Cust = new Customer();

Cust.Name = “Mark Brummel”;

Cust.Address = “Somewhere”;

This would create a new instance of the class and populate the name

Number Series

But we have number series in NAV. ย So let’s make that

A Codeunit as a class

Let’s make a class that can return number series.

2014-11-27_21-46-58

This is a very simple class with a method that returns a number. It should be smarter but I hope it explains the idea

Return the number in the customer

So what if we want to assign this number to the customer? In C/AL we would have triggers. In this example we would use the getter, and store the value in a variable. This latter would off-course be done in the SQL Table in NAV itsself.

2014-11-29_11-10-04.

In the property we return the value of the number series. See how easy that is?

Now if we create a sample application that would create a customer we would have this

2014-11-27_21-51-24

So we have a new customer with a number, that we do not declare in the class, it is automatically added, like in Dynamics NAV

What about address formatting

So we print the address, but what if I want to do that like in NAV? Then we need a new codeunit class, and we would add a method to the class, like this:

2014-11-27_21-54-02

This class takes a customer as a parameter and calls into a generic function to move the address to an array. It also has a function for the Sales Invoice, a class we will use in the next blog post.

A Codeunit is a Method

In C# we would add the adressformating as a method that we can do with a class. This way we don’t have to call the addressformatting class in our programm.

Like this:

2014-11-27_21-56-00

And the keyword this stands for what we would cal Rec in Dynamics NAV.

This is what it does in the program:

2014-11-27_21-58-07

A Table is a Class, A Codeunit is a Method (and a class)

So a table definition (not the actual SQL table) would be a class and a codeunit too, and added to the table class.

This actually would work nice in NAV too, if we would declare things like FormatAddress on the table, we would never have to use Codeunits as a variable anymore.

Next time…

I will explain how to create a sales order in C# and how to post it to a sales invoice.

Hang on, stay tuned.

Advertisements

12 thoughts on “Dynamics NAV in C# | Part 2 | Classes (Updated)

  1. Hey Mark. Just one thing about your Customer No_ property. Each time you access that property you would get a new number. Instead you should have a backing field. Check if that value is null (or use the IsNullOrWhiteSpace function) in the No_ property getter. If so, then get a new number. For example:

    public class Customer
    {
    private string _no_;
    public string No_
    {
    get
    {
    if (String.IsNullOrWhiteSpace(_no_))
    {
    NoSeriesManagement test = new NoSeriesManagement();
    _no_ = test.GetNextNo(“”);
    }
    return _no_;
    }
    set { _no_ = value; }
    }

    }

    Like

  2. No problem. I’m very interested in the series and will provide feedback whenever possible (I come from the C# world and I’m still fairly new to NAV). On a side note, I had a chance to see your presentations in Antwerp and thought the ideas were great. I had a chance to meet Soren and chat with him a bit about source control stuff, but I didn’t get a chance to meet you. Maybe at a future conference ๐Ÿ™‚

    Like

  3. Hi Mark,

    Following on from Jason’s advice, I have a few more tips that would make the C# code more idiomatic and help get new developers into good habits from the start. Good habits == stable code ๐Ÿ™‚

    C# supports object initializers which allow you to specify the object’s properties at construction time:
    Customer customer = new Customer {
    Name = “Mark Brummel”,
    Address = “Somewhere”
    };
    This is useful when dealing with large numbers of objects of the same type so you can reduce the chance of changing the wrong object. It also shows other developers that you are setting those properties as a part of the object’s initialization, so it shows the intent behind the code.

    Along the same lines C# also supports collection initializers so you can define and initialize collections neatly:
    string[] addressArray = new [] { Name, Address, “”, “”, “”, “”, “” };
    This means you can add items to your array and have the compiler do the work of calculating the number of elements so it reduces the chance of human error and also reduces the amount of work you need to do as a developer.

    Additionally, FormatAddress should be written as a static class. This shows other developers that the class has no internal state to worry about, which means the code is simpler and its intent is obvious. This means there is less chance of misunderstanding between developers which means fewer bugs.

    public static class FormatAddress {
    public static string[] FormatCustomer(Customer customer) {
    return FormatAddress(customer.Name, customer.Address);
    }
    public static string[] FormatAddress(string name, string address) {
    return new [] { name, address, “”, “”, “”, “”, “” };
    }
    }

    And you would call it:
    public string[] GetFormattedAddress() {
    return FormatAddress.FormatCustomer(this);
    }

    Happy coding ๐Ÿ™‚

    Like

  4. I recall an old paper by a Microsoft employee which pointed out the tension between an OO-model language to a relational model (which is how SQL Server and many other DBs for ERP programs are set up).

    The OO-model isn’t a good fit, since the relational model allows partially fetching a table**, while one can’t partially create a class (we’d have to declare a partial class for every combination of fields?). On on other hand, table as a class would allow ‘inheriting’ the table, and creating a new ‘table’ which contains only the additional members (and an ‘inherited’ table record or pointer to it). This has been done, but isn’t all that efficiently supported in SQL Server.

    The paper pointed out solutions for the problems:

    * Changing the DB to a more OO-like DB.
    * Changing the programming language to have better support for a relational model (IIRC, the term is ‘first class records’?).
    * Just scraping through, and hacking the language to work as best as possible (his preferred solution and what ends up happening most of the time).

    ** e.g. doing a ‘Group-By’ and fetching sums. What’s the ‘class’ equivalent?

    Like

  5. Hi Mark, I tried to connect to published codeunit using visual studio

    I followed this link

    https://msdn.microsoft.com/en-us/library/dd339004.aspx/

    I’m getting this error

    Error CS1061 ‘Letters’ does not contain a definition for ‘Capitalize’ and no extension method ‘Capitalize’ accepting a first argument of type ‘Letters’ could be found (are you missing a using directive or an assembly reference?)

    Could you please let me know what I’m missing here

    This is my code:
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace UsingLettersService
    {
    // Import newly generated Web service proxy.
    using WebService;

    class Program
    {
    static void Main(string[] args)
    {
    // Create a new instance of the service.
    Letters ws = new Letters();

    // Use default credentials for authenticating
    // against Microsoft Dynamics NAV.
    ws.UseDefaultCredentials = true;
    ws.Url = “http://localhost:7047/DynamicsNAV/WS/CRONUS%20International%20Ltd./Codeunit/Letters”;

    // Declare variables to work with.
    string inputstring, outputstring;
    inputstring = “microsoft dynamics nav web services!”;

    // Call the Microsoft Dynamics NAV codeunit Web service.
    outputstring = ws.Capitalize(inputstring);

    // Write output to the screen.
    Console.WriteLine(“Result: {0}”, outputstring);

    // Keep the console window open until you press ENTER.
    Console.ReadLine();
    }
    }
    }

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s