Archive

Archive for the ‘.NET’ Category

AX2012 DLL Deployment and how AX binds DLL’s at runtime

May 22nd, 2013 2 comments

In an earlier post I have showed how to use custom WPF controls with Dynamics AX 2012.

Well when using this type of fuctionality, you will often come into troubles when using it on other environments because of the corresponding DLL files not being deployed on their machine.

For that, you can use the automatic deployment feature of Ax when adding projects to the AOT. But it seems that there is an issue there. You can find lots of information on this post made by Joris De Gruyter:

http://daxmusings.codecrib.com/2011/09/ax-2012-net-assembly-deployment.html

And there is also information to be found here:

http://msdn.microsoft.com/en-us/library/gg889192.aspx

In short you have the following options to deploy your DLL files:

  • Automatic deployment feature of Visual Studio projects in the AOT
  • Using the SysFileDeployer framework (Joris mentioned an upcoming blog post on that, so that will be cool and interesting)
  • Copy them into the client\bin or server\bin directories
  • Use the Global Assembly Cache to store assemblies

While opinions might be devided, I tend to like the latter option. Simply because the GAC is intended to manage just that. Some of the benefits of the GAC:

  • No polution of the file system with DLL files being copied all around
  • Assemblies must be signed and the PublicKeyToken can be used to differentiate versions of your DLL file (Think of disallowing an assembly in production if it is coming from development environments and the wrong version was accidentally added)
  • Due to the previous fact, you can also have multiple versions of the same DLL file in your GAC.
  • GAC Redirection can be used to point to the right assembly if older versions are searched for

So let’s look back at the initial problem that I was facing. Dynamics AX threw up an error mentioning that it could not find the DLL file it needed. Strange because it was present in the GAC so it should always find it there.

DLLLoadingError

Well to find out why it did not find the DLL I needed to check where AX was actually looking for it. And to do that you can use a .net framework tool called fuslogvw. This little helpfull tool is actually an assembly binding logging tool. So if DLL files are searched for, this little guy will give you the details about it.

So open up a Visual Studio Command Prompt and type fuslogvw and hit enter. First we need to do some minor setup to get it to log stuff. So go to Settings and select the log all binds to disk option. Then select a path to store the log in and you’re set to go.



Fuslogvw Settings

At that point I fired up the AX client and openened up the form that uses the assembly that appeared to be missing. Fuslogvw caught the information that is displayed below.

Fuslogvw_CapturedRecord

*** Assembly Binder Log Entry  (17/05/2013 @ 9:03:38) ***
 
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
 
Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe
--- A detailed error log follows. 
 
