Navigate Into Success http://navigateintosuccess.com Ensuring Microsoft Dynamics NAV implementation success since 2003 Sat, 16 Mar 2013 14:01:00 +0000 en-US hourly 1 http://wordpress.org/?v=3.5.1 How Do I… Videos on MSDN http://navigateintosuccess.com/blog/how-do-i-videos-on-msdn http://navigateintosuccess.com/blog/how-do-i-videos-on-msdn#comments Sat, 16 Mar 2013 14:01:00 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1264

imageMSDN has started running a series of the How do I… videos for Microsoft Dynamics NAV 2013 (feed here). The idea is to showcase a technical feature in 5-15 minutes. The project is still ongoing, but a number of videos have just been released and announced on the Microsoft Dynamics NAV Team Blog.

The project is a joint effort by Plataan and Microsoft, and I participated as a technical expert in charge of seven videos. I’ve already recorded five of them, out of which three are online.

You can find the links below, and please come back to this page as I’ll update it as more videos are published.


Deploying Microsoft Dynamics NAV 2013 with System Center 2012 Support
Queries, Reports, and Charts in Microsoft Dynamics NAV 2013
Microsoft Dynamics NAV and Social Media
Getting Up and Running with Microsoft Dynamics NAV 2013

I hope you like the videos, and learn something from them.


Read this post at its original location at http://navigateintosuccess.com/blog/how-do-i-videos-on-msdn, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/how-do-i-videos-on-msdn/feed 5
Transaction Integrity with Connected Systems http://navigateintosuccess.com/blog/transaction-integrity-with-connected-systems http://navigateintosuccess.com/blog/transaction-integrity-with-connected-systems#comments Tue, 05 Mar 2013 11:30:50 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1260

Broken pencilWith .NET Interoperability around, it’s very likely you’ll be synchronously calling external web services from C/AL, to exchange data. I won’t go into discussing whether or not this kind of architecture is good (my own position is that it isn’t), you may end up having situations where your C/AL code simply makes a synchronous call to external systems, such as web services.

Any external call is an expected point of failure. An important question you must always have in mind when calling external functions is transaction integrity. When writing code that targets only NAV, the structure of code is largely irrelevant, as long as you are not using COMMITs (which is another thing you should avoid at all costs). However, as soon as you introduce external calls, the structure becomes critically relevant. Critically relevant.

I’ve talked about this during my 2012 NAV TechDays session, and I promised I’d blog about it – so, here it goes.

Let me start with the rule first: whenever making external calls from C/AL, make sure they are the last thing that’s called in the transaction.

Remember this whenever calling external systems synchronously from C/AL.

Imagine you have another system, let’s call it Bongo, that keeps track of customers. When a customer is created in NAV, it must be created in Bongo. When it’s deleted in NAV, it must be deleted in Bongo.

Now you have this code:

OnCreate()

IF "No." = ” THEN BEGIN
  SalesSetup.GET;
  SalesSetup.TESTFIELD("Customer Nos.");
  NoSeriesMgt.InitSeries(SalesSetup."Customer Nos.",xRec."No. Series",0D,"No.","No. Series");
END;
IF "Invoice Disc. Code" = ” THEN
  "Invoice Disc. Code" := "No.";

IF NOT InsertFromContact THEN
  UpdateContFromCust.OnInsert(Rec);

DimMgt.UpdateDefaultDim(
  DATABASE::Customer,"No.",
  "Global Dimension 1 Code","Global Dimension 2 Code");

 

All red marked lines above are possible failure points – at any of those, a runtime error can stop the execution, and the customer would not get inserted in NAV. The structure really doesn’t matter from the transactional integrity point of view, as all of this is a single transaction, and if any line fails, no data is written to the database.

Imagine that you add this Bongo synchronization now. You can do it like this:

OnCreate()

IF "No." = ” THEN BEGIN
  SalesSetup.GET;
  SalesSetup.TESTFIELD("Customer Nos.");
  NoSeriesMgt.InitSeries(SalesSetup."Customer Nos.",xRec."No. Series",0D,"No.","No. Series");
END;

// Bongo >
CreateInBongo(Rec);
// Bongo <

IF "Invoice Disc. Code" = ” THEN
  "Invoice Disc. Code" := "No.";

IF NOT InsertFromContact THEN
  UpdateContFromCust.OnInsert(Rec);

DimMgt.UpdateDefaultDim(
  DATABASE::Customer,"No.",
  "Global Dimension 1 Code","Global Dimension 2 Code");

 

This new line of code is a new failure point, however, this one is a separate transaction, which has no integration with the transaction in NAV. If this line fails, no problem, as it is just another failure point for NAV. However, if this line succeeds, and it fails at the violet colored line above then you have a problem: the customer, that does not exist in NAV, has just been created in Bongo.

The code should look like this:

OnCreate()

IF "No." = ” THEN BEGIN
  SalesSetup.GET;
  SalesSetup.TESTFIELD("Customer Nos.");
  NoSeriesMgt.InitSeries(SalesSetup."Customer Nos.",xRec."No. Series",0D,"No.","No. Series");
END;

IF "Invoice Disc. Code" = ” THEN
  "Invoice Disc. Code" := "No.";

IF NOT InsertFromContact THEN
  UpdateContFromCust.OnInsert(Rec);

DimMgt.UpdateDefaultDim(
  DATABASE::Customer,"No.",
  "Global Dimension 1 Code","Global Dimension 2 Code");

// Bongo >
CreateInBongo(Rec);
// Bongo <

 

The principle is very simple – you first execute everything in the local transaction. If something fails, Bongo is not even called. If all works locally, the transaction is still waiting for Bongo to complete. If Bongo fails, then the local transaction fails because an error occurred. If Bongo succeeds, the local transaction commits.

Always put the code that targets external systems at the end, never at the beginning or in the middle.

And yes – of course – there is no way to absolutely guarantee the transaction integrity between NAV and Bongo, or whatever it is on the other end. Technically, a web service call can fail on the transport layer, after the transaction has been committed to Bongo, and then your C/AL code structure will not help. Without a transaction coordinator layer somewhere between the systems, you are toast. That’s why I said that synchronous calls to external web services (at least for data replication or exchange goes) are not architecturally good.

However, from time to time, you’ll have to do this for whatever reasons. When you do it, remember these five words: external calls at the end.


Read this post at its original location at http://navigateintosuccess.com/blog/transaction-integrity-with-connected-systems, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/transaction-integrity-with-connected-systems/feed 3
Cross-Call State Sharing in Web Services http://navigateintosuccess.com/blog/cross-call-state-sharing-in-web-services http://navigateintosuccess.com/blog/cross-call-state-sharing-in-web-services#comments Thu, 21 Feb 2013 00:11:52 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1257

imageWeb services in NAV have an interesting feature: they are stateless. For a system which is pretty stateful otherwise, this feature can be outright annoying. You must get used to it, and then make sure you never ever write code as if there was any state preserved on the other end.

The reason for this is simple – there is no actual protocol that you use to communicate with NAV through SOAP. Calls are ad-hoc, essentially atomic, each one can accomplish a great deal of things in a single go, and it makes programming a whole lot simpler. The price you pay is the state. Once you close the connection, the session ends and the transaction commits (or rolls back). Next call starts from scratch.

If you need to preserve any state between the calls, whatever that state might be, you are toast. NAV simply doesn’t support it out of the box. A common misconception is that single-instance codeunits help. They don’t. The single instance is always single per session, and since each call is an isolated session, it means that each single instance codeunit dies at the end of the call.

Pretty annoying, isn’t it?

Well, it is, and it isn’t. I won’t argue about validity of situations where you need to preserve state across multiple web services calls – I am going to show you how to do it when you need it.

And what I’m going to show you works in both NAV 2009 R2 and 2013.

There are a hundred ways to skin a cat (no animals were harmed during writing of this post) and there are possibly as many ways to store state between calls. They mostly depend on non-volatile approaches, such as database, file system or similar. If you ask me, state should be volatile, so how do we accomplish this?

