• [AX]AX2012 SysOperation框架初窥


    做过AX开发的同学们应该对runbase、runbasebatch、runbasereport这些类比较的熟悉,用它们来从用户收集数据、交互或者batch方式执行操作、并纪录用户的输入选项下次运行时初始化这些选项,为此需要重载pack、unpack、diaog、getfromdialog、run、cangobatch等函数。在AX2012中微软引入了新的SysOperation框架,用于替换runbase框架,微软提供了一份长达58页的白皮书介绍如何使用SysOperation框架,在这里下载http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=29215,所用到的示例代码可以到这里下载http://blogs.msdn.com/b/aif/archive/2012/03/17/introduction-to-the-sysoperation-framework.aspx。本文就如何使用SysOperation框架做简单的探讨,先贴下示例代码的第一个例子,这样便于后续的说明。

    class SysOpSampleBasicController extends SysOpSampleBaseController
    {
    }
    
    public ClassDescription caption()
    {
        return 'Basic SysOperation Sample';
    }
    
    void new()
    {
        super();
    
        this.parmClassName(classStr(SysOpSampleBasicController));
        this.parmMethodName(methodStr(SysOpSampleBasicController, showTextInInfolog));
        this.parmDialogCaption('Basic SysOperation Sample');
    }
    
    public void showTextInInfolog(SysOpSampleBasicDataContract data)
    {
        if (xSession::isCLRSession())
        {
            info('Running in a CLR session.');
        }
        else
        {
            info('Running in an interpreter session.');
            if (isRunningOnServer())
            {
                info('Running on the AOS.');
            }
            else
            {
                info('Running on the Client.');
            }
        }
    
    
        info(strFmt('SysOpSampleBasicController: %1, %2', data.parmNumber(), data.parmText()));
    }
    
    public static void main(Args args)
    {
        SysOpSampleBasicController operation;
    
        operation = new SysOpSampleBasicController();
        operation.startOperation();
    }

    首先是SysOpSampleBasicController类,它继承于SysOpSampleBaseController,后者又继承于SysOperationServiceController,按照白皮书的说明,SysOperation框架的控制类应该直接派生于SysOperationServiceController类,但是目前AX2012版本的SysOperationServiceController类有些问题,所以有派生了SysOpSampleBaseController类来修复这些问题,在以后的版本中SysOperationServiceController会被修复,这里就把SysOpSampleBaseController当作控制类的最基类就行了。

    可以看到控制类所要重载的函数少了很多,关键的地方一是在new()函数中parmClassName()指定控制类名称、parmMethodName()指定要运行的方法名称及parmDialogCaption()指定交互对话框的标题,另外一个关键的函数就是showTextInInfolog(),它被作为参数传入parmMethodName(),所以这个函数的名称是任意的,但是更改后记得做一次CIL增量编译,并清空有关user data,否则会得到方法找不到的错误提示。再来看showTextInInfolog()参数用到的SysOpSampleBasicDataContract类:

    [DataContractAttribute]
    class SysOpSampleBasicDataContract
    {
        str text;
        int number;
    }
    
    [DataMemberAttribute,
    SysOperationLabelAttribute('Number Property'),
    SysOperationHelpTextAttribute('Type some number >= 0'),
    SysOperationDisplayOrderAttribute('2')]
    public int parmNumber(int _number = number)
    {
        number = _number;
    
        return number;
    }
    
    [DataMemberAttribute,
    SysOperationLabelAttribute('Text Property'),
    SysOperationHelpTextAttribute('Type some text'),
    SysOperationDisplayOrderAttribute('1')]
    public Description255 parmText(str _text = text)
    {
        text = _text;
    
        return text;
    }

    它和运行SSRS报表收集报表参数的data contract类一样使用[DataContractAttribute]特性,两个parmxxx()方法也加入了一些特性指定在交互对话框上显示的标签名称、帮助信息及显示顺序。

    运行只需要调用控制类的startOperation()就可以了,它会调用指定showTextInInfolog()方法。它会弹出对话框收集tex和number两个参数,可以放到batch方法去运行,这就是最简单的SysOperation试用方法,和runbase框架相比得到了很大的简化。

    再来看第二个例子,它考虑的问题是如何对交互对话框用户输入的数据做lookup和验证,在runbase框架中我们需要在runbase的dialogPostRun中对dialogField注册重载函数,比如:

    public void dialogPostRun(DialogRunbase _dialog)
    {
        FormControl control;
    
        super(_dialog);
    
        // register overrides for form control events
        numberField.registerOverrideMethod(methodstr(FormIntControl, validate), methodstr(SysOpSampleSimpleRunbaseBatch, numberFieldValidate), this);
        textField.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(SysOpSampleSimpleRunbaseBatch, textFieldLookup), this);
    
    }

    在SysOperation框架中首先对data contract类添加了SysOperationContractProcessingAttribute特性:

    [DataContractAttribute,
    SysOperationContractProcessingAttribute(classStr(SysOpSampleSimpleUserInterfaceBuilder))]
    class SysOpSampleSimpleDataContract
    {
        str text;
        int number;
    }

    由这个特性指定一个自定义的交互对话框构建器类,没有这个特性,会使用系统默认的SysOperationAutomaticUIBuilder构建器,来看看这个自定义的UI构建器是如何做到对dialogField的lookup和validate的:

    class SysOpSampleSimpleUserInterfaceBuilder extends SysOperationAutomaticUIBuilder
    {
        #define.lookupAlways(2)
    
        DialogField numberField;
        DialogField textField;
    }
    
    public void postBuild()
    {
        super();
    
        // get references to dialog controls after creation
        numberField = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(SysOpSampleSimpleDataContract, parmNumber));
        textField = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(SysOpSampleSimpleDataContract, parmText));
        // change text field metadata to add lookup
        textField.lookupButton(#lookupAlways);
    
    }
    
    public void postRun()
    {
        super();
    
        // register overrides for form control events
        numberField.registerOverrideMethod(methodstr(FormIntControl, validate), methodstr(SysOpSampleSimpleUserInterfaceBuilder, numberFieldValidate), this);
        textField.registerOverrideMethod(methodstr(FormStringControl, lookup), methodstr(SysOpSampleSimpleUserInterfaceBuilder, textFieldLookup), this);
    
    }
    
    public boolean numberFieldValidate(FormIntControl _control)
    {
        if (_control.value() < 0)
        {
            error('Please type a number >= 0');
            return false;
        }
        return true;
    }
    
    public void  textFieldLookup(FormStringControl _control)
    {
        FormStringControl       companyControl;
        SysTableLookup          tableLookup;
        Query                   query = new Query();
    
        companyControl = _control;
        tableLookup = SysTableLookup::newParameters(tablenum(DataArea),companyControl);
        tableLookup.addLookupfield(fieldnum(DataArea,Id),true);
        tableLookup.addLookupfield(fieldnum(DataArea,Name),false);
    
        query.addDataSource(tablenum(DataArea));
        tableLookup.parmQuery(query);
        tableLookup.performFormLookup();
    }

    其实要做的工作和runbase框架差不多,也是要对dialogfield注册重载函数,SysOperation框架的处理方式是把这部分处理独立到单独的UI构建器,使得逻辑上比较清晰,注意postbuild方法中是如何得到交互对话框上的两个dialogfield控件的。SysOperation框架还支持使用自定义的form来构建UI,需要重载SysOperationController.templateForm()指定一个form。

    showTextInInfolog()函数也从控制类中脱离出来被放到新的service类中:

    class SysOpSampleSimpleService extends SysOperationServiceBase
    {
    }
    
    public void showTextInInfolog(SysOpSampleSimpleDataContract data)
    {
        if (xSession::isCLRSession())
        {
            info('Running in a CLR session.');
        }
        else
        {
            info('Running in an interpreter session.');
            if (isRunningOnServer())
            {
                info('Running on the AOS.');
            }
            else
            {
                info('Running on the Client.');
            }
        }
    
    
        info(strFmt('SysOpSampleSimpleService: %1, %2', data.parmNumber(), data.parmText()));
    }

    相应的,控制类的new()需要指定服务类的showTextInInfolog()为实际运行方法:

    void new()
    {
        super();
    
        this.parmClassName(classStr(SysOpSampleSimpleService));
        this.parmMethodName(methodStr(SysOpSampleSimpleService, showTextInInfolog));
    }

    这样做使得控制类变得更薄,整体上使用类来封装和组织分离各部分代码逻辑,也是为了使整体结构变得更加清晰。

    第三个例子演示如何向通过控制类的parmExecutionMode()传入SysOperationExecutionMode枚举类型参数来实现不同的运行模式。主要关注的是Reliable Asynchronous方式,它等同于把操作放到batch server去运行,但不同点是在任务完成后从batch jobs列表中自动删除,仅保留运行历史纪录。这个例子稍显复杂,单靠文字不是很能说明清楚,这里就略过了。

    最后一个例子更加详尽的演示了如何使用SysOperation做异步操作,包括如何在多个处理器上同时运行任务、监测异步操作错误、使用Alert机制提示等,从略省过。所以这里只是看看最简单的SysOperation是如何实现的,有兴趣的同学们好好看看这份白皮书吧。

  • 相关阅读:
    Git学习笔记06-版本回退
    python3+selenium入门07-元素等待
    [cerc2017J]Justified Jungle
    [codeforces126B]Password
    计算几何基础模板
    floyd路径记录
    [数据结构复习]层序建立二叉树
    [patl2-011]玩转二叉树
    [poj3348]Cows
    [poj3347]Kadj Squares
  • 原文地址:https://www.cnblogs.com/duanshuiliu/p/2684559.html
Copyright © 2020-2023  润新知