Tuesday, September 27, 2011

Query and New Related Objects in AX 2012

With AX 2012, some new features were added for queries. For those of you who have access to the DEV manuals, one feature is lightly explained in DEV3, the other is absent in the current development manuals. So, time for a blog post!

Before we begin, I have to point out that there is a slightly annoying trend you will notice. One, the shift away from object IDs and to installation specific IDs. It seems that some new classes in AX 2012 now use element names (classstr, tablestr, etc) instead of tablenum, classnum etc. This is a good thing, however, for objects such as queries, it is annoying that the new classes are not consistent in the use of element identification (old classes use the ID, new classes the string).
Secondly, I'm not a fan of the Query classes having "build" in their names, but again, now there's new classes without "build" in the names, and old classes with "build". Very inconsistent and annoying. You'll see what I mean.

So, first new feature, which is touched upon in the DEV3 manual, is the "Filter" object, QueryFilter (not QueryBuildFilter as you may expect). This is a new counterpart to QueryBuildRange. The manual states it is used for outer joins, and filters the data "at a later stage". Unfortunate choice of words, and not very clear. To understand what's going on here, you need to understand what happens underneath the covers on the SQL level.

Let's look at the following scenario. We have a customer table, CustTable, and a sales order table, SalesTable, which has a foreign key relationship to the CustTable based on CustAccount. Let's say we want to retrieve a list of customers, and optionally any sales orders associated with each customer. To accomplish this, one would use an outer join. In SQL, this would translate as follows:

SELECT * FROM CUSTTABLE
        OUTER JOIN SALESTABLE ON SALESTABLE.CUSTACCOUNT = CUSTTABLE.ACCOUNTNUM

So far so good. Now let's say we want to show all customers, and show all sales orders associated with each customer, but ONLY the orders with currency EUR... In SQL, this gives us TWO options:

SELECT * FROM CUSTTABLE
        OUTER JOIN SALESTABLE ON SALESTABLE.CUSTACCOUNT = CUSTTABLE.ACCOUNTNUM
        AND SALESTABLE.CURRENCYCODE = 'EUR'

or

SELECT * FROM CUSTTABLE
        OUTER JOIN SALESTABLE ON SALESTABLE.CUSTACCOUNT = CUSTTABLE.ACCOUNTNUM
        WHERE SALESTABLE.CURRENCYCODE = 'EUR'

So what's the difference? In the first option, we use AND, which means the currencycode is part of the JOIN ON statement filtering the SALESTABLE. In the second option, using the WHERE keyword, the currencycode is part of the query's selection criteria... so what's the difference? If we filter the SALESTABLE using the ON clause, the CUSTTABLE will still show up, even if no SALESTABLEs with currency EUR exist, and it will just filter the SALESTABLE records. However, using a WHERE clause, we filter the complete resultset, which means no CUSTTABLE will be returned if there are no SALESTABLE records exist with EUR as the currency.

That is exactly the difference between QueryBuildRange and QueryFilter when used on an outer join. The QueryBuildRange will go in the ON clause, whereas QueryFilter will go in the WHERE clause. The following job illustrates this, feel free to uncomment the range and comment the filter, and vice versa, and test the results for yourself.

static void QueryRangeFilter(Args _args)
{
    Query                   query;
    QueryBuildDataSource    datasource;
    QueryBuildRange         range;
    QueryFilter             filter;
    QueryRun                queryRun;
    int                     counter = 0, totalCounter = 0;
    
    query = new Query();
    datasource = query.addDataSource(tableNum(CustTable));
    datasource = datasource.addDataSource(tableNum(SalesTable));
    datasource.joinMode(JoinMode::OuterJoin);
    datasource.relations(true);
    datasource.addLink(fieldNum(CustTable, AccountNum),
            fieldNum(SalesTable, CustAccount));
    filter = query.addQueryFilter(datasource,
            fieldStr(SalesTable, CurrencyCode));
    filter.value(SysQuery::value('EUR'));
    //range = datasource.addRange(fieldNum(SalesTable, CurrencyCode));
    //range.value(SysQuery::value('EUR'));
    
    queryRun = new QueryRun(query);
    while (queryRun.next())
    {
        totalCounter++;
        if (queryRun.changed(tableNum(CustTable)))
            counter++;
    }
    
    info(strFmt("Customer Counter: %1", counter));
    info(strFmt("Total result Counter: %1", totalCounter));
}

