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.