Blog

Resolving X++ and metadata conflicts when merging code

In the near future, Microsoft will seal off customizations/overlayering in Dynamics 365 for Operations. Once that happens, and VAR/ISVs catch up, you won’t have the same problems with conflicts while merging code from various sources (including Microsoft’s own X++ hotfixes). Until then, though… I found the process of properly resolving conflicts to be not completely intuitive, and ended up doing unnecessary manual work and comparison for a while. Here’s how to do it the right way (also the easier way), with a little-known secret or two to help.

You probably already know that after merging in new models, you need to go to Dynamics 365 > Addins > Create project from conflicts in Visual Studio to check for conflicts.

Resolve Conflicts 0a

After doing so, you need to select which model to look for conflicts in. Yes, you need to do them one at a time. Yes, the dialog disappears after each check, making it a hassle to use if you are juggling models from a bunch of different ISVs.

Resolve Conflicts 0b

To save time, be smart about which models you check. You only need to check third party “customization” models, not “extension” models. (Comment if you know of a way conflicts can appear in extension models!) If you’re savvy, you might be able to limit it further, if you know who is changing which objects. But play it safe; you don’t want to miss any conflicts!

Assuming you actually hit a conflict… it’s going to need to create a project. I like to use a naming scheme like ModelNameConflicts_YYYYMMDD to make it easy to clean up later.

The project will be created, and it will contain any and all objects that have conflicts. Here’s where it got confusing for me; intuitively, I thought I’d want to right-click the object and choose “Compare and Merge Code” or something. Nope! Start out by just opening the object.

Resolve Conflicts 1

Once you open it, it won’t be obvious where the conflicts are. They’re marked, but if it’s a big complex object, it might be hard to find them.

The secret?… put “cf:” in the search bar and hit enter.

Resolve Conflicts 2

The object will be filtered to show you the conflicts. (See the little red double arrows icon?)

What you do next depends on whether the conflict is in metadata or in code. It’s not that different, though. One at a time, right click each object, and choose either “Resolve property conflicts” or “Resolve code conflicts.”

If it’s a property conflict:

Resolve Conflicts 3

If you are resolving a property conflict, you’ll get a GUI that you hopefully find intuitive.

Resolve Conflicts 4

If it’s a code conflict:

Resolve Conflicts 5

If you are resolving a code conflict, you’ll be given a DIFF tool to do the merge. This post is not meant to fully explain code merges, but it might be intuitive for you anyway, even if you aren’t already familiar with the concept.

Resolve Conflicts 6

Whether you’ve done a property merge or a code merge, you’ll be able to mark the conflict as resolved, so it won’t come up if you do another check for conflicts.

However, re-merging models might cause the conflict to pop up again, if your ISVs (or whomever you are merging from) do not integrate the merged changes. So, be prepared to re-check in the future, and possibly correct the same conflicts repeatedly!

Doing a code merge when a VAR/ISV has renamed an object

This is probably general to Visual Studio (or any other development tool and source control), and not specific to Dynamics 365 for Operations; but after it ate up several hours of my life figuring out why a build wasn’t working, I thought I should share.

What might be unique (or at least more prevalent) in our world of Dynamics 365 for Operations is the need to do a “code merge” from multiple ISVs or VARs. Chances are it will become almost routine for you, and unless Visual Studio gets better at it, after a few months you’ll be routinely promoting changes that aren’t automatically picked up in “Pending Changes.”

Unfortunately, if you get used to promoting both adds and deletes all over, you might miss that renames should be treated specially. You might inadvertently end up with two copies of the object in source control, one with the old name and one with the new name… and, unless you’re sharper than me (certainly possible!) you’ll spend a lot of time puzzling out why your build won’t work but your local compile does, even though your source seems synched. (But, you might eventually notice, the names in your Application Explorer don’t match your file names…!)

Anyway, the meat of the matter is: make sure to watch out for renames, and promote them by highlighting the relevant “delete” and “add” together, right-clicking, and choosing “Promote as Rename.”

Promote as Rename

 

And as a tip  to those working for an ISV/VAR: try to avoid renaming objects once they’ve been checked in, and pass along warning if you do. Maybe your client will have no problem if you don’t… but there’s a chance you’ll be saving them a long night if you do!

Table Browser

How to use the table browser in the D365O web interface.

This neat tip can be found in a few other blogs, but I’ve found it so useful that I want to increase its visibility… and put it together with some other useful info in one place.

Although there isn’t a direct method to get to it through the UI, you can open the “table browser” (which you might recognize from inside Visual Studio) to look at the contents of one of the back end database tables. You’ve got to take your URL and change the part after the slash like so:

http://<host>/Default.htm?mi=SysTableBrowser&tablename=<tn>&cmp=<company>

Obviously, you need to fill in the appropriate <host>, <tn>, and <company>; for example:

https://usnconeboxax1aos.cloud.onebox.dynamics.com/Default.htm?mi=SysTableBrowser&tablename=CompanyInfo&cmp=DAT

…will produce, on your dev VM, the table browser for table CompanyInfo and the DAT company:

Table Browser

If you see this tip elsewhere, you will sometimes see a few other URL parameters in there; lng=<language>limitednav=true (hides parts of the UI like the navigation pane and filters), and prt=<partition> (deprecated partition functionality) are commonly added. I don’t think you are likely to need them, but you can look at other blog posts explaining what those (and other) optional parameters do.

Catch CLR errors in X++ in Dynamics 365 for Operations