So, I can hear you thinking "Why is this useful? I could just use an inner join!". Good catch! One of the main reasons this was introduced is for the user interface. Some screens use outer joins, which works fine. However, when a user filters on fields on the form, the result may not be what that user expects. With a queryBuildRange (as in AX 2009), the query would only filter the joined datasource. So now some fields are showing as empty and read-only (because there is no actual record since it was filtered), but some fields are still showing up (the parent datasource).
In this situation, using QueryFilter makes sense. And in fact, AX by default now uses QueryFilter on Forms for any filters a user adds.

Next, the feature that is not mentioned in the DEV books: QueryHavingFilter. For those of you familiar with SQL statements, you are probably aware of the HAVING statement.

Consider the following scenario. The CUSTTABLE table has a field called CUSTGROUP, indicating the customer group the customer belongs to. We would like to get a list of all customer groups that have less than 4 customers in them.
Traditionally, in AX queries, we can group by the CUSTGROUP field, COUNT the RecIds. However, there was no way to filter on that counted RecId field. However, in SQL, the having statement gives you that ability:

SELECT CUSTGROUP, COUNT(*) FROM CUSTTABLE
	GROUP BY CUSTGROUP
	HAVING COUNT(*) < 4
In AX you can count, group by, but you'll need to loop over the results and check the counter manually if you want to filter values out. So, in AX 2012, a new query class was added: QueryHavingFilter, that lets you do just that:
static void QueryHaving(Args _args)
{
    Query                   query;
    QueryBuildDataSource    datasource;
    QueryBuildRange         range;
    QueryHavingFilter       havingFilter;
    QueryRun                queryRun;
    int                     counter = 0, totalCounter = 0;
    CustTable               custTable;
    
    query = new Query();
    datasource = query.addDataSource(tableNum(CustTable));
    datasource.addSelectionField(fieldNum(CustTable, RecId),
            SelectionField::Count);
    datasource.orderMode(OrderMode::GroupBy);
    datasource.addGroupByField(fieldNum(CustTable, CustGroup));
    
    havingFilter = query.addHavingFilter(datasource, fieldStr(custTable, RecId),
            AggregateFunction::Count);
    havingFilter.value('<4');
    
    queryRun = new QueryRun(query);
    while (queryRun.next())
    {
        custTable = queryRun.getNo(1);
        info(strFmt("Group %1: %2", custTable.CustGroup, custTable.RecId));
    }
}

Note that in this code example, I added a selection field on RecId and used SelectionField::Count. This is not necessary for the having filter to work, the only reason it is in the code example is to be able to show it in the infolog (ie to have the count value available). So it is independent of the HavingFilter!


Unfortunately, the HAVING statement is not yet added to the inline SQL statements of X++. So currently the only way to use this feature is by using query objects.

AX 2012 Testing Best Practices

Dave Froslie just announced on his blog that the whitepaper "Testing best practices for AX 2012" is now available for download on Microsoft's download center.

It is a good read about ALM (Appliction Lifecycle Management) for AX code both in X++ and Visual Studio, and some guidelines and thoughts on testing, unit testing, gathering requirements, peer reviews, etc.


I've added the whitepaper download to the ALM/TFS page. I will start posting more new AX2012 content soon, including TFS articles. It's overdue. There has been the multi-developer single AOS whitepaper, which I thought was a little disappointing, so I'll make sure to give my thoughts and suggestions on those matters.

Thursday, September 22, 2011

AX 2012: Multiple Instances of Reporting Services on the same server

Ok, this was a huge deal in AX 2009 in my opinion. During the TAP program of AX 2012, a whitepaper was released on how to do this, but we've had to wait until now for Microsoft to make it public.
So, yes, it is now possible to have several instances of SQL Reporting running on the same box, connecting to different AOSes. Note that you do need a separate instance of SQL reporting (not one instance connecting to different AOSes), but even that was not possible with AX 2009.

