Showing posts with label customization. Show all posts
Showing posts with label customization. Show all posts

Tuesday, 15 March 2016

Dynamics AX7 Development 4–Overlay or extend

In this post I will look at the decision of overlaying or extending. In AX7 you can extend metadata by adding a field to a table or adding a control to a form, and extend business logic by defining event handlers. You can now write event handlers on several pre-defined events on tables, forms, form data sources, form controls, and others.
Below we are going to look at a basic example comparing Overlay with Extending (using event handler). As mentioned there are many forms of extensions but for simplicity we will focus on one (event handler).

Overlay

Overlaying is when you modify existing code by changing the system behaviour. For example lets look at overlaying the initValue method on the CustTable.
Right click on the object and click Customize. This will add it to your project.
2016-01-19_0729
You will see a little [c] to indicate it is a customised object.
2016-01-19_0735
I added a bit of code to the initValue method. Notice how it has changed colour to indicate it has been customised.
2016-01-19_0738

Extension (using events)

Extensions are used in AX7 much more and is much more flexible. Extensions allow you to leave the system behaviour but adding your piece to it. In some cases you have to overlay but try to avoid that if possible. As overlaying may seem simple but it will cost you on upgrades, hotfixes, maintaining code and merging code.
Lets look at the same example but now using extensions.
On the CustTable right click and Opern designer.
2016-01-19_1608
Right click and copy the vent handler method (this will copy into clipboard).
2016-01-19_1607
Now create a class. Paste whats in clipboard. It will paste the highlighted section below.
Add your code. The vent will now be triggered after the initValue method.
2016-01-19_1610
Warning: Code block to update languageId is for illustration only. Not runnable.
More detail on the wiki page:

Dynamics AX7 Development 4–Overlay or extend

In this post I will look at the decision of overlaying or extending. In AX7 you can extend metadata by adding a field to a table or adding a control to a form, and extend business logic by defining event handlers. You can now write event handlers on several pre-defined events on tables, forms, form data sources, form controls, and others.
Below we are going to look at a basic example comparing Overlay with Extending (using event handler). As mentioned there are many forms of extensions but for simplicity we will focus on one (event handler).

Overlay

Overlaying is when you modify existing code by changing the system behaviour. For example lets look at overlaying the initValue method on the CustTable.
Right click on the object and click Customize. This will add it to your project.
2016-01-19_0729
You will see a little [c] to indicate it is a customised object.
2016-01-19_0735
I added a bit of code to the initValue method. Notice how it has changed colour to indicate it has been customised.
2016-01-19_0738

Extension (using events)

Extensions are used in AX7 much more and is much more flexible. Extensions allow you to leave the system behaviour but adding your piece to it. In some cases you have to overlay but try to avoid that if possible. As overlaying may seem simple but it will cost you on upgrades, hotfixes, maintaining code and merging code.
Lets look at the same example but now using extensions.
On the CustTable right click and Opern designer.
2016-01-19_1608
Right click and copy the vent handler method (this will copy into clipboard).
2016-01-19_1607
Now create a class. Paste whats in clipboard. It will paste the highlighted section below.
Add your code. The vent will now be triggered after the initValue method.
2016-01-19_1610
Warning: Code block to update languageId is for illustration only. Not runnable.
More detail on the wiki page:

Dynamics AX7 Development 6–Adding Delegates for Customised Code in Higher Package

Dynamics AX is split into multiple models the main ones are as follows; Application suite, Application Foundation and Application Platform.
2016-01-20_1256
If you look at some of the debendencies you see how the organization of model affects the assemblies (how it is compiled).
In some cases you have to modify the Foundation or the Platform. The issue with that is you are unable to reference code sitting in a higher package (model). In short a higher model can take dependencies and access elements in a lower model but not the other way around.
To get around this limitation you have to use a delegate method. Below is an example of a delegate. The PrintMgmtDocType has a method to get the default report form.
2016-01-29_0612
See how the delegate method is called from the Foundation and uses an EventHanderResult to pass around the result.
2016-01-29_0610
The delegate method doesnt have to have any code. It is there to allow other methods to subscribe to it.
2016-01-29_0611
Now this is the calls in the Suite. Notice how to subscribe by adding the SubscribesTo attribute.
2016-01-29_0623
Refer to the Microsoft Wiki. It has some really good examples.