The concept I like to apply here is the one I explained and demonstrated in my Web Services Black Belt session at NAV TechDays 2012 in Antwerp: it’s the static classes in .NET. Static classes, or static members of dynamic classes in .NET are isolated for an application domain and they remain in memory as long as the application is running. Pretty volatile if you ask me. Since NST is a .NET application, keeping a static class in its domain achieves my goal.

Step 1: The Class

I’ll first create a new class in .NET. It must be classic and must have some methods to store and retrieve objects from it. In my example, I’ll use a Dictionary object to store key-value pairs of strings and objects. This allows you to store any simple data type into the State. Here’s the code:

namespace Demo
{
    public static class StateManager
    {
        private static Dictionary<String, Object> _state =
         
new Dictionary<String, Object>();

        public static void Set(string key, object value)
        {
            Clear(key);
            _state.Add(key, value);
        }

        public static Object Get(string key)
        {
            if (_state.ContainsKey(key))
            {
                return _state[key];
            }
            return null;
        }

        public static void Clear(string key)
        {
            if (_state.ContainsKey(key))
            {
                _state.Remove(key);
            }
        }

        public static void Clear()
        {
            _state.Clear();
        }

        public static bool Exists(string key)
        {
            return _state.ContainsKey(key);
        }

    }
}

 

Should be pretty self explanatory. If it isn’t, there is a static private dictionary member that is instantiated on the first access. There are Set and Get methods to store and retrieve anything to and from the state. There is a Clear method which can either remove a single object from the state, or clear all objects. Finally, there is a method to check if an object exists in the state.

Now compile this and deploy it to either Add-ins or GAC. Your choice entirely.

Yeah, yeah, I know, all you .NET ninjas out there – this is not thread safe. Scroll down, it’s our last step. I don’t want to confuse all non-DotNet folks here with unnecessary stuff. First things first.

Step 2: Consuming the Class

Now that we have the class, let’s consume it. I’ll create a new codeunit that provides access to this state. It is nothing but a C/AL wrapper around the C# class above. Here it goes:

Documentation()

OnRun()

SetString(Key : Text;Value : Text)
State.Set(Key,Value);

GetString(Key : Text) : Text
EXIT(State.Get(Key));

SetDate(Key : Text;Value : Date)
State.Set(Key,Value);

GetDate(Key : Text) : Date
EXIT(DT2DATE(State.Get(Key)));

Exists(Key : Text) : Boolean
EXIT(State.Exists(Key));

Clear(Key : Text)
State.Clear(Key);

ClearAll()
State.Clear;

I’m pretty sure that I don’t need to explain what the State variable in the above piece of code is. I’ll say one thing: it’s global (even though it should be pretty obvious, too). I also hope that I don’t need to explain why I have GetString, SetString, GetDate, SetDate functions here. C/AL doesn’t understand the concept of boxing and that’s why you’ll need to create as many Get/Set function pairs as there are data types you want to store. You cannot use variants because they make the codeunit unavailable to web services, and you can’t return a variant from a function.

A funky thing here is that when you box a C/AL Date type into Object, it gets automatically translated into DateTime, but when you unbox it, you cannot directly unbox it into the C/AL Date type. Probably a bug in .NET interoperability, but the workaround is extremely simple, as you can see above.

Save this codeunit, publish it as a web service, and off you go.

Step 3: Implement the State

Let’s take a real-life scenario: work date. In Web services, work date always defaults to current system date. Sometimes, especially in page web services, in relation to, for example, number series, this can be pretty annoying. Let’s use our state manager to make web services use a different work date for page calls.

I’ll first add the SetWorkDate and ApplyStateWorkDate functions to the state manager codeunit:

SetWorkDate(Date : Date)
SetDate(Text_STATE_WORKDATE,Date);

ApplyStateWorkDate()
IF Exists(Text_STATE_WORKDATE) THEN
  WORKDATE := GetDate(Text_STATE_WORKDATE);

Here, you only need to declare a text constant with a unique value that you use as a key to store the date in the state manager.

Then, in the page you want to make use the work date from the state, modify the OnInit trigger to include this piece of code:

StateMgt.ApplyStateWorkDate;

 

I’ll use the SalesOrder page (42).

Step 4: Verifying the State

Next step is to verify that this works. So, publish the page 42 (or whichever one you wanted to use) as a web service, and from your consumer application, call the state manager codeunit web service first to set a work date to some value, and then call the sales order page web service to create a new sales order. This is my demo code, you might need to tweak it left or right:

var state =
    new StateManagement
        {
            UseDefaultCredentials = true,
            Url =              "
http://localhost:7147/DynamicsNAV70/WS/CRONUS International Ltd./Codeunit/StateManagement"
        };
state.SetWorkDate(new DateTime(2011, 10, 10));

var salesOrderSvc =
    new SalesOrder.SalesOrder_Service
        {
            UseDefaultCredentials = true,
            Url =
"
http://localhost:7147/DynamicsNAV70/WS/CRONUS International Ltd./Page/SalesOrder"
        };

var salesOrder = new SalesOrder.SalesOrder();
salesOrderSvc.Create(ref salesOrder);

MessageBox.Show(salesOrder.Document_Date.ToString());

Now, run it and admire it. It first stores October 10, 2011 as your work date, and then creates a sales order on this date. Pretty fly for a web service call.

Step 5: Thread safety, and other ninja stuff

If you’ve made it this far, you must speak both C/AL and C# fluently and you have been keeping that “yes, but…” for quite a while. As I mentioned earlier – this stuff is not thread safe.

Thread safety is something that, before .NET Interoperability, you never had to worry about in C/AL. Now, you must worry about it whenever writing your own classes intended for consumption from C/AL. You also must worry about it when consuming thread-unsafe third-party assemblies, which is a story for another post.

In short – thread safety is a concept that applies to situations when multiple threads are accessing the shared piece of data. Since NAV Service Tier is a heavily multi-threaded application, and since static classes are shared data, you must make all of your static classes thread-safe.

There are many different approaches to achieving thread safety. The simplest is to synchronize access to shared data through locks. Simply lock the _state variable before each access, and you are good. For example, instead of the code above for Set and Get methods, write this:

public static void Set(string key, object value)
{
    lock (_state)
    {
        Clear(key);
        _state.Add(key, value);
    }
}

public static Object Get(string key)
{
    lock (_state)
    {
        if (_state.ContainsKey(key))
        {
            return _state[key];
        }
        return null;
    }
}

Of course, do this for all methods that access the _state variable.

Another possibility you have here is to use the ConcurrentDictionary class of .NET Framework 4.0 and above, but this is applicable only to NAV 2013.

Just remember – your static classes, and classic members of your dynamic classes, must be thread safe. If they are not, see for yourself what happens. Hint: it doesn’t work.

And in the end…

And now that you reached this far, let me say that yes – I am still alive, and no – I didn’t stop blogging or have any intentions of stopping blogging. Over last year I was pretty busy writing content for NAV 2013 courseware, and this year I started doing some very similar stuff, which I’ll soon also blog about. The point is – I’m here, I’m glad that you are here, too, and I’ll blog whenever I get a chance about stuff that I believe is relevant. Stay tuned, and see you around.


Read this post at its original location at http://navigateintosuccess.com/blog/cross-call-state-sharing-in-web-services, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/cross-call-state-sharing-in-web-services/feed 8
Some tips and hints about temporary tables http://navigateintosuccess.com/blog/some-tips-and-hints-about-temporary-tables http://navigateintosuccess.com/blog/some-tips-and-hints-about-temporary-tables#comments Thu, 01 Nov 2012 10:26:53 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1253

MP900433071[1]Temporary tables in NAV are a great thing, and are frequently used, but there are some misconceptions about them. I see developers do the same mistakes time after time and again. In this post I’ll address some common misconceptions and give some tips and hints that you can use in practice.

There may be a lot of basics for you here, in which case just skip to the end: there I give you a nice tip about how to prevent accidental changes to physical tables when you expect that a table is temporary, and in fact it is not.