You can find the information on technet at http://technet.microsoft.com/en-us/library/hh389760.aspx.

(Source: EMEADaxSupport blog)

Tuesday, September 20, 2011

Deploying your AX 2012 Code

Yesterday I talked about deploying .NET assemblies, how they get automatically deployed for any Visual Studio projects you have. At the end, I talked briefly about X++ code and the CIL assemblies. I will take that a bit further today. If you haven't read the Microsoft whitepaper on "Deploying Customization Across Microsoft Dynamics AX 2012 Environments" I suggest you take a look at that, it's a good read.

We had a gathering with some other MCTs at Microsoft's offices in Fargo, and we had a big discussion around deploying the customizations, and the "high availability" scenario where you want to deploy code, but avoid too much downtime. But let's not get ahead of ourselves too quickly.

[Editing note: I admit, I like to rant. Please bear with me, I promise it will get interesting further down :-)]

I made this statement to one of our clients a few months ago, and I'd like to share it with you: moving XPOs is barbaric. Yes, barbaric. As AX developers, administrators, implementers and customers we need to move on. Yes, moving XPOs has some benefits, but they are all benefits to circumvent proper procedure. The benefit of moving one piece of code? That's introducing risk and circumventing proper code release management (branching and merging for the version control aficionados). The benefit of no downtime? That is bad practice, what about users that have cached versions of your code running in their sessions? Not to mention data dictionary changes. The benefit of not having to recompile the whole codebase? Talk about bad practice again, and all the possible issues that come out of that. Sure, you say, but I am smart and I know what I can move without risk. Famous last words. And that's not a reason to circumvent proper code release procedures anyway. Here's my take:

1) Code should be released in binary form. For AX 2009 that means, layers. In AX 2012, we have models.
Have you ever received a .cpp or .cs code file from Microsoft containing a patch for Windows or Office? Didn't think so.

2) Released code should be guaranteed to be the same as the tested code (I'm sure your auditors will agree)
When importing an XPO there is an overwrite and/or merge step that happens. This is prone to user error.
Also, who is importing the XPO? If there is no chance of doing anything wrong or different, can't you just have a user do it? Yeah, didn't think so either.

3) You should schedule downtime to install code updates
Sure, AX doesn't mind a code update while that code is still running. A binary update? Not so much, you need to restart the AOS.
Remember Windows asking to restart the system after an update was installed? Yes, there's a good reason for that, to replace stuff that's in use.

I can keep going for a while, but those are my main points. So, back to AX 2012. I will relate this to the points above.

1) Models are binary files. The .AxModel files are technically assemblies, if you open them up in Reflector or ILSpy you won't see too much though, it contains the model manifest (XML) as a resource, and a BinaryModel resource. The model is a subset of a specific layer, so it's a more granular way to move code than moving layers was in AX 2009. But, just like in AX 2009, since this is not the full application, after installing the model one should compile the application. An additional reason to do so in AX 2012 is the fact that the model also contains compiled X++ p-code. Any references to other classes, fields, etc gets compiled into IDs. In 2012, those IDs are installation-specific. That means your code using field ABC may have been compiled to use fieldID 1, but perhaps in the new environment you're importing this model into, the field ABC is really fieldID 2. So now your code, when run, will reference the wrong field (you can actually test this, it's freaky). So, compiling is a necessity. Also think of situations where your model modifies a base class. The whole application needs to be recompiled to make sure all derived classes get your update compiled into them (yes, you can do compile forward, assuming the person installing the model is aware of what is actually in the model).
You can replace an existing model. This avoids the typical XPO issue where you need to import with "delete elements" enabled. Which you can't always do since you may not want to remove other fields that are not in your XPO, but belong to another project. The model knows what it contained previously, and what it contains now, and will only delete the specific changes for your model. One thing to remember is that you should never uninstall the old model and install the new one. This will likely cause havoc in your object IDs, which means tables will get dropped and recreated rather than updated!