Dynamics AX7 Development 6–Adding Delegates for Customised Code in Higher Package

Dynamics AX is split into multiple models the main ones are as follows; Application suite, Application Foundation and Application Platform.
2016-01-20_1256
If you look at some of the debendencies you see how the organization of model affects the assemblies (how it is compiled).
In some cases you have to modify the Foundation or the Platform. The issue with that is you are unable to reference code sitting in a higher package (model). In short a higher model can take dependencies and access elements in a lower model but not the other way around.
To get around this limitation you have to use a delegate method. Below is an example of a delegate. The PrintMgmtDocType has a method to get the default report form.
2016-01-29_0612
See how the delegate method is called from the Foundation and uses an EventHanderResult to pass around the result.
2016-01-29_0610
The delegate method doesnt have to have any code. It is there to allow other methods to subscribe to it.
2016-01-29_0611
Now this is the calls in the Suite. Notice how to subscribe by adding the SubscribesTo attribute.
2016-01-29_0623
Refer to the Microsoft Wiki. It has some really good examples.

listpages in AX7

In AX 2012 we had to maintain two forms; a list page and a details form. This has changed in AX7 with the introduction of form patterns. Now we only have to maintain a single form and by applying the correct patterns it is displayed accordingly. This is a big benefit and reduces the overhead of developing and maintaining two forms.
Below is an example:
2016-03-08_1655
Figure 1: Customer list
2016-03-08_1656
Figure 2: Customer details with the navigation list pulled out
Below you see the different patterns.
2016-03-08_1653
The menu item has a view option which allows you to open the form in the selected view.
2016-03-08_1701

listpages in AX7

In AX 2012 we had to maintain two forms; a list page and a details form. This has changed in AX7 with the introduction of form patterns. Now we only have to maintain a single form and by applying the correct patterns it is displayed accordingly. This is a big benefit and reduces the overhead of developing and maintaining two forms.
Below is an example:
2016-03-08_1655
Figure 1: Customer list
2016-03-08_1656
Figure 2: Customer details with the navigation list pulled out
Below you see the different patterns.
2016-03-08_1653
The menu item has a view option which allows you to open the form in the selected view.
2016-03-08_1701

Tuesday, 1 March 2016

Basic Development concept AX7

Before we talk AX7 Development, we need to have look at few terminologies, which are as under

Element: Element is any Object residing in AOT. E.g. any Base Enumeration, any EDT, any Table, any Form, which you see in AOT Tree, is an element itself.

Model: A Model is a group of elements. A model is collection of elements that represent a distributable software solution.

Packages: A package is deployable unit, which may have multiple Models.

Project: Projects are the logical containers for everything that's needed to build your application. A project can be associated with only one model.

After we know basic terminologies, which will be used very frequently, let’s start with ways of developments AX7 provides.

With arrival of AX7, now we can do development in AX, with two methodologies.

  1. OverLayring
    If you have been developer of previous versions of AX such as AX2012 or AX2009, you don’t need explanation of this way of development. Name of this methodology ‘OverLayring’ is self-explanatory.
    In Microsoft Dynamics AX, a layer system is used to manage elements. The USR layer is the top layer and the SYS layer is the bottom layer, and each layer has a corresponding patch layer above it.
    OverLayring means if you do change/customize any element in upper layer, it will override its definition, in lower layer.
    This is what we were doing till AX2012 to customize AX. It basically allows customization of metadata and source code in higher layer. For example, you can add a new field in CustTrans Table in the user layer or in ISV Layer.
  2. Extension
    It refers to concept of extending existing elements, without overriding those into other layers. That means, elements will not be customized, instead elements will be extended. This approach reduces upgrade cost and conflicts. By creating extension elements, all of the customizations and code are stored in a separate assembly. It only contains the code that was added or changed in the extension file. Since this code resides in a separate assembly, it improves performance and the ability to upgrade and test.