A temporary table is a record variable on which you have set the Temporary property to Yes. When you do this, the record variable has the same structure as the physical table, but it is only stored in memory. When you create a temporary record variable, the temporary table is empty at first, and then you can insert, modify, or delete data in it at will, and it does not affect the physical table. I’m quite sure you knew this much, but I repeated it here just to show you how smart I am Smile with tongue out

Temporary Tables in Function Parameters

One thing that is frequently done is passing around temporary tables to functions as parameters. What often goes wrong here is that people tend to think that inside the function the table is temporary because the variable passed to it is temporary. In fact – it’s not. Or at least not always.

First thing to know about record variables is that a record variable does not represent the whole table. It only represents as much as it says on the tin: the record – or to be as precise as it gets – a single record (row) in a table. The Temporary property is simply telling you where the runtime will store the changes you make if you call any of the data modification functions, or where it will look for more records if you iterate through data or run any of the FIND functions.

Another piece of theory is about function parameters. A parameter can be by value or by reference. By value means that the runtime establishes a new in-memory space for the parameter and when you call the function the value of the variable (or constant, or expression) passed to the function is copied into this freshly allocated memory space – literally you get a copy of the original value. By reference means that the runtime literally takes the variable into the function and the parameter is merely another name tag attached to the same variable that was passed to the function.

Last piece of theory here is about record type as a function parameter. When declaring a parameter of type record, you can set its Temporary property to Yes or No, as with any other record variable.

If you combine the last two theory bits, about parameters, and about record type, you may believe that you have these four combinations:

  • Record, by value
  • Temporary record, by value
  • Record, by reference
  • Temporary record, by reference

In fact, you don’t. There are only three combinations:

  • Record by value
  • Temporary record by value
  • By reference

The first two are simple: if the parameter is by value, then the Temporary property on the parameter determines whether within the function the table will be temporary, or physical.

Check this out:

image

Within the first two functions, the actual state of the Cust record is determined by the Temporary property set on the parameter. If you pass a physical record variable to DoSomething_Temporary, the field values of that physical record will get copied to the Cust record, but the Cust will continue to be temporary.

Just as if you did this: Cust := Customer_Physical;

The same applies if you call DoSomething_Physical and pass the Customer_Temporary to it. The field values are copied, but Cust refers to the physical table.

Furthermore, when you have Temporary set to Yes on a by-value parameter, that temporary table is always empty when the function is called. Just as if you declared a local temporary record variable. That’s because the runtime first establishes a new memory space for the by-value parameter.

So, this covers the first two cases. Now for the third case.

If the record parameter is by reference, then the Temporary property makes absolutely no difference. These two are essentially equal:

image

When you pass a variable by reference, you don’t allocate new memory space: you simply pass the whole variable. The Temporary property is then taken from the variable, regardless of what you set as the Temporary property on the parameter itself. If you pass a physical table to a temporary by-reference parameter, the parameter record within the function is physical. Also, if you pass a temporary table to a non-temporary by-reference parameter, the parameter record within the function is temporary.

Not understanding this may have devastating effects on your data. Imagine this:

image

This deletes all of your customers from the physical table (those in the filter, at least). The Temporary property had no effect – you have passed the whole variable including all of its properties, including Temporary.

Therefore, setting Temporary on a by-reference parameter makes absolutely no difference. Never forget this.

Temporary Records and Transactions

Another misconception about temporary records is that they are managed as transactions. They are not. When you call COMMIT, it does not affect your temporary tables. Also, if you call ERROR, it won’t rollback any inserts, changes, or deletions from your temporary tables.

There is not much rocket science around this, really.

SourceTableTemporary

The SourceTableTemporary property on pages (or forms in 5.0 and 2009) allows you to run pages that only work over temporary data. When you run them, they are empty, and then you need to populate them with data. You do that by simply filling in the data in the Rec variable.

One typical problem I’ve frequently seen with pages (or forms) over temporary data, is that the Rec variable is passed by reference, and then iterated over. That’s not the smartest thing in the world. In certain versions of clients, this may cause phantom inserts – if you are positioned on the new row, and then call a function which iterates over a range of rows to do something, and then leaves the row positioned on an actual row.

For example:

image

Let’s set the phantom inserts aside for a while, and just apply a simple trick here that works – and should always be done anyway – with physical tables as well: when entering a function where a record variable is passed by reference, store the position of the current record, and when exiting the function, restore the record to its original position:

image

By Reference – How to Know Temporary from Physical?

And finally, for the tip: when in a function that receives a record variable by reference, how do you know if the record is temporary or physical? You may “know” that your function will always be called with temporary record (or you may set its Temporary property to Yes to “ensure” it) but in fact for by-reference whether it’s temporary or not is determined by the actual variable. So, don’t do something crazy like this and delete your G/L:

image

You know by now that the GLEntryTemp record may – or may not!! – be temporary. Instead of populating the physical G/L Entries into a temporary table, you may end up deleting all of the entries from the actual, physical G/L Entry table. Probably not something you’d want to do on your regular Thursday.

To avoid headache, just do a simple sanity check:

image

You simply create a record reference over the parameter, and then check its ISTEMPORARY property before you do anything crazy with those physical tables.

So – I hope this was useful and helpful. If not, just feel free to boo me publicly here.


Read this post at its original location at http://navigateintosuccess.com/blog/some-tips-and-hints-about-temporary-tables, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/some-tips-and-hints-about-temporary-tables/feed 7
Web Services Black Belt: consuming NAV web services using pure C/AL http://navigateintosuccess.com/blog/web-services-black-belt-consuming-nav-web-services-using-pure-cal http://navigateintosuccess.com/blog/web-services-black-belt-consuming-nav-web-services-using-pure-cal#comments Sun, 30 Sep 2012 20:23:29 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1233

MP900406779[1]Have you ever needed to connect to the Web services of one NAV instance from another one? If so, I bet that the approach was something like this: you created a .NET class where you defined a Web or Service reference to the target instance, and then you consumed that .NET class using .NET Framework interoperability. It was kind of clumsy, inflexible, but it worked.

How cool would it be if you could do something like this:

WITH WebService DO BEGIN
  CONNECT(‘http://localhost:7047/DynamicsNAV70/WS/CRONUS%20International%20Ltd/Page/Customer’);

  INIT;
  SETVALUE(‘Name’,'Test Customer’);
  SETVALUE(‘Blocked’,Cust.Blocked::Ship);
  SETVALUE(‘Credit_Limit_LCY’,10000);
  CREATE;

  MESSAGE(‘I just created Customer No. %1 in another NAV instance.’,GETVALUE(‘No’));
END;

As a matter of fact, you can write something like that. You can write exactly that. And it compiles, runs, and accomplishes exactly what you expect it to do. The most beautiful thing, you don’t need to write a single line of code in Visual Studio, or deploy any external dependencies – it uses pure C/AL, and works equally well in NAV 2009 and NAV 2013.

The only thing you need is a simple codeunit that you can download from Mibuso. If you missed the link in the previous sentence, then click here.

I wrote that codeunit as a part of the demo I presented last Wednesday at Mibuso NAV TechDays 2012 in Antwerp, and as promised – I am making the code available for you to use.

This simple codeunit does no magic, it simply harnesses the power of the features built into the .NET Framework. It builds the proxy class and compiles it on the fly, and then uses reflection to instantiate objects, set properties, and call methods to allow you to interact with any NAV page web service.

Before you can consume a NAV page Web service from C/AL you do not need to know anything about the service, except for its URL. If it’s a page web service, you can use it to read, create, update, and delete data in another NAV instance, simply using C/AL.

At this stage, it supports the following page web service functions:

  • Read
  • ReadMultiple
  • Create
  • CreateMultiple
  • Update
  • UpdateMultiple
  • Delete

Right now, I am providing no documentation for it, but I believe it should not be difficult to figure out what it can do by following these couple of examples.

Creating a customer

That’s the example above. Just declare a variable named WebService of type Codeunit 50113, and you are good to go.

Iterating through a set of customers read, with a filter applied

WITH WebService DO BEGIN
  CONNECT(‘http://localhost:7047/DynamicsNAV70/WS/CRONUS%20International%20Ltd/Page/Customer’);
  SETFILTER(‘Balance_LCY’,'>0′);
  SETFILTER(‘Name’,'A*’);
  IF READMULTIPLE THEN
    REPEAT
      MESSAGE(‘Customer %1 %2 has balance of %3′,GETVALUE(‘No’),GETVALUE(‘Name’),GETVALUE(‘Balance_LCY’));
    UNTIL NEXT = 0;
END;
EXIT;

Updating an item

WITH WebService DO BEGIN
  INIT;
  SETVALUE(‘No’,’1000’);
  READ;
  SETVALUE(‘Description’,’Bicycle 2’);
  UPDATE;
END;

Creating a purchase order from a sales order

WITH WebService DO BEGIN
  CONNECT(‘http://localhost:7047/DynamicsNAV70/WS/CRONUS%20International%20Ltd/Page/PurchOrder’);
  INIT;
  SETVALUE(‘Buy_from_Vendor_No’,Rec."Sell-to Customer No.");
  SalesLine.SETRANGE("Document Type",Rec."Document Type");
  SalesLine.SETRANGE("Document No.",Rec."No.");
  IF SalesLine.FINDSET THEN
    REPEAT
      NEWLINE;
      SETLINEVALUE(‘Type’,FORMAT(SalesLine.Type));
      SETLINEVALUE(‘No’,FORMAT(SalesLine."No."));
      SETLINEVALUE(‘Quantity’,SalesLine.Quantity);
    UNTIL SalesLine.NEXT = 0;
  CREATE;
  MESSAGE(‘Purchase Order No. %1 is created in the vendor”s system.’,GETVALUE(‘No’));
END;

I’ll be updating the functionality of this codeunit and uploading a more comprehensive version, as I find time to do this.

This post is a series of posts where I’ll present most of the stuff I talked about at NAV TechDays 2012, and expand those topics into the areas that I either had to leave out due to time constraints, or that I thought were not as interesting as those that I chose to put into the presentation.

Please, let me know how you like this small gadget.


Read this post at its original location at http://navigateintosuccess.com/blog/web-services-black-belt-consuming-nav-web-services-using-pure-cal, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/web-services-black-belt-consuming-nav-web-services-using-pure-cal/feed 20
Benchmarking Results: NAV 2013 Outperforms All Previous Versions http://navigateintosuccess.com/blog/benchmarking-results-nav-2013-outperforms-all-previous-versions http://navigateintosuccess.com/blog/benchmarking-results-nav-2013-outperforms-all-previous-versions#comments Mon, 25 Jun 2012 06:50:00 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1223

imageMarketing is nice as long as it matches the reality. With Microsoft Dynamics NAV 2013, Microsoft has promised a lot of improvements, but how well does NAV 2013 stand the reality test?

Apparently, outstandingly well.

Over the past two days, I have intensively tested NAV 2009 and NAV 2013 through a series of five different tests that measure different aspects of NAV data handling. My conclusion is clear: NAV 2013 is faster than any NAV you have ever seen, including the Classic client on the native database.

Continue reading to find out more about my findings and testing approach.

Is This Some Kind Of A Trick?

No, this is not a trick. It’s for real.

Several days ago I wrote about performance improvements in Microsoft Dynamics NAV 2013, and then got a comment that it all looks nice in theory, but that NAV 2013 is actually slower than NAV 2009. Per Mogensen of Mergetool.com has done some testing and published a video demonstrating the results.

I’ve reviewed the video, and I’ve noticed a couple of possible issues with how the performance was measured, so I decided to do check for myself. My results show something completely different: not only NAV 2013 is faster than NAV 2009, it’s also faster than the Classic client on the native database – kind of a holy grail of NAV performance.

And then I double-checked with Per, and he confirmed to me that he also noticed a couple of problems himself. He has repeated the tests, and his tests now also show great improvement in NAV 2013. His updated video is here.

But, let’s continue with my results.

The Racing Horses

To find out how fast NAV 2013 really is, I’ve compared it to other flavors of NAV. The racing horses were:

  • Microsoft Dynamics NAV 2013 RoleTailored Client
  • Microsoft Dynamics NAV 2013 Web Services
  • Microsoft Dynamics NAV 2009 RoleTailored Client
  • Microsoft Dynamics NAV 2009 Web Services
  • Microsoft Dynamics NAV 2009 Classic Client – SQL Server Option
  • Microsoft Dynamics NAV 2009 Classic Client – Native Database Option

So, quite a jolly bunch. I would love if I could also have tested the performance of 2009 NAS on both native database and SQL Server, but I chose to let it pass.

The Environment

All of the applications have had exactly the same operating conditions, under exactly the same environment and system configuration settings. The following are the system specifications:

  • Intel Core i7-2620M CPU (Quad Core)
  • 8 GB of RAM
  • OCZ Vertex2 SSD drive
  • Windows 7 Ultimate, Service Pack 1, 64-bit
  • Microsoft SQL Server 2008 R2, Standard Edition, 64-bit

The machine was physical, not virtual. All flavors of NAV were installed on the same physical instance.

The Tests

All of the six applications had to endure the same testing conditions, and have run the following tests:

  • Creating, releasing, shipping and invoicing a sales order, 100 times in a row (the original Per Mogensen’s test)
  • Iterating through all customers, vendors, and items, 500 times in a row
  • Iterating through a filtered list of customers, vendors, and items, with an inefficient filter over a text field, 500 times in a row
  • Iterating through a unique list of G/L accounts from the G/L Entry table, 500 times in a row.
  • Manually summing flow fields of all customers, vendors, and items, by calling CALCFIELDS on each row, 500 times in a row.

In addition, under NAV 2013 I’ve run the following test as well:

  • Manually summing the balance and inventory flow fields of all customers, vendors, and items, respectively, by calling SETAUTOCALCFIELDS before the iteration, 500 times in a row.

The Methodology

Before each of the tests, I prepared the environment by doing the following:

  • I stopped all instances of NAV and closed all clients and made sure no applications were running.
  • I created a new empty database.
  • I restored the W1 database into the just created database.
  • I started the relevant service tier and clients, and then ran all the tests three times to warm the system up.
  • I cleared the time logs to eliminate the warm-up results, and make sure they don’t distort the test results.
  • Closed any unnecessary applications (e.g. the Classic Client before using the RTC to run the tests) to ensure that only the environment which is running the test is open.

Then, after the environment was ready, for each of the tests I did the following:

  • Ran the test three times in a row.
  • Copied the results from the log table into Excel.

The warm-up is indeed slower under NAV 2013, than under any other system, and my methodology disregarded the warm-up measurements. Warm up times mostly don’t show anything useful.

Each of the tests records the time right before the test starts, and then again right after it ends. The time difference is then logged into the database.

I measured the time by creating two DateTime instances, setting them to current system time, then subtracting the start time from the end time. This gives the duration in milliseconds. In addition to this, under NAV 2013 I’ve added another measurement method: the .NET System.Diagnostics.Stopwatch class, just in case – if there is anything flawed with NAV’s time variable in 2013, certainly nothing will be wrong with the .NET Stopwatch. As expected, there was no difference between what NAV calculated and what the System.Diagnostics.Stopwatch measured.

In the results, all measurements I present are in milliseconds, and in all test results I’ll show, less is better.

The Results

Finally, we get to the point which I believe you await as much as did I: the results. Let me present them test by test.

1. Sales Orders

In the Per Mogensen’s tests, the NAV 2009 Classic Client on a native database is the winner of this test. At pure C/AL level, NAV 2013 there performs almost as fast as Classic on native, but the RTC under NAV 2013 is still the slowest. My results are very different. I can’t be 100% sure why, but I’ll give a couple of thoughts at the end of this post.

In any case, these are the measurements I got:

2013, Web Services

5,169

2013, RoleTailored Client

6,186

2009, Classic Client, Native

7,467

2009, Web Services

11,778

2009, Classic Client, SQL

14,420

2009, RoleTailored Client

14,690

 

A picture is worth a thousand words, so here it comes:

image

Image 1: Sales Orders test results

As I expected, the Web Services perform faster on both 2009 and 2013, because there is no user interface and only the NST is involved in code execution. Under Web Services, NAV 2013 performs about 44% faster than the fastest breed of NAV ever – the Classic Client on a native database. Stripped off the burden of a UI, NAV 2013 Web Services practically demonstrate pure SQL Server performance, and SQL Server is faster than ever before, just as it says on the tin.

But NAV 2013 RTC also showed respectable performance. It performed 21% better than NAV 2009 Classic Client on native database. I kind of didn’t expect this to occur, because the Classic Client on native database is a native ISAM system and NAV business logic is entirely optimized to fly on it. What astonishes me is 128% improvement of NAV 2013 over NAV 2009 in Web Services, or 137% improvement in RoleTailored Client performance. That’s truly amazing.

Obviously, NAV 2013 provides considerable improvement over NAV 2009.

2. Repeated Read

This test measures the capability of a client to iterate through a series of records. Iteration is something that C/AL code frequently does, and where any flavor of NAV somewhat sucked under SQL Server, as compared with the sheer performance of the native database. Again, native database and C/AL as a language are optimized precisely for this kind of access, and it was never a wonder that the native was a king here.

However, NAV 2013 seems to have just deposed that king:

2013, Web Services

16

2013, RoleTailored Client

25

2009, Classic Client, Native

644

2009, Web Services

8,081

2009, RoleTailored Client

8,133

2009, Classic Client, SQL

8,637

 

Graphically, this is how it looks:

image

Image 2: Repeated Read of Customers, Vendors and Items

NAV 2013 is lightning fast here, and no wonder why: the caching. While NAV 2009 on SQL Server had to maintain a series of cursors, NAV 2013 ran a single T-SQL query, and then cached the records for subsequent reads. It simply outperforms everything.

I don’t want to spend any time comparing the speed of NAV 2013 with the speed of NAV 2009 native; what I want to do is point out the speed improvement by a factor of more than 400x over NAV 2009 on SQL. How cool is that?

3. Repeated Read of Filtered Tables

The beauty of this test is that it shows how well a system copes with a complex filter. I’ve set the filter on Name and Description columns on Customer, Vendor and Item table respectively to this: @*a* (it searches for letter a anywhere in the field, in a case-insensitive way).

This filter can’t make meaningful use of any key, so what shall win or lose this race will be the capability of the database management system to handle such a process on foot.

Again, NAV 2013 played this one coolly.

Here go the results:

2013, Web Services

20

2013, RoleTailored Client

24

2009, Classic Client, Native

515

2009, Web Services

5,720

2009, RoleTailored Client

5,741

2009, Classic Client, SQL

6,178

 

This is the graph:

image

Image 3: Repeated Read of Filtered Tables

While the variances in NAV 2009 SQL Server flavors are insignificant, the improvement of NAV 2013 is again verging with insane. It’s obvious that the cache kicked in here bit time, but I also assume that there may be some .NET-level code optimization that made this kind of thing possible.

4. Reading Unique G/L Account Numbers from G/L Entry

Now, this was a tricky one. It uses several concepts, combination of which is a total no-brainer for the ISAM-based NAV 2009 on native, but verges on rocket science for anything SQL-related. It was literally the most inefficient thing to do to a SQL database in NAV, and running a piece of code such as this literally smothers SQL by causing it to drop existing and create new cursors all the time.

The algorithm is as follows:

  1. Set the key on G/L Account column
  2. Find the first G/L Entry row
  3. Set a filter on the G/L Account column to that G/L Account which is currently selected
  4. Find the last G/L Entry with this filter applied
  5. Remove the filter on the G/L Account column
  6. Repeat 3 to 6 until there are more G/L Entry rows

In previous versions, steps 2, 4, and 6 drop existing (except for the first iteration) and create new cursors in SQL Server, and I was curious to find out how well SQL coped with this task now that cursors are gone, and MARS is taking their role. There are much less read rows in this test than in the simple repeated read, and if you understand how ISAM works, and how SQL works, you should also expect ISAM to do this with no speed penalty over a simple iterative read, while you can expect SQL to run way slower than a simple iterative read, no matter which approach it takes.

And this is exactly what the results show:

 

2009, Classic Client, Native

478

2013, Web Services

1,129

2013, RoleTailored Client

1,142

2009, Web Services

11,029

2009, RoleTailored Client

11,113

2009, Classic Client, SQL

11,555

 

And then, the picture:

image

Image 4: Repeated Read of SIFT-Filtered Tables

Now, before jumping out from your seat and shouting “gotcha!”, think of this test once again. NAV 2013 is almost 10x faster than NAV 2009 here, and whatever it did deep there in its engine is close to a miracle. If it did caching to attain this speed, that caching must be pretty smart, because this piece of code was accessing some very small sets and jumping around the records like crazy.

While I have a very plausible explanation what made NAV 2013 win all previous tests, I don’t have a faintest idea what kind of magic made it perform this well here. Yes, it is slower than native, but this was kind of like making a Formula One compete in a rally.

Catch this: native is fully optimized to do this kind of access, and doing this is no smarter for it than doing the simplest kind of data iteration. As a matter of fact, since there were less rows to read, this one should have been faster than the repeated read test. And it was. At the same time, NAV 2009 on SQL was slower here, because this put much more pressure on it, and it had to struggle. And struggle it did.

Yet, NAV 2013, while still struggling, has shown an incredible performance improvement to make even this kind of thing perform well. Quite a job, Microsoft!

5. SIFT Read

I measured how various systems perform with SIFTs, in a scenario quite common in real life: iterating through a set of data and calculating flow fields for each row. NAV does this in many situations, and I was very curious to find out how fast NAV 2013 would be here, because of the many changes Microsoft has done in handling the flow fields in NAV 2013.

Here are the results:

2013, RoleTailored Client

1,517

2013, Web Services

1,518

2009, Classic Client, Native

1,638

2009, Web Services

9,500

2009, RoleTailored Client

9,552

2009, Classic Client, SQL

9,745

 

Or graphically:

image

Image 5: SIFT Read

When handling flow fields, NAV 2013 performs slightly better than native ever did, about 8% faster. This is quite a feat, if you have in mind that native handles this functionality again, well, natively, by building the flow field information right into indexes, something that SQL never could.

Okay, I assume that some serious caching took place here as well, but still, caching or not, the whole system performs better and faster in NAV 2013. Compared to SQL Server flavors in NAV 2009, the improvement of 532% is quite amazing, and even more so if you think that probably everybody thought that Microsoft has hit the limit with replacing SIFT tables with indexed views in 5.0 SP1. With that obviously not having been a limit at all, I now wonder shall we experience even more improvement here in the future?

5a. SETAUTOCALCFIELDS

Finally, I ran the same test as the previous one, with the SETAUTOCALCFIELDS. I expected serious improvement, but at average of 1,466 milliseconds, this test performed practically only insignificantly faster than the previous one. I expected this one to show the real improvement over the traditional CALCFIELDS approach, but it stubbornly declined. I can’t explain this, but hey, let’s not get too picky Smile

Overall Results

When you add all of the figures above together, the cumulative results demonstrate that Microsoft Dynamics NAV 2013 outperforms its previous incarnations, including the so-far unbeatable Classic Client on a native database.

On average, this is what it took the three clients to execute all tests:

2009 SQL

48,636

2009 Native

10,743

2013

8,374

 

And the last picture of the day:

image

Image 6: Overall Results

Obviously, the improvements that NAV 2013 promises are not just plain words, as these test results show. The overall performance is about 28% better than with the NAV 2009 Classic Client on a native database, and about 480% better (that’s almost 6x performance improvement!) than with NAV 2009 under SQL Server.

However, this is only a part of the story. There is another one: concurrency. Performance is always welcome, but performance is not what has been preventing NAV to scale as much as, for example, AX could. I wonder if Microsoft will release a hardware sizing document that would estimate some kind of the upper limit for vertical scalability of NAV 2013. The last time we got such numbers from Microsoft was with version 5.0 SP1, when it was set at 250 concurrent users.

Of course, any estimates of the kind are comparing apples to oranges, anyway, because at that number of users, the application is probably always heavily customized, and the actual upper vertical scalability limit will invariably depend on a very complex set of parameters, and can be determined only on a case-by-case basis.

I would’ve loved to have done concurrency tests together with the performance tests, but I may do that another time. However, based on the figures I see here, I dare estimating that everything else being equal, concurrency levels can at least be doubled in any given NAV 2013 deployment, over an equal NAV 2009 deployment.

But What About The Other Test?

So, why do Per Mogensen’s test show somewhat different results? On the C/AL level, hist test is very consistent with my measurements with Web services, but in Per’s tests, NAV 2013 performance with RTC is still inferior to all other clients and platforms.

I can’t tell for sure, but I’ll give my best guess:

  • Virtualization: The systems were comparable, but the tests were run under different virtual machines, and the virtual hypervisor in charge might have redistributed resources, or other virtual machines were doing some cleanups while NAV 2013 was running, or a whole range of other things might have happened.
  • Hardware: The RTC is a .NET application, and depends a lot on hardware on a machine to execute all the things that .NET applications do: just-in-time compilation during warm-up, and talking to video drivers at run time. Since it was a virtual box, maybe the virtual hardware causes troubles with .NET applications talking to it, while it performs better when Win32 applications (as the Classic client) are talking to it.
  • Warm-up: While it certainly should be enough to run 100 sales orders through the create-release-ship-invoice cycle to warm a system up, I still think that a thorough warm-up is required for any kind of benchmarking. The warm-up time itself should be disregarded as it is no measure of either real performance under pressure, or the scalability. To determine if the system is properly warmed up, you need to keep running warm-ups until you see no significant performance between the two runs. Only then you can start measuring. The minimum number of runs to determine this condition is three runs.

Don’t Take My Word For This

So, who do you trust, Per or me? Neither one! Please, don’t just take my findings for granted. Do the measurements yourself.

Here, I’ve attached the objects that I’ve used to run the benchmark, so you can run the same tests on your own machine, and see your own results. I am really curious about the results you’ll get.

So, download the objects:

The reason why there are three distinct sets of objects is that NAV 2013 uses .NET Interoperability in addition to system time to measure time, and that native doesn’t use role centers. Everything else is exactly the same.

(Just in case you need it, here is also my Excel sheet with testing results and charts.)

Run the tests, and then come back here and share your findings. I’d love to hear from you!


Read this post at its original location at http://navigateintosuccess.com/blog/benchmarking-results-nav-2013-outperforms-all-previous-versions, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/benchmarking-results-nav-2013-outperforms-all-previous-versions/feed 32
Top 5 SQL Server Improvements in NAV 2013 http://navigateintosuccess.com/blog/top-5-sql-server-improvements-in-nav-2013 http://navigateintosuccess.com/blog/top-5-sql-server-improvements-in-nav-2013#comments Thu, 21 Jun 2012 20:13:05 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1202

imagePerformance is one of those things you can’t get enough of and NAV is one of those systems where an extra operation per second is always welcome. Yesterday, during the Expert Panel at the NAV day of the Decisions Spring conference, there was a question: is there any improvement in how NAV 2013 works on SQL Server.

And the answer is: oh yeah!

As a matter of fact, everything is new and improved.

Jörg has already posted an overview of the news of NAV on SQL Server in his last blog post, but I still think there’s room for a couple of more words on the really amazing palette of news and improvements.

As I said, the SQL Server improvements are plenty. Here’s the list of the top 5 technical improvements that rock my boat.

1. Cursors are gone

If there was a single thing that was killing performance in NAV, that was server-side cursors. The burden on SQL Server, especially in critical multi-user environments was tremendous, and I’ve seen server monsters crawling under pressure. The cursors are replaced with MARS (Multiple Active Result Sets), which basically take the browsing through recordset chore away from the SQL and assign it to the NST.

2. Caching

Apart from MARS, another killer improvement is the caching. Most of data access operations are cached on the NST, which results in a considerable reduction in the number of SQL Server calls. Now, caching alone is a great improvement, but caching + MARS is a winner.

Try profiling a simple thing, such as this:

IF Cust.FINDSET THEN

  REPEAT

  UNTIL Cust.NEXT = 0;

Run it a couple of times in a row. Under NAV 2013, you get a single SELECT against the SQL Server, then nothing else. The iteration happens on the NST, and every consecutive call to the same stuff does everything on the NST. Try that under NAV 2009, and the profiler goes bananas.

3. SIFTs

There are several improvements in how NAV 2013 handles SIFTs. First – you don’t have to explicitly declare SIFT fields on keys. You can do CALCFIELDS and CALCSUMS on any decimal field, regardless of the structure of keys on the source table. And SQL simply calculates the value. This relieves SQL from maintaining too many indexed views. Yes, I know, it also slows the read operations slightly, but did I mention the caching? Oh, sorry, I have. There.

Another improvement is that you can include the SIFT fields into the SQL statement, and get the SIFTs with the same single SELECT statement that NST issues against SQL. You do this with the SETAUTOCALCFIELDS statement which you call on a record variable just before you FIND or FINDSET the records.

Compare these two in the profiler, and it’s clear right away:

a) with CALCFIELDS

IF Cust.FINDSET THEN

REPEAT

// Balance is not calculated, we have to do it manually

Cust.CALCFIELDS(Balance);

UNTIL Cust.NEXT = 0;

b) with SETAUTOCALCFIELDS

Cust.SETAUTOCALCFIELDS(Balance);

IF Cust.FINDSET THEN

  REPEAT

    // No need for CALCFIELDS, Balance is returned already

  UNTIL Cust.NEXT = 0;

With the option a, whenever you hit the CALCFIELDS, the NST obeys and fetches the sum. With the option b, there is a single SELECT statement, which already includes the OUTER APPLY clause, which calculates the SUM for each row retrieved.

Pretty cool stuff.

4. ADO.NET

The whole shebang is now run on ADO.NET, instead of OLEDB/ODBC that it was before. There are plenty of benefits of that, performance included.

ADO.NET streamlines deployment and administration, increases performance, reduces the number of SQL connections (Jörg has explained some drawbacks of this access, but I think generally that this is a good thing), reduces the memory consumption, and maybe a couple other things.

5. Unicode

I’ve already blogged about this, Jörg has also mentioned this, so I won’t play the same tune yet another time. NAV is now Unicode, which allows you to store characters in any language, at the same time.

Unfortunately, Unicode is not as Unicode as I’d truly love it to be, because the object captions remain tied to the chosen database collation (yes, you still need to choose this). That practically means that while you’ll be able to store characters from any alphabet, your RTC user interface will remain limited to a single character set.

Wrap up

So, to wrap it up, there is a lot of new things, bigger or smaller, that have been changed and that warrant better performance, or user experience, or both.

You may notice that I didn’t mention queries. Yes, they are a mind-boggling improvement over previous versions, but they are simply a completely new feature, not something that NAV had, and now has better than before. My list here is the list of tweaks and tune-ups that take those things that we are used to have to a new level altogether. Queries? Well, they are out of this world, but their true power is yet to come – when (I’m kind of sure it’s about “when”, not “if”) we’ll be able to use them as sources for pages or reports.


Read this post at its original location at http://navigateintosuccess.com/blog/top-5-sql-server-improvements-in-nav-2013, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/top-5-sql-server-improvements-in-nav-2013/feed 20
NAV Expert Panel Session Begins http://navigateintosuccess.com/blog/nav-expert-panel-session-begins http://navigateintosuccess.com/blog/nav-expert-panel-session-begins#comments Wed, 20 Jun 2012 11:53:19 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1198

imageI’m right now sitting in the virtual lobby of the NAV Expert Panel Session of the NAV day of the Decisions Spring 2012 conference. The panel features three MVPs, three book authors, and established members of the NAV community: Eric Wauters, Matt Traxinger, Steven Renders, Brent Fisher and myself.

With Microsoft Dynamics NAV 2013 beta out and a lot of partners having laid their hands on it, I assume the discussion will develop around NAV 2013 topics.

I don’t know how much time I’ll have during the session, because I’ll probably be busy answering questions, but I’ll be tweeting live from the session, so if you don’t have an opportunity to join the conference, you can still stay in the loop by following me at @vjekob, or follow the conference hashtag #msdwdecisions.


Read this post at its original location at http://navigateintosuccess.com/blog/nav-expert-panel-session-begins, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/nav-expert-panel-session-begins/feed 2
Decisions Spring 2013 Kicking-off Next Week http://navigateintosuccess.com/blog/decisions-spring-2013-kicking-off-next-week http://navigateintosuccess.com/blog/decisions-spring-2013-kicking-off-next-week#comments Thu, 14 Jun 2012 07:45:21 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1194

imageMake sure not to miss Decisions, the virtual conference about Microsoft Dynamics, by MSDynamicsWorld.com. It’s starting next Monday, and I hope you already have it in your calendar. It’s a four day conference, a day per Dynamics flavor (SL is the only one not being served). The best of all – it’s free! Be there.

The Microsoft Dynamics NAV day is on Wednesday, June 20, and it’s featuring a program manager from Microsoft, three MVPs, (at least) three book authors, and a team of seasoned professionals in a series of interesting presentations.

Just like the previous years, I’ll be speaking there myself, and if you would like to join me for an excursion into the world beyond ERP, where several disruptive trends are shaping the future of the IT, and consequently the ERP. I’ll take an angle at the challenges the present and the future bring, and how Microsoft Dynamics NAV faces them, copes with them, and plays along. I promise it’ll be time well spent.

The conference is virtual, so you can attend it in your slippers, I won’t mind. See you in the cloud!


Read this post at its original location at http://navigateintosuccess.com/blog/decisions-spring-2013-kicking-off-next-week, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/decisions-spring-2013-kicking-off-next-week/feed 1
Unlimited Text Length in NAV 2013 http://navigateintosuccess.com/blog/unlimited-text-length-in-nav-2013 http://navigateintosuccess.com/blog/unlimited-text-length-in-nav-2013#comments Wed, 13 Jun 2012 20:25:36 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1191

imageHave you noticed already that in Microsoft Dynamics NAV 2013 the text variables can have unlimited length? That’s quite a leap ahead of the previous versions which couldn’t handle more than 1024 characters per variable. If you wanted to achieve bug-free code then, when you were assigning texts around, you had to concatenate the result down to the MAXSTRLEN of the target text.

Not anymore.

The trick is to simply not declare the Length property on text variables. If you declare a variable of type Text, and then leave the Length empty, it means – unlimited.

Don’t worry – you won’t kill NAV by eating up all the available memory. Underneath C/AL there is .NET now, and strings in .NET are of unlimited length, or better yet – unlimittable – length anyway. Strings will only make things slow if you stuff the revised version of King James’s Bible in them. In all practical situations, there will be absolutely no performance penalty of leaving Texts unlimited.

I don’t know about you, but from tomorrow morning, I won’t be setting Length to my Texts.


Read this post at its original location at http://navigateintosuccess.com/blog/unlimited-text-length-in-nav-2013, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/unlimited-text-length-in-nav-2013/feed 10
Length of G/L Account Name in NAV 2013 http://navigateintosuccess.com/blog/length-of-gl-account-name-in-nav-2013 http://navigateintosuccess.com/blog/length-of-gl-account-name-in-nav-2013#comments Sun, 10 Jun 2012 08:41:46 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1185

imageA small but important change often slips under the radar of the What’s New kinds of documents. One of those is the standard length of the Name field in G/L Account table. I’ve just noticed that in Microsoft Dynamics NAV 2013 the length of this field has been increased from 30 characters to 50 characters.

While this seams a minor thing, it’s actually a huge improvement. If 30 characters was not enough in previous versions, increasing it was not a simple thing to do, and required you to change thirty or so other objects as well. It was in fact one of those annoying things that you better got used to, rather than changed. Yes, I’ve seen customers who insisted on changing it, but most of them simply gave in.

In NAV 2013, this change is not only about G/L Account – the length of all Name and Description fields in all master tables has been consistently set to 50. In the previous versions of NAV the length varied between 30 and 50, but now all of the master table Name and Description fields are of length 50.

A small step for man, a giant leap for mankind.


Read this post at its original location at http://navigateintosuccess.com/blog/length-of-gl-account-name-in-nav-2013, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/length-of-gl-account-name-in-nav-2013/feed 11
NAV 2013 beta mini-launch at Adriatics Community http://navigateintosuccess.com/blog/nav-2013-beta-mini-launch-at-adriatics-community http://navigateintosuccess.com/blog/nav-2013-beta-mini-launch-at-adriatics-community#comments Tue, 22 May 2012 08:52:04 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1180

Microsoft Comomunity CroatiaIf you want to learn more about the upcoming release of Microsoft Dynamics NAV 2013, and you are from Zagreb, or don’t mind coming to it, the next community event of Microsoft Dynamics Community Adriatics will be fully dedicated to NAV 2013.

There are going to be two presentations. In the first one on the topic of “What’s new in application functionality”, hosted by Ivan Koletić, a member of Microsoft Dynamics NAV product team, who will give an overview of new application features in NAV 2013, and by now you should already know there are plenty.

The second presentation will be about “What’s new in technology”, and will be hosted by me. I won’t be doing any deep-dive this time, and I’ll provide a cloud-perspective overview of a myriad of architecture changes and technology improvements in NAV 2013.

Both of these presentations are merely going to be an introduction in the series of the presentations that will follow over the next several community events. It’s going to be an exciting summer and fall.

If you would like to attend, then please register your attendance (for free, of course) at the event homepage. We are looking forward to seeing you there!


Read this post at its original location at http://navigateintosuccess.com/blog/nav-2013-beta-mini-launch-at-adriatics-community, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/nav-2013-beta-mini-launch-at-adriatics-community/feed 0
Generics in .NET Interop for NAV 2013 http://navigateintosuccess.com/blog/generics-in-net-interop-for-nav-2013 http://navigateintosuccess.com/blog/generics-in-net-interop-for-nav-2013#comments Thu, 17 May 2012 22:55:54 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1175

image.NET Framework is full of programming conceptual gems, that are now at the fingertips of us poor C/AL folks. One of those is generics. However, the C/AL support for generics at the first glance seems rather limited, and the help file says that you can’t specify data types, and that all generics will be instantiated with System.Object as their type.

However, with Microsoft Dynamics NAV 2013, there is a very simple way which allows you to use generics with other data types, as well. So, if .NET Framework Interoperability interests you a slightest bit, here’s a solution.

The example below will be for the System.Collections.Generic.Dictionary<,>, and I will show how to use instances of the Dictionary<,> object with any desired data type, without having to pull in any external assemblies.

The Solution

Before I show the example, I’ll first explain the solution.

Declaratively, you can’t declare a generic variable, and specify the type. C/SIDE is just not (yet) that flexible. But that doesn’t matter, because .NET Framework includes a nice feature which allows you to create instances of any type on the fly: Reflection.

By using reflection, you can create an instance of a generic type, and specify which type(s) it should use, all with very little coding. In the examples that follow, I’ll create an instance of Dictionary<string,int>.

The whole process in C# would look, more or less, like this:

Dictionary<string, int> dict =

Activator.CreateInstance(

typeof(Dictionary<,>).MakeGenericType(

new Type[]

{

typeof (string),

typeof (int)

})) as Dictionary<string, int>;

 
Okay, it’s kind of hax0rish, because all is inline, so if you prefer it step by step, here it goes:

// Step 1

Type[] types =

new Type[]

{

typeof (string),

typeof (int)

};

 

// Step 2

Type dictionaryType = typeof (Dictionary<,>).MakeGenericType(types);

 

// Step 3

Dictionary<string, int> dict =

Activator.CreateInstance(dictionaryType) as

Dictionary<string, int>;

 

Step 1 creates an instance of a 2-element array of Type. This is needed for creating a generic type using reflection.

Step 2 uses reflection to create a generic type of specified types. The types are specified in the array we created in the step 1.

Step 3 uses reflection to create an instance of the type created in step 2.

Now that we’ve seen it in C#, let’s map the same to C/AL.

 

1. Declaration

Let’s get it straight, you can’t declare a DotNet variable of a generic type, and specify the actual type (or types) it generalizes. The C/SIDE simply doesn’t allow that. But, don’t worry. Go ahead, and declare the following variables:

Name Subtype
Dict System.Collections.Generic.Dictionary`2.’mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
Type System.Type.’mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
Activator System.Activator.’mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
Arr System.Array.’mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
String System.String.’mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
Int  

Of course, all of the above are DotNet, except for the last one, which is Integer.

 

2. Creating an instance of an array

To declare an instance of an array of type Type, we can call the CreateInstance method of the Array class, by providing the type of System.Type. Then we populate the array with the types of System.String, and System.Int32:

Arr := Arr.CreateInstance(GETDOTNETTYPE(Type),2);

Arr.SetValue(GETDOTNETTYPE(String),0);

Arr.SetValue(GETDOTNETTYPE(Int),1);

This isn’t nearly as elegant as in C#, but accomplishes the goal quite as nicely. Take a note of the GETDOTNETTYPE function – a new gem in C/AL, the equivalent of the typeof keyword in C#.

 

3. Creating the dictionary type

To create the type for the Dictionary<string,int> that we need, we have two steps. First is to get the type of Dictionary, and the second is to use that type to reflect out the actual Dictionary type that we need, based on types specified in the array:

Type := GETDOTNETTYPE(Dict);

Type := Type.MakeGenericType(Arr);

Again, it can’t be a single line in C/AL, because the syntax of C/AL does not treat the result of the GETDOTNETTYPE as an object.

 

4. Creating an actual instance

Finally, we create an actual instance of the Dictionary<string,int> object, exactly as we would in C# (except we do it in C/AL):

Dict := Activator.CreateInstance(Type);

There. And now we are ready to use it.

 

5. Testing if it really is what we need

Testing generics is easy – if you pass on to it the arguments of invalid type, they’d complain loudly. So, let’s try to pass some valid ones, and an invalid one:

Dict.Add('first',1);

Dict.Add('second',2);

Dict.Add('third','three');

Here, at the 3rd line, it fails with the following message, exactly as expected: This message is for C/AL programmers: A call to System.Collections.Generic.Dictionary`2[System.String,System.Int32].Add failed with this message: The type of one or more arguments does not match the method’s parameter type.

So, obviously, we have an actual instance of the Dictionary<string,int> which receives exactly those elements, and behaves exactly as we would expect from a true .NET Framework generic class: if we try to pass a value of incorrect type, it’s not going to be happy.

 

6. And now for something completely different

If you know anything about generics, at this moment you should be puzzled, as I was when I first tried this out. All of the C/AL voodoo above is the equivalent of this code in C#:

Dictionary<object, object> dict =

Activator.CreateInstance(

typeof (Dictionary<,>).MakeGenericType(

new Type[]

{

typeof (string),

typeof (int)

})) as Dictionary<object, object>;

No need to try running it, it fails. Actually, it doesn’t fail, it returns null. The problem is, being strongly typed, the .NET runtime can’t cast Dictionary<string,int> as Dictionary<object,object>, and the declared type of Dictionary<object,object> can’t hold a value of Dictionary<string,int>. It’s apples and oranges—even though both are instances of the same generic type, it’s not the same actual type, and they are not typecast compatible.

When you declare a DotNet of a generic type, in this case the Dictionary type, it’s declaratively Dictionary<object,object>, so how in the earth did we manage to stuff Dictionary<string,int> into it?

As a matter of fact, we never did that. I can’t say for sure, but I’ll give an educated guess here. DotNet is never actually the exact type we declare, but a wrapper class around just about anything. I assume it actually wraps around System.Object, and then uses reflection to access the members of the actual object it wraps.

But in the end, why do we care? It does what we need it to do.


Read this post at its original location at http://navigateintosuccess.com/blog/generics-in-net-interop-for-nav-2013, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/generics-in-net-interop-for-nav-2013/feed 1
Hello, unicode! http://navigateintosuccess.com/blog/hello-unicode http://navigateintosuccess.com/blog/hello-unicode#comments Thu, 17 May 2012 08:11:52 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1171

image你好,世界!გამარჯობა, მსოფლიო! હેલો, વિશ્વ! مرحبا، العالم! שלום, עולם! नमस्ते, दुनिया! こんにちは世界 ಹಲೋ, ವಿಶ್ವದ! 안녕하세요, 세계! Γεια σου, κόσμε! Привет, мир! வணக்கம், உலக! హలో, ప్రపంచం! สวัสดีโลก!

No, no, I didn’t go fully crazy yet, but I’m surely closing in. Maybe it’s not at all such a big deal as I see it, but the new Unicode support in Microsoft Dynamics NAV 2013 is just blowing my socks off. After a quarter century of being tied to a single code page of choice, NAV has finally been freed of it’s single byte per character legacy.

So, the scribble above is not just me showing off with my ability to use Google translate, it’s a playground for you to copy select pieces of it and paste it all over NAV text fields in your NAV 2013 installation. You have one, don’t you? If not, go grab your copy!

This Unicode thingy, it was obvious this was coming. It was not exactly officially confirmed earlier, but with the good riddance of the Classic stack, and having the whole new stack built entirely upon .NET Framework and SQL Server (which had Unicode since ages), retaining ASCII would actually required far more work than simply adding the so much desired n in front of all those varchars in the database. In memory, everything was Unicode already anyway and if you have been in Antwerp at NAV TechDays last year, you may remember this presentation with the demo.

With NAV 2013 beta out, the sheer number of news is frightening, and I hope I just get enough time to blog as much as I’d love to. But I’m sure my colleagues would kick-off as well, and there will be oceans of useful information about NAV 2013 pouring in. That I can promise.


Read this post at its original location at http://navigateintosuccess.com/blog/hello-unicode, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/hello-unicode/feed 7
Microsoft Dynamics NAV 2013 Beta Available! http://navigateintosuccess.com/blog/microsoft-dynamics-nav-2013-beta-available http://navigateintosuccess.com/blog/microsoft-dynamics-nav-2013-beta-available#comments Mon, 14 May 2012 20:20:48 +0000 Vjekoslav Babic http://navigateintosuccess.com/?p=1168

BetaI don’t know about you, but I think today is a great day: Microsoft Dynamics NAV 2013 Beta has been published on PartnerSource, and if you have access, you can download it from here.

I’ve been playing around with CTPs for more quite a while, and even though I can’t share any specifics, I can assure you: this is definitely the best release ever, technically, architecturally, functionally and from business value perspective. Whatever angle you take – this release is massive.

I believe I don’t exaggerate if I say that 2013 brings more news in comparison with 2009 R2, than 2009 brought in comparison with 5.0 SP1.

If you want to check more about what exactly is new, I suggest you read the white paper and accompanying documentation at the NAV 2013 launch portal, and I hope the MVPs soon get the clearance to blog about specific features. There are just so many fantastically exciting to-dos for this blog, about NAV 2013, that I’ll probably eat my fingernails – heck, the whole fingers! – in anticipation to be able to start.


Read this post at its original location at http://navigateintosuccess.com/blog/microsoft-dynamics-nav-2013-beta-available, or visit the original blog at http://NavigateIntoSuccess.com. 47fc2f5642456dfd71e5581a3785c625)]]>
http://navigateintosuccess.com/blog/microsoft-dynamics-nav-2013-beta-available/feed 5