=== Pre-bind state information ===
LOG: User = EPS\lab rd wdpan59
LOG: DisplayName = EPS.AX.WPFControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
(Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Dynamics AX/60/Client/Bin/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = Ax32.exe
Calling assembly : Microsoft.Dynamics.AX.ManagedInterop, Version=6.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: The same bind was seen before, and was failed with hr = 0x80070002.
ERR: Unrecoverable error occurred during pre-download check (hr = 0x80070002).

The following line shows what was wrong at the time:

LOG: DisplayName = EPS.AX.WPFControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

The assembly manager was actually looking for an unsigned version of my assembly in the GAC. But that version is not present since I had signed my assembly… So why was it looking for an unsigned version?? Well the answer to this was the order in which I had done things.

For development purposes I did the following in the exact same order:

  • Created a Visual Studio solution and added it to the AOT.
  • Added a ManagedHost control on a form and pointed out to the assembly that I needed. (Filedbased) (Until now an unsigned one)
  • When all was working well, I tried to do stuff the BP way and I signed my assembly and put it into the GAC.

As that seems to be enough, environments other than my machine were still facing the issue even though the DLL was in the GAC there too. And when looking at the ManagedHost control in AX, I saw that it was keeping a reference to the unsigned assembly and not the signed one!! So to solve it, you need to do things in a different order:

  • Create the Visual studio project.
  • Sign and build your assembly.
  • Add the solution to the AOT.
  • Add the ManagedHost control now and point to the assembly (that is now in your GAC already)

When this is done, you will have a reference in AX that also takes the right PublicKeyToken in to account and it works on the other machines also. To be sure I checked with fuslogvw again and this is the output.

 

*** Assembly Binder Log Entry  (17/05/2013 @ 9:03:42) ***
 
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
 
Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe
--- A detailed error log follows. 
 
=== Pre-bind state information ===
LOG: User = EPS\lab rd wdpan59
LOG: DisplayName = EPS.AX.WPFControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=14cd416a5dbff93c, processorArchitecture=x86
(Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Dynamics AX/60/Client/Bin/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = Ax32.exe
Calling assembly : Microsoft.Dynamics.AX.ManagedInterop, Version=6.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin\Ax32.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: EPS.AX.WPFControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=14cd416a5dbff93c, processorArchitecture=x86
LOG: Found assembly by looking in the GAC.
LOG: Binding succeeds. Returns assembly from C:\Windows\Microsoft.Net\assembly\GAC_32\EPS.AX.WPFControls\v4.0_1.0.0.0__14cd416a5dbff93c\EPS.AX.WPFControls.dll.
LOG: Assembly is loaded in default load context.

And as we can see, Dynamics AX now takes the key into account and mentioned that it indeed found the assembly in the GAC.

LOG: DisplayName = EPS.AX.WPFControls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=14cd416a5dbff93c, processorArchitecture=x86

So for now, we have stored all the assemblies that we use in a folder on the network and every time there is a new version available, simple scripts are run to update the GAC and that is the only thing that needs to be done.

 

 

Hosting custom WPF calendar control in AX 2012

May 20th, 2013 No comments

The requirement

A couple of days ago, I needed to create a calendar like lookup but it had to be possible to block out dates for selection. In Dynamics AX, there is calendar lookup form available, but there are some minors to it:

  • It is not really (easy) customizable
  • It has limited functionality

What I needed the calendar form to do:

  • Visually block dates for selection
  • Easy navigation over longer periods
  • Support for different selection types (Single date, weeks, multiple selected dates, …)
  • Provide a custom range to display dates

So it is clear that Ax does not have a calendar like that, so I had the idea of creating a custom control for this. But due to time restriction ( isn’t there always a time restriction ! :-) ) I went looking for a WPF control that I could wrap around and integrate it with Ax. And then I found the following control that has all I need : http://www.codeproject.com/Articles/88757/WPF-Calendar-and-Datepicker-Final But having a working control in a WPF application is one thing, getting it to work with Dynamics AX is another. I noticed when I was using the control directly, the client crashed and some of the properties were not marshallable because Dynamics AX does not support generics. So wrapping the control in a control of my own was an option here. And there are two reasons why I did wrap the control:

  • When using the control directly, it crashed :)
  • When wrapping into your own control, you can decide which of the features you want to be available and which are omitted
  • It is possible to write some helper methods for generic properties since Ax does not support generics

Now let me show you how to do it.

Creating a custom WPF user control

First start of by creating a custom WPF user control. Open up visual studio and create a new project of the type WPF User Control Library. NewProject Since we are going to implement the vhCalendat control, add a reference to the vhCalendar dll file. (Found in the CodeProject post link above). Once the reference is in place and before going into XAML mode, let us take a look at the code behind file and put some things in place.

Control definition

First we have a partial class that defines the CalendarViewControl. Extending this later with your own stuff should be easy since it is a partial. public partial class CalendarViewControl : UserControl, INotifyPropertyChanged

Control properties

Now lets add properties for all of the calendar’s properties that we want to expose. (Here I will not show them all, just some examples)

/// <summary>
/// Gets/Sets the date that is being displayed in the calendar
/// </summary>
public DateTime DisplayDate 
{ 
    get 
    { 
        return (DateTime)theCalendar.DisplayDate; 
    } 
    set 
    { 
        theCalendar.DisplayDate = value; 
        RaisePropertyChanged("DisplayDate"); 
    }
} 
 