Basic Development concept AX7

Before we talk AX7 Development, we need to have look at few terminologies, which are as under

Element: Element is any Object residing in AOT. E.g. any Base Enumeration, any EDT, any Table, any Form, which you see in AOT Tree, is an element itself.

Model: A Model is a group of elements. A model is collection of elements that represent a distributable software solution.

Packages: A package is deployable unit, which may have multiple Models.

Project: Projects are the logical containers for everything that's needed to build your application. A project can be associated with only one model.

After we know basic terminologies, which will be used very frequently, let’s start with ways of developments AX7 provides.

With arrival of AX7, now we can do development in AX, with two methodologies.

  1. OverLayring
    If you have been developer of previous versions of AX such as AX2012 or AX2009, you don’t need explanation of this way of development. Name of this methodology ‘OverLayring’ is self-explanatory.
    In Microsoft Dynamics AX, a layer system is used to manage elements. The USR layer is the top layer and the SYS layer is the bottom layer, and each layer has a corresponding patch layer above it.
    OverLayring means if you do change/customize any element in upper layer, it will override its definition, in lower layer.
    This is what we were doing till AX2012 to customize AX. It basically allows customization of metadata and source code in higher layer. For example, you can add a new field in CustTrans Table in the user layer or in ISV Layer.
  2. Extension
    It refers to concept of extending existing elements, without overriding those into other layers. That means, elements will not be customized, instead elements will be extended. This approach reduces upgrade cost and conflicts. By creating extension elements, all of the customizations and code are stored in a separate assembly. It only contains the code that was added or changed in the extension file. Since this code resides in a separate assembly, it improves performance and the ability to upgrade and test.

Using clauses AX7

Previously, all references to managed artifacts that weren’t authored in X++ was done using fully qualified names, including the namespace for each type. This is still possible, but you can now provide using clauses to make the use of such artifacts less onerous. As opposed to a using statement, each using clause precedes the class in which the clause is applied.

It’s also possible to provide aliases that introduce a short name for a fully qualified name. Aliases can denote namespaces and classes as shown below.

Example

Consider the following code:
 using System;
using IONS=System.IO; // Namespace alias
using Alist=System.Collections.ArrayList; // Class alias

public class MyClass2
{
public static void Main(Args a)
{
Int32 I; // Alternative to System.Int32
Alist al; // Using a class alias

al = new Alist();
str s;

al.Add(1);

s = IONS.Path::ChangeExtension(@"c:\tmp\test.xml", ".txt");
}
}

Extension methods AX7

The extension method feature lets you add extension methods to a target class by writing the methods in a separate extension class. The following rules apply:
    • The extension class must be static.
    • The name of the extension class must end with the ten-character suffix _Extension. However, there’s no restriction on the part of the name that precedes the suffix.
    • Every extension method in the extension class must be declared as public static.
    • The first parameter in every extension method is the type that the extension method extends. However, when the extension method is called, the caller must not pass in anything for the first parameter. Instead, the system automatically passes in the required object for the first parameter.
It’s perfectly valid to have private or protected static methods in an extension class. These are typically used for implementation details and are not exposed as extensions.
The example below illustrates an extension class holding a few extension methods:
public static class AtlInventLocation_Extension
{
public static InventLocation refillEnabled(
InventLocation _warehouse,
boolean _isRefillEnabled = true)
{
_warehouse.ReqRefill = _isRefillEnabled;
return _warehouse;
}

public static InventLocation save(InventLocation _warehouse)
{
_warehouse.write();
return _warehouse;
}
}

Extension methods AX7

The extension method feature lets you add extension methods to a target class by writing the methods in a separate extension class. The following rules apply:
    • The extension class must be static.
    • The name of the extension class must end with the ten-character suffix _Extension. However, there’s no restriction on the part of the name that precedes the suffix.
    • Every extension method in the extension class must be declared as public static.
    • The first parameter in every extension method is the type that the extension method extends. However, when the extension method is called, the caller must not pass in anything for the first parameter. Instead, the system automatically passes in the required object for the first parameter.
