最新消息:ww12345678 的部落格重装上线,希望大家继续支持。

Label ID fix

网络文摘 William 1851浏览 0评论

I recently saw an interesting problem with labels in AX 2012 – two customizations created different labels with the same IDs, therefore the newer won and the older one showed completely wrong texts in GUI.

For example, one customization created a form with caption @XYZ1 = “Customers”. Another customization created a label with the same ID, @XYZ1, with text “This is an error” and used the label for an error message. The latter change effective replaced the text of @XYZ1 from “Customers” to “This is an error” and therefore the form caption becomes a nonsense.

The cause (I believe) was that two developers used different primary language when putting code to TFS and not all labels existed in all languages. Anyway, the main question was how to fix it.

There is no way how @XYZ1 could mean both “Customers” and “This is an error” at the same time, therefore it was necessary to create a new label for one of the cases and update all code using the label. And repeat it for more than a hundred times.

I didn’t know how difficult it would be to automate it – fortunately I found it rather easy. First of all, I extracted original labels from an older version of the .ald (version control systems can’t prevent all problems, but at least you have all data so you can recover from failures). Then I parsed this list of labels to objects containing label ID, label text and description. (Note that I didn’t have to deal with translations in this case.) You can see it in getParsedLines() method below.

Next step was to create a new label ID for the given text and description and maintain a mapping between the old and the new label ID.

Finally, I used some existing methods to replace original labels IDs with new ones in code and properties. This was potentially the most complicated part, but it turned out to be a piece of cake. :-)

I also had to identify and checked out all objects where labels should have been be replaced, because the replacement works only with checked-out objects. It wasn’t too difficult thanks to version control; I simply took all objects included in the original changeset.

The complete code is below; maybe somebody will run into a similar problem and will find this useful.

class DevLabelFix
{
    private List getParsedLines()
    {
        str fileName = @'D:\oldLabelsFromTFS.txt';
        System.Collections.IEnumerable lines;
        System.Collections.IEnumerator enumerator;
        str line;
        DevLabelDef labelDef;
        List parsedLines = new List(Types::Class);
        int spacePos;
 
        try
        {
            lines = System.IO.File::ReadAllLines(fileName);
            enumerator = lines.GetEnumerator();
 
            while (enumerator.MoveNext())
            {
                line = enumerator.get_Current();
 
                if (strStartsWith(line, '@'))
                {
                    labelDef = new DevLabelDef();
 
                    spacePos = strFind(line, ' ', 1, 10);
                    labelDef.parmId(subStr(line, 0, spacePos-1));
                    labelDef.parmLabel(subStr(line, spacePos+1, strLen(line)));
                    parsedLines.addEnd(labelDef);
                }
                else if (line != '')
                {
                    Debug::assert(labelDef != null);
                    labelDef.parmDescription(line);
                }
            }
        }
        catch (Exception::CLRError)
        {
            throw error(AifUtil::getClrErrorMessage());
        }
 
        return parsedLines;
    }
 
    public void run()
    {
        ListEnumerator enumerator = this.getParsedLines().getEnumerator();
        DevLabelDef labelDef;
        SysLabelEdit sysLabelEdit = new SysLabelEdit();
        str newLabelId;
        Map labelMap = new Map(Types::String, Types::String);
 
        while (enumerator.moveNext())
        {
            labelDef = enumerator.current();
 
            newLabelId = sysLabelEdit.labelInsert(  'en-us',
                                                    labelDef.parmLabel(),
                                                    labelDef.parmDescription(),
                                                    SysLabelApplModule::None,
                                                    'XYZ');
            info(strFmt("%1|%2", labelDef.parmId(), newLabelId));
 
            labelMap.insert(labelDef.parmId(), newLabelId);
        }
 
        // These methods are normally private; I made them temporarily public to allow these calls.
        SysLabelFile::preCheckInUpdateAllPendingFiles(labelMap);
        SysLabelFile::preCheckInUpdateAOTElementsClient(labelMap);
    }
 
    public static void main(Args args)
    {
        new DevLabelFix().run();
    }
}
 
// The DevLabelDef class merely holds ID, label text and description together.
class DevLabelDef
{
    str id;
    str label;
    str description;
 
    public str parmDescription(str _description = description)
    {
        description = _description;
        return description;
    }
 
    public str parmId(str _id = id)
    {
        id = _id;
        return id;
    }
 
    public str parmLabel(str _label = label)
    {
        label = _label;
        return label;
    }
}
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址