/// <summary>
/// Gets/Sets animations are used
/// </summary>
public bool IsAnimated 
{ 
    get 
    { 
        return (bool)theCalendar.IsAnimated; 
    } 
    set 
    { 
        theCalendar.IsAnimated = value; 
        RaisePropertyChanged("IsAnimated"); 
    } 
} 
 
/// <summary>
/// Gets/Sets the selection mode 
/// </summary>
public CalendarSelectionType SelectionMode 
{ 
    get 
    { 
        int i = (int)theCalendar.SelectionMode; 
        return (CalendarSelectionType)i; 
    } 
    set 
    { 
        int i = (int)theCalendar.SelectionMode; 
        theCalendar.SelectionMode = (SelectionType)i; 
        RaisePropertyChanged("SelectionMode"); 
    } 
}

The last property above shows a bit of ‘nasty’ code because I needed to translate the System.Windows.Visibility enum into a custom enum. This was because the CIL generator had a problem with the System.Windows.Visibility enum. CIL kept giving me the error : ‘Invalid cast’ until I used a custom enum.

Control events

Next to some properties, there are also a couple of events. The first one is to let Dynamics AX know that the selected date has changed.

public delegate void SelectedDateChangedEventHandler(object sender, EventArgs e); 
 
public event SelectedDateChangedEventHandler SelectedDateChanged; 
 
/// <summary>
/// Raised when the selected date changes in the calendar.
/// </summary>
public void RaiseSelectedDateChanged(object sender, vhCalendar.SelectedDateChangedEventArgs e) 
{ 
    if (SelectedDateChanged != null) 
    { 
        SelectedDateChanged(this, new EPSSelectedDateChangedEventArgs() { NewDate = e.NewDate, OldDate = e.OldDate }); 
    } 
}

Please note that the delegate is outside of the class but in the same namespace. Af of now, I’ve implemented single selection but there are also events in the calendar for when multiple selection changes.