It’s perfectly valid to have private or protected static methods in an extension class. These are typically used for implementation details and are not exposed as extensions.
The example below illustrates an extension class holding a few extension methods:
public static class AtlInventLocation_Extension
{
  public static InventLocation refillEnabled(
    InventLocation _warehouse, 
    boolean _isRefillEnabled = true)
  {
    _warehouse.ReqRefill = _isRefillEnabled;
    return _warehouse;
  }

  public static InventLocation save(InventLocation _warehouse)
  {
    _warehouse.write();
    return _warehouse;
  }
}

Using clauses AX7

Previously, all references to managed artifacts that weren’t authored in X++ was done using fully qualified names, including the namespace for each type. This is still possible, but you can now provide using clauses to make the use of such artifacts less onerous. As opposed to a using statement, each using clause precedes the class in which the clause is applied.

It’s also possible to provide aliases that introduce a short name for a fully qualified name. Aliases can denote namespaces and classes as shown below.

Example

Consider the following code:
 using System;
using IONS=System.IO; // Namespace alias
using Alist=System.Collections.ArrayList; // Class alias

public class MyClass2
{
  public static void Main(Args a)
  {
    Int32 I; // Alternative to System.Int32
    Alist al; // Using a class alias

    al = new Alist();
    str s;

    al.Add(1);

    s = IONS.Path::ChangeExtension(@"c:\tmp\test.xml", ".txt");
  }
}

Compiler diagnoses attempts to store objects in containers AX7

In previous incarnations of the X++ compiler, it was possible to store object references into containers, even though this would fail at runtime. This is no longer possible. When the compiler sees an attempt to store an object reference into a container:
container c = [new Query()];
It will issue the error message:
Instances of type 'Query' cannot be added to a container.
If the type of the element that is added to the container is anytype the compiler can’t make the determination of whether or not the value is a reference type. The compiler will allow this under the assumption that the user knows what they’re doing. The compiler won’t diagnose the following code as erroneous:
anytype a = new Query();
container c = [a];
but an error will be thrown at runtime.

Casting AX7

The previous version of X++ was very permissive in its treatment of type casting. Both up-casting and down-casting were allowed without intervention from the programmer. Some of the casting permitted in legacy X++ can’t be implemented in the confines of the .NET runtime environment.
In object oriented programming languages, including X++, casting refers to assignments between variables whose declared types are both in the same inheritance chain. A cast is either a down-cast or an up-cast. To set the stage for this discussion, we introduce a few self-explanatory class hierarchies:
Casting_DebugFeatures
As you can see, the MotorVehicle class isn’t related to the Animal cast.
An up-cast happens when assigning an expression of a derived type to a base type:
  Animal a = new Horse();
down-cast happens when assigning an expression of a base type to a derived variable.
Horse h = new Animal();
Both up-casts and down-casts are supported in X++. However, down-casts are dangerous and should be avoided whenever possible. The example above will fail with an InvalidCastException at runtime, since the assignment doesn’t make sense.
X++ supports late binding on a handful of types, like object and formrun. This means that the compiler won’t diagnose any errors at compile-time when it sees a method being called on those types, if that method isn’t declared explicitly on the type,. It’s assumed that the developer knows what they’re doing.
For instance, the following code may be found in a form.
Object o = element.args().caller();
o.MyMethod(3.14, “Banana”);
The compiler can’t check the parameters, return values, etc. for the MyMethod method, since this method isn’t declared on the object class. At runtime, the call will be made using reflection, which is orders of magnitude slower than normal calls. note that calls to methods that are actually defined on the late binding types will be naturally checked.
For example, the call to ToString():
o.ToString(45);
will cause a compilation error:
'Object.toString' expects 0 argument(s), but 1 specified.
because the ToString method is defined on the object class.
There’s one difference from the implementation of previous version of X++, related to the fact that methods could be called on unrelated objects, as long as the name of the method was correct, even if the parameter profiles weren’t entirely correct. This isn’t supported in CIL.

Example