Although there are useful posts out there on catching CLR errors in X++ for older versions of Dynamics AX, as of this writing, I couldn’t find one that address the current version. It took me a little experimentation and trial-and-error to figure out how to do it; in particular, to actually return a useful error message, instead of just a generic CLR error. Below is the pattern I use. For simplicity, I’m leaving out some of the other types of CATCH you might use, as well as other detail irrelevant to the pattern.

As usual, I would greatly appreciate comments on whether this works for you, and if you know of any improvements.

Logging in to SQL Server in the developer VM

Connecting to SQL Server in the Dynamics 365 for Operations development VM

This post assumes you are comfortable in the use of SQL Server. If you are not, this is a good entry to go ahead and skip.

EDIT: This post might not be necessary. I am told that due to UAC, all you need to do is launch SSMS using “run as administrator” instead. I’ll leave what I wrote here for historical purposes (it’s still interesting) but you don’t need it!

Coming from a SQL Server background, I have frequently found it helpful to dig through the tables in AxDB, the SQL Server database used as a datastore for Dynamics AX / Dynamics 365 for Operations. Although we do not have direct access to them when programming, and the “Tables” in the AOS are an abstraction that sometimes differs, they are often analogous; it can be easier to plan out a join in familiar T-SQL before trying it in X++. It’s also a good troubleshooting and debugging tool.

And, let’s face it… Microsoft might not like it, but once in a blue moon it can be easier to do certain cleanup or bulk updates that way, if you know what you are doing. Not the best practice, but certainly a fast way to clear a new table you are building, or activate a hundred imported users in one shot…

Working on platform update 3 and earlier, all you had to do was fire up SSMS (SQL Server Management Studio) while you were logged in as the VM Administrator, and (per defaults for most SQL Server installations) you were a sysadmin. After moving to a fresh Platform Update 5 VM (skipping PU4), however, I found that they’d configured SQL Server to no longer allow you access. Not cool, Microsoft.

However, there is a workaround. As you might know, there is a web.config file that contains information Dynamics 365 for Operations uses to connect to its datastore, including a sysadmin user and password. Although the password is stored “encrypted,” you can decrypt it temporarily. Just do that and find the relevant entries in the web.config file:


Although “security through obscurity” ain’t great, I’m not going to put the actual platform update 5 default password here, especially since it might change anyway.

If you want long-term convenience, you might want to immediately log in with these credentials and re-add the local administrator as a login with the sysadmin role. (If you don’t know how to do that, maybe you shouldn’t be mucking around in the SQL Server after all!) Then you don’t need to remember or save the password you dug out of here.

Oh, and… don’t forget to re-encrypt the web.config file when you’re done.

ADDENDUM: In case something happens to the linked post, here are the commands to decrypt and re-encrypt the web.config file. But please, go through and comment on the original post… and comment here too… it motivates bloggers to keep going when we get the occasional response. Just a quick “thank you” is plenty!

C:\AOSService\webroot\bin\Microsoft.Dynamics.AX.Framework.ConfigEncryptor.exe -decrypt C:\AOSService\webroot\web.config

C:\AOSService\webroot\bin\Microsoft.Dynamics.AX.Framework.ConfigEncryptor.exe -encrypt C:\AOSService\webroot\web.config

WRITING to Financial Dimensions (DefaultDimension) in X++

One of my initial programming tasks with Dynamics 365 for Operations (AX 7) has been writing routines to import data from external systems. These complex routines are writing to multiple tables, and sending email when there are problems (a subject for a future post)… and, recently, took another step up in complexity.

When I found out I had to write a routine to import data to “Financial Dimensions” (sometimes called “Default Dimensions” for reasons I’ll soon explain) on employees/workers (more specifically, their employment records, the HcmEmployment table) I was flummoxed for a while.

It took me a bit of reading to figure out what Financial Dimensions even were. Basically, they are attribute/value pairs that you can define yourself. There is more to them then that, and I won’t say I fully understand them yet… that’s a subject for other posts, so I’m just giving you some basics here in case you are unfamiliar. A few are set up by default, but you can also create your own. (General ledger > Chart of accounts > Dimensions > Financial dimensions) So you or an admin can go create a Favorite_Color dimension, give it a bunch of choices (01=Red, 02=Blue, etc.) and then attach a favorite color to a bunch of entities. Just look for a DefaultDimension column. Once that’s done, users can see and set them. For example, in my case, I could go to Human resources > Workers > Worker, look under “Employment” for a given worker, and see the Financial dimensions section listed at the bottom.

Unfortunately, the way they are stored and managed is complex. It’ll take a bunch of reading and looking at code samples to figure out how to get data out of them; I won’t repeat that here, it’s easy to find. But for all my searching, I could not find a way to WRITE to financial dimensions in X++. Finally, with a little help (thanks to Steeve Gilbert in the AXUG forums), I was able top work out a reusable method (or three) to help.

I’m sharing my sample code here to save you the pain I experienced. For sake of example, I’m assuming you put this in a class named MyDimensionHandlerClass, along with any other generic/reusable dimension-related methods you want.

In future blog posts I will share sample code for reading and validating attributes, just for completeness… although there are other samples for those out there.

 

2017-03-24_16-00-35

Finding the customizations/extensions on an object

A minor tip, but a useful one that doesn’t seem to be widely documented/circulated:

Perhaps you might find yourself searching for the customizations or extensions that have been made to a standard object. It usually isn’t difficult to find these manually, but here’s a simple tip to do so quickly:

You’ll notice that you have a “search” option in design view.

vs-aot-object-search

If you use c: or e: for the search, it will show you customizations or extensions, respectively.

vs-aot-object-search-customizations