Another important one is the RaisePropertyChanged event. This event will be useful to us when we are using binding in XAML. It will notify the control’s user interface that a property has changed and all of the UI elements that are bound to the corresponding property will be updated. (Note that the delegate PropertyChangedEventHandler is already known because our control implement INotifyPropertyChanged.

/// <summary>
/// Raised when one of the properties was changed in the WPF control
/// </summary>
public void RaisePropertyChanged(string propertyName) 
{ 
    if (PropertyChanged != null) 
    { 
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
}

Implement the control in Dynamics AX

Now for the AX part, start with creating a form with a ManagedHost control so that we can host the control. When you add the ManagedHost control, a windows will popup to select the control type that you want to use. In that window, select the reference to the dll (or browse for your dll) and select the type of control to use.

WPFDLLReference

 Next we need a way to handle the events of the calencar control. When we choose a date in the control, we need to be notified in X++ so that we can do what we want with it.

To do that, you can right click the ManagedHost control and select events. In the events window, you can now select our selectedDateChanged event and add an X++ handler method to it.

ManagedControlEventSelection

  The following code was added to our form ( Note that you can also use the ManagedEventHandler class when you are consuming external services asynchronously! ):

_ManagedHost_Control = ManagedHost.control();
_ManagedHost_Control.add_SelectedDateChanged(new ManagedEventHandler(this, 'ManagedHost_SelectedDateChanged'));

So when we open our form and we select a date in the calendar, the ManagedHost_SelectedDateChanged method will be called. So let’s open up the form and see what it looks like.

InitialCalendarView

Nice! But are we satisfied yet? Not quite…

Imho when implementing things like this, you should always keep in mind that others want to use your control in other contexts. Today I want to use it when selecting delivery dates but if we make some modifications, everyone can use this in any context they want.

What I did to achieve this is to create two things:

  • A property bag class that contains all of the properties that can be passed to the control.
  • An interface that forms need to implement when they want to host the control.

So first let’s take a look at the property bag. This is in fact merely a class with some parm methods on it. No PhD required here :)

/// <summary>
/// Data container class containing the parameters that can be set on the WPF control from inside Ax.
/// </summary>
public class EPSWPFCalendarParameters
{
    // Selection type of dates (single, multiple, ...)
    EPS.AX.WPFControls.CalendarSelectionType selectionType;
 
    // Start view of the calendar (month, year, decade, ...)
    EPS.AX.WPFControls.CalendarDisplayType displayType;
 
    // Date being displayed in the calendar
    System.DateTime displayDate;
 
    // Date from where the calendar displays dates
    System.DateTime displayDateStart;
 
    // Date to where the calendar displays dates
    System.DateTime displayDateEnd;
 
    // Use animation and transitions in the calendar
    boolean isAnimated;
 
    // Show the footer
    EPS.AX.WPFControls.CalendarVisibilityType footerVisibility;
 
    // Color the today's date in the calendar
    boolean isTodayHighlighted;
 
    // Show week columns
    EPS.AX.WPFControls.CalendarVisibilityType weekColumnVisibility;
 
    // Dates that will be marked as blocked and will not be selectable in the calendar
    Map blockedDatesList;
}

Apart from the parm methods, there is also an initialization method present so that some defaults are set in case they are not specified by the caller.

public void initDefaults()
{
    ;
    this.parmDisplayDate            (systemDateGet());
    this.parmDisplayType            (EPS.AX.WPFControls.CalendarDisplayType::Month);
    this.parmFooterVisibility       (EPS.AX.WPFControls.CalendarVisibilityType::Visible);
    this.parmIsAnimated             (true);
    this.parmIsTodayHighlighted     (true);
    this.parmSelectionType          (EPS.AX.WPFControls.CalendarSelectionType::Single);
    this.parmWeekColumnVisibility   (EPS.AX.WPFControls.CalendarVisibilityType::Visible);
    this.parmBlockedDatesList       (new Map(Types::Date, Types::Date));
}

Now for the next part, let’s create an interface that simply asures that forms hosting the control have a method to construct parameters for the calendar control.

/// <summary>
/// Interface for defining what is needed to be able to host the EPS WPF Calendar control on that form.
/// </summary>
public interface EPSWPFCalendarFormHostable { } 
 
/// <summary>
/// Calendar parameter data bag.
/// </summary>
/// <returns>
/// An instance of EPSWPFCalendarParameters 
/// </returns>
public EPSWPFCalendarParameters calendarParameters() 
{ }

This interface needs to be implemented on the caller form. Below we have an example of just that. (Note that for this example the code is on the form, but this should be done in a form handler class)

class FormRun extends ObjectRun implements EPSWPFCalendarFormHostable
 
/// <summary>
/// Contains parameters for the WPF calendar
/// <summary>
/// <returns>
/// An instance of EPSWPFCalendarParameters. 
/// </returns> 
public EPSWPFCalendarParameters calendarParameters() 
{ 
    ; 
    // Create default instance of the parameters 
    calendarParameters = EPSWPFCalendarParameters::construct(); 
 
    // Set the calendar selection mode to a single date 
    calendarParameters.parmSelectionType(EPS.AX.WPFControls.CalendarSelectionType::Single); 
 
    // Set the default view to a month 
    calendarParameters.parmDisplayType(EPS.AX.WPFControls.CalendarDisplayType::Month); 
 
    // Passes a map of dates to be blocked for selection in the calendar
    calendarParameters.parmBlockedDatesList(this.parmBlockedDeliveryDates()); 
 
    return calendarParameters; 
}

For the last part, we need to glue these together. This is done in the form where we host the calendar control. When the form is called, it requests the calendar parameters from the caller and applies all of them to the control.

public void init()
{
    SysSetupFormRun formRun = element.args().caller();
    ;
    super();
 
    // Check if the managed host is even the right type
    if(ManagedHost.control() is EPS.AX.WPFControls.CalendarViewControl)
    {
        calendarViewControl = ManagedHost.control() as EPS.AX.WPFControls.CalendarViewControl;
    }
    else
    {
        throw error("@EPS6008");
    }
 
    // Initialize from the caller interface (The caller should have implemented the interface that contains the calendarParameters)
    if(formHasMethod(formRun, 'calendarParameters'))
    {
        hostable = element.args().caller();
 
        // The hostable should have the parameters defined
        calendarParameters = hostable.calendarParameters();
 
        // Initialize the calendar control based on the found parameters
        element.initControlParameters();
    }
    else
    {
        throw error("@EPS6009");
    }
 
    // Register an event handler that attached to the selected date changed event of the calendar control)
    calendarViewControl.add_SelectedDateChanged(new ManagedEventHandler(this, 'ManagedHost_SelectedDateChanged'));
}

Note the formHasMethod call. This is an extra safety check. When using classes, the compiler makes sure that you have implemented the interface’s methods. But with forms, you never have a constructor called so that the compiler can do the check for you.

/// <summary>
/// Initializes the control based on the parameters found in the caller.
/// <summary>
private void initControlParameters() 
{ 
    Map blockedDates = calendarParameters.parmBlockedDatesList(); 
    MapEnumerator mapEnum; 
    TransDate fromDate; 
    TransDate toDate; 
    ; 
 
    calendarViewControl.set_SelectionMode (calendarParameters.parmSelectionType()); 
    calendarViewControl.set_DisplayMode (calendarParameters.parmDisplayType()); 
    calendarViewControl.set_FooterVisibility (calendarParameters.parmFooterVisibility()); 
    calendarViewControl.set_IsAnimated (calendarParameters.parmIsAnimated()); 
    calendarViewControl.set_IsTodayHighlighted (calendarParameters.parmIsTodayHighlighted()); 
    calendarViewControl.set_WeekColumnVisibility (calendarParameters.parmWeekColumnVisibility()); 
 
    if(calendarParameters.parmDisplayDate()) 
    { 
        calendarViewControl.set_DisplayDate (calendarParameters.parmDisplayDate()); 
    } 
 
    if(calendarParameters.parmDisplayDateStart()) 
    { 
        calendarViewControl.set_DisplayDateStart (calendarParameters.parmDisplayDateStart()); 
    } 
 
    if(calendarParameters.parmDisplayDateEnd()) 
    { 
        calendarViewControl.set_DisplayDateEnd (calendarParameters.parmDisplayDateEnd()); 
    } 
 
    // Pass the blocked out dates collection to the control. 
    if(blockedDates) 
    {
        mapEnum = blockedDates.getEnumerator(); 
        while (mapEnum.moveNext()) 
        { 
            fromDate = mapEnum.currentKey(); 
            toDate = mapEnum.currentValue(); 
            calendarViewControl.addBlockedDate(fromDate, toDate); 
        }
    }
}

So when all of this is in place, the calendar form calls the calling form and requests the parameters, passes them to the control and renders the control. Everyone that want to have the same control hosted on their for only need to implement the calendar parameters method on the form and that’s it.

When all is in place, this is what it looks like when the calendar has blocked days:

CalandarFinished1

 

When clicking on the month title, you can easily navigate between months and years:

CalandarFinished2

 

CalandarFinished3

 

So that is the end of it. I hope you already have some ideas as to what controls you can now host within Dynamics AX 2012. It is possible to create your own, but you can host any other WPF control if you want. (Think of Infragistics controls, Telerik, …)

System.Diagnostics.StopWatch

February 3rd, 2013 No comments

I often see code that still uses the WinApi::GetTickCount method to measure an interval of time. And though there is nothing wrong with it, I wanted to show an alternative method : the StopWatch already known in .Net for quite some time.
The sample below show the usage of the stopwatch while I was testing something out with looping all of the tables in the system:

static void FetchTableNames_ModelElementTables(Args _args)
{
    SysModelElement element;
    SysModelElementType elementType;
    System.Collections.ArrayList tableNames = new System.Collections.ArrayList();
    System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
    int64 elapsed;
    ;
 
    stopWatch.Start();
 
    // The SysModelElementType table contains the element types and we need the recId for the next selection
    select firstonly RecId
    from elementType
    where elementType.Name == 'Table';
 
    // With the recId of the table element type, select all of the elements with that type (hence, select all of the tables)
    while select Name
    from element
    where element.ElementType == elementType.RecId
    {
        tableNames.Add(element.Name);
    }
 
    stopWatch.Stop();
 
    // Get the time it took
    elapsed = stopWatch.get_ElapsedMilliseconds();
 
    info(strFmt("Time taken: %1", elapsed));
}

Propagate infolog messages to the windows event log

November 4th, 2011 No comments

The windows event viewer can be a nice tool to check for messages dispatched by the system. You can save the logs in there, reopen them, different kinds of information is available so you can actually trace lots of things in there. But wouldn’t it be nice to also be able to log the messages thrown by Ax 2012 in the windows event log?

That way you do not lose user messages and they are nicely logged into the event viewer. It can also help to log messages received on a client that you cannot seem to reproduce, …

Well, it is possible and here is how to do it in a couple of steps:

  • Add a windows event log and source to put our specific infolog messages in
  • Edit the Ax32 config file to add an event log listener to the configuration

Create event log and source

So first things first, let’s create a windows event log by using the following powershell command

new-eventlog -logname "RealDolmen Ax Solutions" -source "Ax 2012 Infolog"

The result should be like in the figure below

Configure the listener

To add a listener, first open the ax32.exe.config file located in the clientbin directory. You should see a configuration similar to this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0.30319" />
<requiredRuntime version="v4.0.30319" safemode="true"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="EditorComponents"/>
</assemblyBinding>
</runtime>
</configuration>

Modify the configuration so that it looks like this: (It is absolutely important to keep the source name !! The initializeData must be filled with the source you created in the event log)

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="Microsoft.Dynamics.Kernel.Client.DiagnosticLog-Infolog" switchValue="Information">
<listeners>
<!-- The initializeData contains the source that was linked to the created event log -->
<add name="EventLog"
type="System.Diagnostics.EventLogTraceListener"
initializeData="Ax 2012 Infolog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0.30319" />
<requiredRuntime version="v4.0.30319" safemode="true"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="EditorComponents"/>
</assemblyBinding>
</runtime>
</configuration>

Now we are all set up and when firing up the client, any messages to the infolog should be redirected to the event log. So let’s send some error lines to the infolog.

Now check if the same messages appear in the infolog. Normally this is what it should look like:

So there you have it. The messages are nicely logged in the event viewer. As a last remark, you can also adjust the logging level by modifying the switchvalue of the source. Off will not log anything at all, verbose will fill your event log with everything.

AX2012 Editor Extensions

November 3rd, 2011 No comments

Today I was reading a very interesting post about possible extensions to the editor in AX 2012 and I would very much like to share it.

Basically it explains that the editor is a hosted visual studio editor (that was already clear) and by knowing this, it is also possible to use the extensions that are available there to the editor inside Ax.
The post I read was dealing with the brace matching extension that is available to do automatic formatting of the braces.

You can read the full post here : http://dev.goshoom.net/en/2011/10/ax2012-editor-extensions/

Dynamics Ax 2012 Technical conference : Day 1 : Part 1

January 19th, 2011 6 comments

This articles will be brief, because I don’t have much time between the sessions J

Yesterdag was the first day of the Dynamics Technical conference and following sessions were attended by me:

  • Programming model improvements Part 1 of 2
  • Programming model improvements Part 2 of 2
  • Developing in .NET managed code and X++ Enhancements
  • Solving the element ID problem

Programming model improvements Part 1 of 2

From this session, I remember the following additional features:

  • Table inheritance is added. So now you can have abstract tables which are then inherited by child tables.
    The unit of work pattern also comes into play here as there will be issues to address to manage transactions and code dealing with one ‘virtual record’ which may consist of multiple child tables. (Vehicle table with child tables bycicle, car, truck, …)
  • Next to normal X++ temporary tables, there is now also support for temporary tables in SQL Server
  • Date effective tables have been added. This means you can actualy filter records based on an ‘effective as of date’
  • Eventing has been added so now you can actually subscribe methods to events on other classes. Also, this is implemented by drag and drop so it is actually user friendly to do this.
  • The normal batch framework has been ‘adjusted / replaced’ with the SysOperation framework
  • The tree of linked tables are then linked by RecId, but you can actually have a key with fields specified in a field group to be used in the design when showing on what the linked was based
  • Tables have full text indes support now : This means they can be optimized for searches on text fields to look for certain words in the body.

Historical data pattern

This one is actually cool. Let’s say you have a historical table to contain a history of sales. Then you can set properties on the SalesTable datasource and the kernel will keep the history for you. So when you change values on the sales order for example, the kernel will create / update records in the historical data table.

Query ranges vs Query filters

When using joins (outer joins) the query ranges can produce incorrect outcomes. But now query filters are used to fix that. Instead of using the QueryRange object on the query, you can now also use QueryFilter objects and they are more optimized for SQL Server.

The other sessions will be describes in following posts as there is new session beginning right now J

Dynamics Ax AIF Web Service reference credential problem

March 26th, 2010 3 comments
 

At a customer’s site, I was creating some extra AIF wcf services so that some extra tables would be externally available. For creating the WCF service, I was using the service wizard in Ax 2009 which is described here : http://msdn.microsoft.com/en-us/library/aa609947.aspx

The newly created service was deployed to the Internet Information Server but when the .Net application tried to reference the webservice, the following happened : The service was prompting for credentials and did not work properly.

WCF Service Reference Credential Prompt

After a certain amount of searching time and nearly giving up,  I was browsing the configuration file of the web services directory and discovered that the BindingMethod of the deployed services was configured to use basicHttpBinding.

Endpoint binding method basicHttpBinding

This was the actual problem because the wsdl looked like this : (negotiate authentication tags were added, …)

 

Wrong WSDL with negotiateAuthentication tag

Changing the binding method to wsHttpBinding creates the service without the negotiateAuthentication and takes care of our annoying credential problem.

Endpoint binding method wsHttpBinding

Using C# / XML / XSLT to create Excel Spreadsheet

August 21st, 2009 7 comments

This article will not go into the details of the SpreadSheetML format but is inteded to show a way of creating Excel spreadsheets programatically.
There are several ways to do this and this is only one of them so I am also not going to make comparisons between the different methods.

In this example we are going to do the following :

  • Create an XML file containing customers
  • Create a template from Excel
  • Adjust the template file and turn it into an XSL file
  • Transform the customer XML file to get the result we want

Creating the XML file

We are going to create a simple XML file using C# containing a list of Items. The following figure shows the fields available for an item.

tblinventTable

For this post, we are going to keep it simple and write three sample items in the XML file.
Normally this data would be fetched from a database but here we just export three sample items from the code.

CreateXml

The result is the following XML file :

RawXml

Creating the template

Now that we have the XML file (which is relatively simple to create from your application), we are going to create an excel file template that will be used to merge with the XML file to get the result we want.

So we fire up Excel and create a simple spreadsheet to contain the list of Items.

ExcelTemplate1

When we have our desired layout, we save the file as an XML spreadsheet.

FileType

Now it is getting interesting… We can open the XML file an there we see that it is saved in the OOXML format (SpreadsheetML in this case)

ExcelTemplate2

From here on we can change the template by adding XSLT code that will receive data from the Items.xml file and that way we can add a row for each item to our spreadsheet. (You many possibilities here. It is also possible for example to create a worksheet for each item, …)

First  we adjust the template to create an XSL file. So rename the ItemsTemplate.xml filename to ItemsTemplate.xsl.

Then adjust the xsl file by adding following code at the beginning of the document :

BeginDoc

Also add the closing tags at the end of the document.

To create a record for each item in the source XML file , we just need to do an xsl:for-each loop for each item and process the XML code generated by excel.

 ValueOfSelect

Before we continue, there is a little thing we still need to do because otherwise this will not be working. In the xml node “Table” we need to delete the attribute “ExpandedRowCount” otherwise excel will not be able to open the result document.

Now our template is ready to be used in a transformation with the source XML file.

Transform the XML

Following code shows how you can do XSLT transformation through C# code resulting in the final XML file.

TransformCode

The actual result looks like this in the XML file.

ResultXml

And this can be neatly opened in Excel and gives the following result.

ResultExcel