public class MyClass2
{
public static void Main(Args a)
{
Object obj = new Car();
Horse horse = obj; // exception now thrown
horse.run(); // Used to call car.run()!
}
}
You should use the IS and AS operators liberally in your code. The IS operator can be used if the expression provided is of a particular type (including derived types); the AS operator will perform casting into the given type and return null if a cast isn’t possible.

Casting AX7

The previous version of X++ was very permissive in its treatment of type casting. Both up-casting and down-casting were allowed without intervention from the programmer. Some of the casting permitted in legacy X++ can’t be implemented in the confines of the .NET runtime environment.
In object oriented programming languages, including X++, casting refers to assignments between variables whose declared types are both in the same inheritance chain. A cast is either a down-cast or an up-cast. To set the stage for this discussion, we introduce a few self-explanatory class hierarchies:
Casting_DebugFeatures
As you can see, the MotorVehicle class isn’t related to the Animal cast.
An up-cast happens when assigning an expression of a derived type to a base type:
  Animal a = new Horse();
down-cast happens when assigning an expression of a base type to a derived variable.
Horse h = new Animal();
Both up-casts and down-casts are supported in X++. However, down-casts are dangerous and should be avoided whenever possible. The example above will fail with an InvalidCastException at runtime, since the assignment doesn’t make sense.
X++ supports late binding on a handful of types, like object and formrun. This means that the compiler won’t diagnose any errors at compile-time when it sees a method being called on those types, if that method isn’t declared explicitly on the type,. It’s assumed that the developer knows what they’re doing.
For instance, the following code may be found in a form.
Object o = element.args().caller();
  o.MyMethod(3.14, “Banana”);
The compiler can’t check the parameters, return values, etc. for the MyMethod method, since this method isn’t declared on the object class. At runtime, the call will be made using reflection, which is orders of magnitude slower than normal calls. note that calls to methods that are actually defined on the late binding types will be naturally checked.
For example, the call to ToString():
o.ToString(45);
will cause a compilation error:
'Object.toString' expects 0 argument(s), but 1 specified.
because the ToString method is defined on the object class.
There’s one difference from the implementation of previous version of X++, related to the fact that methods could be called on unrelated objects, as long as the name of the method was correct, even if the parameter profiles weren’t entirely correct. This isn’t supported in CIL.

Example

public class MyClass2
{
  public static void Main(Args a)
  {
    Object obj = new Car();
    Horse horse = obj; // exception now thrown
    horse.run();    // Used to call car.run()!
  }
}
You should use the IS and AS operators liberally in your code. The IS operator can be used if the expression provided is of a particular type (including derived types); the AS operator will perform casting into the given type and return null if a cast isn’t possible.

Compiler diagnoses attempts to store objects in containers AX7

In previous incarnations of the X++ compiler, it was possible to store object references into containers, even though this would fail at runtime. This is no longer possible. When the compiler sees an attempt to store an object reference into a container:
container c = [new Query()];
It will issue the error message:
Instances of type 'Query' cannot be added to a container.
If the type of the element that is added to the container is anytype the compiler can’t make the determination of whether or not the value is a reference type. The compiler will allow this under the assumption that the user knows what they’re doing. The compiler won’t diagnose the following code as erroneous:
anytype a = new Query();
        container c = [a];
but an error will be thrown at runtime.

The mkDate predefined function no longer accepts shorthand values

In legacy systems, it was possible to use “shorthand” values for the year argument of the mkDate function. The effect can be seen in the following code sample.
static void Job16(Args _args)
{
int y;
date d;

for (y = 0; y < 150; y++)
{
d = mkDate(1,1,y);
info(strFmt("%1 - %2", y, year(d)));
}
}
Running this code in the legacy system will produce the following values:
0 – 2000
1 – 2001
2 – 2002

27 – 2027
28 – 2028
29 – 2029
30 – 2030
31 – 1931
32 – 1932
33 – 1933

97 – 1997
98 – 1998
99 – 1999
100 – 1900
We no longer support these values. Attempts to use such values will cause the mkDate function to return the null date (1/1/1900).