2) Obviously by exporting the model from an existing environment where you tested, the code will be the same. Same confidence as moving layers in previous versions of AX. Another method is moving the code using branch merging in a source environment, and creating a binary build out of that. In this case you are branching a known and tested set of code, and have full traceability of the code as it progresses through your testing and release processes.

3) Ok, this is all great, but... compiling in AX 2012 takes a LONG time compared to AX 2009. And then we need to generate the CIL as well (which doesn't take that long in my experience)! So you catch my drift on the whole binary deployment, you see what I mean with matching released code to tested code... and starting the AOS is one thing, but having to recompile and wait for that to complete? That could be some serious downtime!

Enter.. the model store! Think about this. The model store today, is what the APPL directory used to be in previous releases. It contains EVERYTHING. The layers, which contain the code, the labels, etc. So, it contains the compiled code as well. In fact, the model store even contains the generated compiled IL code. So, going back to the "Deploying Customization Across Microsoft Dynamics AX 2012 Environments" whitepaper. It has this section called "import to the target system". To avoid downtime, you should have a code-copy of your production environment ready, where you can replace models, do whatever you need, and then compile the application and generate the CIL for X++. This is what the whitepaper means with the "source system". When that system is fully prepped, you can export the FULL model store. Again, this contains source code, compiled code, CIL and even your VS projects' built assemblies!
To further avoid down time, you can import the model store into production (the "target" system in the whitepaper) using a different schema. This basically lets you "import" the modelstore without disturbing the production system. Then, whenever you are ready, you can stop the AOS, and apply your temporary schema, effectively replacing the code in production with the code you built. The only thing you have to do still, after starting the AOS, is synchronize the database (and deploy web and reporting artifacts). And of course, clean up the model store's old schema.

So, when you start up the AOS, it will recognize the changed CIL in the modelstore, and download it to its bin\vsassemblies directory (see my previous article).

Now that's what I call high availability. So... no more reason to not move code in binary form! No more barbarism.

Monday, September 19, 2011

AX 2012 .NET Assembly Deployment

Compared to AX 2009, assemblies in AX 2012 work a bit differently. One of the obvious differences is the introduction of visual studio projects. However, deploying the assemblies works differently, in our favor (of course!). There are a few things we need to keep in mind though, and definitely a few bad habits from AX 2009 to get rid of!

AX 2012 improves assembly deployment and referencing. For the client side of things, this means the assemblies no longer need to be copied to the client/bin folder. The development manuals for AX 2012 INCORRECTLY state that the assembly automatically gets downloaded by the client to the client bin folder. This is incorrect. The assemblies get downloaded to %USERPROFILE%\AppData\Local\Microsoft\Dynamics AX\VSAssemblies . The %USERPROFILE% by default on Windows 7 should be C:\Users\username so if your user name is DAXMUSINGS, the assemblies will be in C:\Users\DAXMUSINGS\AppData\Local\Microsoft\Dynamics AX\VSAssemblies . Make a correction in your 2012 development manual!
Since the assemblies are kept by user, that means in a multi-user environment such as terminal services or Citrix, there is no need for all users to log out (ie all client executables closed so no more assembly files are in use) before a new assembly can be deployed. First, you don't have to deploy, AX does it for you. Secondly, any time a user restarts AX, it will download the new assemblies where and if needed. It also means different users could have different versions of your code in use. This could happen traditionally with X++ as well, so it's always a good idea to schedule downtime to deploy new code, managed or otherwise.

So, when you build a Visual Studio project and click "deploy" in Visual Studio (or, in fact, if you just build the project and then restart your AX client), your AX client will, the next time it needs the assembly, detect a newer version of the assembly and copy it into the VSAssemblies directory. Also note that you can in fact build the project from the AOT. When you right-click/compile on a Visual Studio project, AX builds the project and thus a new assembly.

What happens on the server side? A similar thing, except here the assemblies are deployed to the server bin/VSAssemblies . By default, the AOS runs in 1 AppDomain which means you need to restart the AOS server to get the new assembly. But, in a developer environment you may be recompiling your assembly a lot, so to avoid having to restart your AOS constantly, hotswapping was enabled for the AOS. Check this MSDN page for more information. You should definitely never enable hotswapping in a production environment!

So, for anyone who has dealt with VS projects in previous versions, please don't copy assembly DLLs into your BIN directories. It will deploy automatically, refresh automatically, and load automatically. Also remember you don't have to explicitly add your Visual Studio's project as a reference in the AOT. The fact that it is an AOT VS project makes it available as an implicit reference anywhere in X++ . If you missed it previously, you may want to check out the managed code series for a look on how to create managed code projects.

Then there is the X++ compiled to IL. Those are assemblies too! Well, X++ is kept in the model store now. This includes the X++ source, the X++ p-code, and the X++ compiled IL. These compiled pieces are versioned, and the AOS will download newer versions of the X++ assemblies to it's server bin/XppIL folder, including the PDB files so you can debug that X++ running in the CLR using Visual Studio.

Friday, September 16, 2011

Windows 8

As you may or may not have heard, this week at the build conference, the Windows 8 Developer Preview was released. You can go over to the build website, watch the keynotes (good overviews), and download the ISO files for the Windows 8 build.
We've installed it here on a laptop, and it's nice to see the work in progress. Stressing the work in progress. We've already had to reinstall it, after switching the laptop between docking station and running stand-alone, the new start screen got very confused on what monitor to be on, and decided to just disappear altogether. In any case, it's cool to play around, it also has IE10 on it and Visual Studio Express 11, which I haven't had time to check out yet. Make sure to watch some of the videos on the build website, they show off some good tech stuff, developing against the WinRT API using Javascript, etc.

A good friend of mine, Kevin Dockx, who is a frequent speaker on SilverLight at Microsoft events (and has written books on the subject), has put together a quick overview and his take on the whole new API, JavaScript development, etc. Check it out here. It's a good overview for developers in case you don't want to watch all the Build conference material.

I agree with him that the new Metro-style and start screen are great for touchscreens, but are pretty clumsy on mouse and keyboard. We have to keep in mind though that this is an early preview, so we'll see how this ends up in the final product. For those who were involved in the AX 2012 beta program, you know how for example the sales order screen was initially redesigned (short story: it was pretty bad). Microsoft did take the beta participants' feedback and reworked that to something way more user friendly. So let's not scream too hard just yet, there's a ways to go with Windows 8 development.
What I like a lot is the new multi-monitor support. It's gotten better over the years, especially with Windows 7, but I feel like the new features (taskbar per monitor, options for showing all or only windows on that monitor, etc) finally equal what other OSes and third-party plugins have offered for years now.

I've tried to install the AX2012 client on Windows8, but it threw an exception while checking prerequisites. I'll try again later but at least it won't work right out of the box (yet).

Thursday, September 8, 2011

AX 2012 Virtual Launch

If you haven't heard, this morning is the AX 2012 Virtual Launch event. Keynote from Steve Ballmer and Kirill Tatarinov followed by Gartner analyst Nigel Montgomery. Make sure to head on over to http://www.microsoft.com/dynamics/ax2012launch/ which will also allow you to replay the keynote in case you missed it!

Obviously, Microsoft is making a big deal out of this release. And rightfully so. There have been more changes in this new release than the last three releases combined! If you've been following my blog, you've noticed all the new technical features which I've been explaining. And I'm far from done. Of course, I only blog about technical topics, but there is just as much excitement on the functional side.

Back in the old days, before Microsoft acquired this product called 'Axapta', we used to not even bother "deploying" the AX client to customer's computers. We just copied the executable and some DLLs from the install CD onto a shared folder on the network, and just gave all users a shortcut to the executable. It's tough to put it all in words, but it's pretty incredible how far Microsoft has brought this product. To me as a developer, who happened to land a job coding in this small but promising Danish product, it is great to see the progress, and with this 2012 release the type of investment Microsoft has made to push an already leading edge platform and take it to the next level. I'm happy to see my job is safe for quite a few years to come. I worked for VARs that also did other ERPs, and it was sad to see some great functional products getting lost in today's technology, being bought and sold, with no roadmap or hope for an overdue technology facelift (you know who you are!).

AX has always been at the forefront of technology in the ERP world. And it's obvious Microsoft is all-in to make sure it stays that way. I was in Fargo this week (one of the major Microsoft campuses for Dynamics) and it is clear there is a vision and a goal. Looking at the changes, both architecturally and technically, it is clear where things are going. Technologies are converging. Using C# with AX (and making X++ a managed language). Sharepoint. SQL Reporting. Office add-ins. WCF. WPF. Workflow.

These are exciting times, and I'm glad to be a part of it. Next stop - the cloud.

Tuesday, September 6, 2011

10-Minute AX 2012 App: Windows Azure (Cloud)

Powerfully simple put to the test. If you missed the first article, I showed you how to create a quick WPF app that reads data from AX 2012 queries and displays the results in a grid. In this article, I will continue showing you how easy it is to make use of AX 2012 technology in conjunction with other hot Microsoft technologies. Today, we will create a Windows Azure hosted web service (WCF), to which we'll have AX 2012 publish product (item) data. Again, this will take 10 minutes of coding or less. Granted, it was a struggle to strip this one down to the basics to keep it a 10-minute project.

Windows Azure is Microsoft's cloud services platform. We'll be creating a web role here, hosting a WCF service. The idea I'm presenting here is an easy push of data out of AX to an Azure service. There, one could build a cloud website or web service, for example to serve mobile apps (Microsoft has an SDK to build iOS, Android and Windows Phone 7 apps based on Azure services). We'll spend most time setting up the Azure WCF service (and a quick webpage to show what's in the table storage), and finally we'll create a quick AX 2012 VS project to send the data, and hook that into AX using an event handler!
So, we'll build an Azure WCF service using Table storage (as opposed to BLOB storage or SQL Azure storage). Make sure to evaluate SQL Azure if you want to take this to the next level. So, our ingredients for today will require you to install something you may not have already...

Ingredients:

* Visual Studio 2010
* Windows Azure SDK (download here)
* Access to an AX 2012 AOS

Now, the Azure SDK has some requirements of its own. I have it using my local SQL server (I did not install SQL Express) and my local IIS (I did not install IIS express).

Ok, everything installed and ready? Start the timer! You need to start Visual Studio 2010 as administrator. So right-click Visual Studio in your start menu and select "Run as Administrator". This is needed to be able to run the Windows Azure storage emulators. We'll start a new project and select Cloud > Windows Azure Project. I've named this project "DAXMusings.Azure". Once you click OK, Visual Studio will ask you for the azure role and type of project. I've select "WCF Service Web Role". Click the little button to add the role to your solution. Also, click the edit icon (which won't appear until your mouse hovers over it) to change the name to "AXCloud".


Ok, first things first, setup the data connection for the table storage. Right-click on the "AXCloud" under "Roles" and select properties.


Under settings, click the "Add Setting" button, name it "DataConnectionString", set the drop down to... "Connection String", and click the ellipsis. On that dialog screen, just select the "Use the Windows Azure storage emulator" and click OK.


Hit the save button and close the properties screen. So, what we will be storing, and communicating over the webservice, is item data. So, let's add a new class and call it ItemData. To do this, we right-click on the AXCloud project, and select Add > New Item. On the dialog, select Class and call it "ItemData".




So, here's the deal. For WCF to be able to use this, we need to declare this class as a data contract. For Azure table storage to be able to use it, we need three properties: RowKey (string), Timestamp (DateTime) and PartitionKey (string). For item data, we will get an ITEMID from AX, but we'll store it in the RowKey property since that is the unique key. We'll just add a Name property as well, to have something more meaningful to look at. To support the data contract attribute, you'll need to add the namespace "System.Runtime.Serialization" and for the DataServiceKey you need to add the namespace "System.Data.Services.Common". The PartitionKey we'll set to a fixed value of "AX" (this property has to do with scalability and where the data lives in the cloud; also, the RowKey+PartitionKey technically make up the primary key of the data...). We'll also initialize the Timestamp to the current DateTime, and provide a constructor accepting the row and partition key.

Click here for screenshot or copy the code below:

namespace AXCloud
{
    [DataContract]
    [DataServiceKey(new[] { "PartitionKey", "RowKey" })]
    public class ItemData
    {
        [DataMember]
        public string RowKey { get; set; }

        [DataMember]
        public String Name { get; set; }

        [DataMember]
        public string PartitionKey { get; set; }

        [DataMember]
        public DateTime Timestamp { get; set; }

        public ItemData()
        {
            PartitionKey = "AX";
            Timestamp = DateTime.Now;
        }

        public ItemData(string partitionKey, string rowKey)
        {
            PartitionKey = partitionKey;
            RowKey = rowKey;
        }
    }
}


Next, we'll need a TableServiceContext class. We'll need to add a reference to "System.Data.Services.Client" in our project. Just right-click on the "References" node of the AXCloud project and select "Add Reference". On the .NET tab, find the "System.Data.Services.Client" assembly and click OK.



For easy coding, let's add another using statement at the top as well, for the Azure storage assemblies.


And we'll add the Context class. This will provide a property that's Queryable, and an easy way to add an item through an AddItem() method.

Click here for screenshot or copy the code below:

    public class ItemDataServiceContext : TableServiceContext
    {
        public ItemDataServiceContext(string baseAddress, StorageCredentials credentials)
            : base(baseAddress, credentials)
        {
        }

        public IQueryable Items
        {
            get
            {
                return this.CreateQuery("Items");
            }
        }

        public void AddItem(string itemId, string name)
        {
            ItemData item = new ItemData();
            item.RowKey = itemId;
            item.Name = name;

            this.AddObject("Items", item);
            this.SaveChanges();
        }
    }


So, first time we use this app (or any time you restart your storage emulator), the table needs to be created before we can use it. In a normal scenario this would not be part of your application code, but we'll just add it in here for easy measure. Open the "WebRole.cs" file in your project, which contains a method called "OnStart()". At the top, add the using statements for the Windows Azure assemblies. Inside the onstart() method, we'll add code that creates the table on the storage account if it doesn't exist.


Click here for a full screenshot or copy the below code to add before the return statement:

CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSettingPublisher) =>
{
	var connectionString = Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(configName);
	configSettingPublisher(connectionString);
}
);

CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

storageAccount.CreateCloudTableClient().CreateTableIfNotExist("Items");


Next, we'll create a new operation on the WCF service to actually add an item. Since we already have all the ingredients, we just need to add a method to the interface and its implementation. First, in the IService.cs file, we'll add a method where the TODO is located. You probably want to remove all the standard stuff there, but to keep down the time needed and to make it easier for you to see where I'm adding code, I've left it in these screenshots.


Now, into the Service1.svc.cs we'll add the implementation of the method, for which we'll need to add the Windows Azure using statements again:



Click here for a full screenshot or copy the code below:

public void AddItem(ItemData item)
{
    CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSettingPublisher) =>
    {
        var connectionString = Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(configName);
        configSettingPublisher(connectionString);
    });

    CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

    new ItemDataServiceContext(storageAccount.TableEndpoint.ToString(), storageAccount.Credentials).AddItem(item.RowKey, item.Name);
}


So now the last thing to do is create a class the consumes this service, which we can use as a post event handler for the insert() method on the InventTable table in AX... I am skipping through some of the steps here, but basically, we create a new class library project in Visual Studio (open a second instance of Visual Studio, since we'll need to keep the Azure service running!), and "Add it to AOT". For a walkthrough on how to do this, check this blog article. We're calling this class libary "DAXMusings.ItemSubscriber".
Alright, when you have the new project created and added to the AOT, we need to add a service reference to the Azure WCF service. Since we're running all of this locally, you'll need to make sure the Azure service is started (F5 on the Azure project). This will open internet explorer to your service page (on mine it's http://127.0.0.1:81/Service1.svc). If Azure opens your web site but not the .svc file (you probably will get a 403 forbidden error then), just add "Service1.svc" behind the URL it did open. If you renamed the WCF service in the project, you'll have to use whatever name you gave it.
So, we'll add that URL as a service reference to our subscriber project, and I'm giving it namespace "AzureItems":


Now that we have the reference, we will make a static method to use as an event handler in AX. First, we need to add references to XppPrePostArgs and InventTable by opening the Application Explorer, navigating to Classes\XppPrePostArgs and Data Dictionary\Tables\InventTable respectively. For each one, right-click on the object and select "Add to project" (for more information on the why and how, check this blog post on managed handlers).
Next, there's one ugly part I will have you add. Since the reference to the service is in a class library, which will then be used in an application (AX), the service reference configuration (bindings.. the endpoint etc) which gets stored in the App.config for your class library, will not be available to the AX executables. Technically, we should copy/paste these values into the Ax32Serv.exe.config (or the client one, depending where your code will run). However, this would require a restart of the AOS server, etc. So (.NET gurus will kill me here, but just remember: this is supposed to be up and running in 10 minutes!) for the sake of moving along, we will just hardcode a quick endpoint into the code...

Click here for full screenshot of the class.

public static void InventTableInsertHandler(XppPrePostArgs args)
{
    InventTable inventTable = new InventTable((Microsoft.Dynamics.AX.ManagedInterop.Record)args.getThis());
    AzureItems.ItemData itemData = new AzureItems.ItemData();
    itemData.RowKey = inventTable.ItemId;
    itemData.Name = inventTable.NameAlias;

    System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
    binding.Name = "BasicHttpBinding_IService1";
    System.ServiceModel.EndpointAddress address = new System.ServiceModel.EndpointAddress("http://127.0.0.1:83/Service1.svc");
    AzureItems.Service1Client client = new AzureItems.Service1Client(binding, address);

    client.AddItem(itemData);
}


Notice how the URL is hardcoded in here (this is stuff that should go into that config file). One thing I've noticed, with the Azure project running emulated on my local machine, that it seems to change ports every now and then (I started and stopped it a few times). So you may need to tweak this while you're testing this stuff out.

So last thing to do is add this as a Post-Handler on the InventTable insert() method... (for more information and walkthrough on adding managed post-handlers on X++ objects, check this blog post)


Time to add an item and test! If you wish to debug this to see what's going on, remember the insert method will be running on the AX server tier so you need to attach the debugger to the AOS service.


How do you now know your item was actually added in the Azure table storage? Well, I will post some extra code tomorrow (a quick and dirty ASP page that lists all items in the table).

I am expecting you will run into quite a few issues trying to get through this exercise. I know I have, some of them were minor things but took me hours to figure out what I was missing. Feel free to contact me or leave a comment, and I'll try to look into each issue.

Monday, September 5, 2011

New Design and New Articles

If you haven't noticed yet, Dynamics AX Musings has a new design. This is something I've been wanting to do for a while, so nothing better than a long weekend to do it. On top of that, I've gone through old posts and fixed all the large screenshots that were running into the right-hand menu. Going forward, rather than just a screenshot, the new design will allow me to post some code that you can copy/paste. Hopefully this will improve the usability of the articles in the future. I realize this will not show up properly in the syndication of this blog, including the syndication on community.dynamics.com but I will make sure to provide a link to the actual blog article every time. I will also still continue to provide a link to a screenshot for those who prefer that.

A link to the screenshot will go here.

public void Example()
{
    info("this is an example of what it will look like");
}


On top of that, I will soon be providing downloads for all the code belonging to the big articles, including all the managed code ones, the WPF code, etc... and will continue doing that for all the future articles to come.

For those who are waiting on the continuation of the 10-minute apps for AX 2012, I will post the next one tomorrow (it's actually finished except for the new inline code).

So thanks for being patient, and hopefully you will find that the new inline code and project downloads were worth the wait!

Thursday, September 1, 2011

AX 2012 Licensing

There's a lot of questions surrounding licensing and AX 2012, especially around user licensing. Just wanted to do a quick post and bring your attention to two blogs tackling some of these questions:

1) Becky Newell from Microsoft posted a blog article explaining the licensing and how to obtain them
2) Matrin DrĂ¡b on his Goshoom.NET DEV blog posted some more details on the licensing and useful links to partnersource and other resources