[AX]AX2012 AIF(四):文档服务应用实例

在这篇文章我们将通过文档服务来创建、读取销售订单等来演示如何使用文档服务。

实例一:在这个例子中我们使用文件系统适配器端口,通过XML文档创建销售订单。首先在Inboud ports创建一个文件适配器的增强型端口,选择一个网络共享目录作为URI(我的配置\\dax\AIFData\AIFIn),注意不要使用本地目录,否则会提示找不到相应目录的错误,此外设置目录的权限允许AOS服务账号读写。在适配器“config”窗口中选择一个用户作为“User default for Administration group”,文件系统适配器将文件的owner作为发送消息的用户,在启用UAC的系统上文件的Owner可能会被设置为管理员组因而无法判断具体是谁创建了XML文档,因此这里选择一个用户作为这些文档的默认Owner。另外我们勾选“Response address”,同样设置为文件系统适配器,选择一个网络共享目录为输出目录(我的配置\\dax\AIFData\AIFOut)。在Service operations我们选择 SalesSalesOrderService.create、SalesSalesOrderService.read、SalesSalesOrderService.findKeys操作,在“Data policies”中激活所有的字段。其他配置看自己的需求配置,最后激活这个端口。

下面要做的就是准备好创建销售订单的消息XML,下面是一个样例:

<?xml version="1.0" encoding="utf-8" ?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
  <Header>
    <MessageId>{5603D03A-4380-404D-9F27-738BE0FEA13E}</MessageId>
    <Action>http://schemas.microsoft.com/dynamics/2008/01/services/SalesOrderService/create</Action>
  </Header>
  <Body>
    <MessageParts>
      <SalesOrder xmlns="http://schemas.microsoft.com/dynamics/2008/01/documents/SalesOrder">
        <SalesTable class="entity">
          <CustAccount>9001</CustAccount>
          <DeliveryDate>2013-03-11</DeliveryDate>
          <PurchOrderFormNum>PO</PurchOrderFormNum>
          <ReceiptDateRequested>2013-02-11</ReceiptDateRequested>
          <SalesLine class="entity">
            <ItemId>1206</ItemId>
            <SalesQty>123</SalesQty>
            <SalesUnit>ea</SalesUnit>
          </SalesLine>
        </SalesTable>
      </SalesOrder>
    </MessageParts>
  </Body>
</Envelope>

注意消息头中<Action>中我们用的SalesOrderService/create请求,将这个XML保存(文件名so_create_01.xml)到入站目录\\dax\AIFData\AIFIn,这个时候什么都不会发生,我们还缺少一个Batch job来运行AifGatewayReceiveService, AifGatewaySendService, AifInboundProcessingService, 和AifOutboundProcessingService这个几个服务,如果觉得麻烦用下面的Job手工执行一次吧:

static void AifProcessingClasses(Args _args)
{
 AifGatewayReceiveService receive = new AifGatewayReceiveService();
 AifInboundProcessingService inbound = new AifinboundProcessingService();
 AifOutboundProcessingService outbound = new AifOutboundProcessingService();
 AifGatewaySendService send = new AifGatewaySendService();

receive.run();
inbound.run();
outbound.run();
send.run();
}

一切正常的话你会发现so_create_01.xml消失,在\\dax\AIFData\AIFOut会多出来一个xml,这就是新创建销售订单的响应结果,形如:

<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
  <Header>
    <MessageId>{D630C246-3C62-42AE-BE69-4BFE609E8470}</MessageId>
    <Action>http://schemas.microsoft.com/dynamics/2008/01/services/SalesOrderService/create</Action>
    <RequestMessageId>{5603D03A-4380-404D-9F27-738BE0FEA13E}</RequestMessageId>
  </Header>
  <Body>
    <MessageParts xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
      <EntityKeyList xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList">
        <EntityKey xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey">
          <KeyData>
            <KeyField>
              <Field>SalesId</Field>
              <Value>00000009_050</Value>
            </KeyField>
          </KeyData>
        </EntityKey>
      </EntityKeyList>
    </MessageParts>
  </Body>
</Envelope>

在AR下的销售订单列表中你也能看到这个新创建的销售订单。

 

实例二:这个例子中我们通过销售订单号来读取订单的完整信息,使用例一中的端口配置。需要更改的是我们的XML消息请求:

<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
  <Header>
    <MessageId>{D630C246-3C62-42AE-BE69-4BFE609E8470}</MessageId>
    <Action>http://schemas.microsoft.com/dynamics/2008/01/services/SalesOrderService/read</Action>
    <RequestMessageId>{5603D03A-4380-404D-9F27-738BE0FEA13E}</RequestMessageId>
  </Header>
  <Body>
    <MessageParts xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
      <EntityKeyList xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKeyList">
        <EntityKey xmlns="http://schemas.microsoft.com/dynamics/2006/02/documents/EntityKey">
          <KeyData>
            <KeyField>
              <Field>SalesId</Field>
              <Value>00000009_050</Value>
            </KeyField>
          </KeyData>
        </EntityKey>
      </EntityKeyList>
    </MessageParts>
  </Body>
</Envelope>

其实就是把例一中的响应消息中的Action换成read,同样保存到\\dax\AIFData\AIFIn,运行一次服务JOB,在响应目录中会找到订单详细信息的XML,包含订单头及订单行的所有信息,内容比较长就不列出了。

实例三:在这个例子中我们使用MSMQ适配器端口,如何部署AIF消息队列参见http://msdn.microsoft.com/EN-US/library/aa834340.aspx。创建MSMQ适配器一个入站端口,使用例一中销售订单服务的read和create两个操作,具体步骤不做介绍。消息队列不像文件夹那样可以直接放入XML文档,下面我们使用C#程序向队列投递消息来创建销售订单:

static void Main(string[] args)
{
  
    // The queue name.
    // Replace this AOS name and queue name with the values from 
    // the URI field in the Inbound ports form. 
    // For this walkthrough, 
    // only the server name should be different.
    String QName = "FormatName:DIRECT=OS:DAX\\CreateSO";
    // The path to the sales order XML file
    String XMLPath = "c:\\so_create_01.xml";

    // Create the XML document object.
    XmlDocument doc = new XmlDocument();
    doc.Load(XMLPath);

    // Create a new message.
    Message msg = new Message();

    // Add authentication.
    msg.AttachSenderId = true;
    msg.UseAuthentication = true;
    msg.HashAlgorithm = HashAlgorithm.Sha;

    // Attach the document to the message.
    msg.Body = doc;    

    // Create the queue object.
    MessageQueue myQ = new MessageQueue(QName);

    try
    {
        // Send a message to the queue
        // Create a transaction.
        MessageQueueTransaction myTransaction = new MessageQueueTransaction();

        // Begin the transaction
        myTransaction.Begin();

        // Send the message
        myQ.Send(msg, "Sales Order", myTransaction);

        // End the transaction
        myTransaction.Commit();
    }
    catch (Exception e)
    {
        // Display the description of the exception
        Console.WriteLine(e.Message);
    }  

    Console.Write("Done. Press ENTER to continue.");
    Console.In.ReadLine();
}

程序比较简单,不多讨论。

实例四:在这个例子我们使用C#程序通过NetTcp适配器入站端口读取销售信息,如何配置NetTcp端口也从略,创建好一个C#工程,添加服务引用http://DAX:8101/DynamicsAx/Services/SalesOrderRead,主程序:

static void Main(string[] args)
{
    // Create the sales order objects
    // Service client
    var cl = new ServiceReference1.SalesOrderServiceClient();
    // Sales order object to receive response
    TCP_Client.ServiceReference1.AxdSalesOrder resp;

    // Create the entity key list for the request
    var readRespKeys = new ServiceReference1.EntityKey[1];
    readRespKeys[0] = new ServiceReference1.EntityKey();
    readRespKeys[0].KeyData = new ServiceReference1.KeyField[1];
    readRespKeys[0].KeyData[0] = new ServiceReference1.KeyField();
    readRespKeys[0].KeyData[0].Field = "SalesId";
    readRespKeys[0].KeyData[0].Value = "00000003_050";

    try
    {
        // Try to read the sales order
        resp = cl.read(null, readRespKeys);

        // Display the information from the first sales table
        Console.WriteLine("For sales order: " + resp.SalesTable[0].SalesId);
        Console.WriteLine("Customer Account is: " + resp.SalesTable[0].CustAccount);
    }
    catch (Exception e)
    {
        Console.WriteLine("Exception: " + e.Message);
        cl.Abort();
    }            
    cl.Close();
}

程序读取打印订单00000003_050的客户号,也是比较简单,不多讨论。需要讨论的是上面代码中没有用到的CallContext类,它有Company、LogonAsUser、Language、PropertyBag、MessageId、AX2012 R2引入的PartitionKey几个属性,默认情况下调用服务是以当前进程用户的默认公司执行,使用CallContext则可以设置这些选项,比如:

            var context = new CallContext();
            context.Company = "dat";
            context.LogonAsUser = "yourdomain\userid";
            context.Language = "en-us";

在调用服务时指定context,比如上面的resp = cl.read(context, readRespKeys),它产生的结果类似XML消息的消息头中指定的相关选项:

<Header>
    <MessageId>MessageId1</MessageId>
    <LogonAsUser>domain\user1</LogonAsUser>
    <PartitionKey>PartitionKey1</PartitionKey>
    <Company>Company1</Company>
    <Action>create</Action>

  </Header>

 

实例五这个例子我们使用C#通过HTTP适配器入站端口读取销售订单,HTTP适配器需要将Web service部署到IIS。在C#中使用这类适配器和使用NetTcp适配器端口一样,WSDL地址可能是http://DAX/MicrosoftDynamicsAXAif60/WebSalesOrderRead/xppservice.svc,调用服务的代码和NetTcp一样不用改动,不同的是添加Service reference时app.config中WCF服务绑定端口不一样了,所以这里就不再贴出代码了。

实例六:这是一个使用C#通过NetTcp或者HTTP适配器端口创建销售订单的例子:

            SalesOrderServiceClient proxy = new SalesOrderServiceClient();
            CallContext context = new CallContext();
            context.Company = "ceu";

            AxdSalesOrder salesOrder = new AxdSalesOrder();
            AxdEntity_SalesTable[] salesTables = new AxdEntity_SalesTable[1];
            AxdEntity_SalesTable salesTable = new AxdEntity_SalesTable();


            salesTable.CurrencyCode = "USD";
            salesTable.CustAccount = "1103";
            salesTable.ReceiptDateRequested = Convert.ToDateTime("2/1/2012");
            salesTable.Payment = "N060";
            salesTable.PurchOrderFormNum = "PO113";


            AxdType_DimensionAttributeValue dimBusinessUnit = new AxdType_DimensionAttributeValue();
            dimBusinessUnit.Name = "BusinessUnit";
            dimBusinessUnit.Value = "20";

            AxdType_DimensionAttributeValue dimCustomerGroup = new AxdType_DimensionAttributeValue();
            dimCustomerGroup.Name = "CustomerGroup";
            dimCustomerGroup.Value = "10";


            AxdType_DimensionAttributeValue dimDepartment = new AxdType_DimensionAttributeValue();
            dimDepartment.Name = "Department";
            dimDepartment.Value = "500";


            AxdType_DimensionAttributeValueSet valueSet = new AxdType_DimensionAttributeValueSet();

            valueSet.Values = new AxdType_DimensionAttributeValue[3] { dimBusinessUnit, dimCustomerGroup, dimDepartment };
            salesTable.DefaultDimension = valueSet;


            AxdEntity_SalesLine salesLine = new AxdEntity_SalesLine();

            salesLine.ItemId = "1000";
            salesLine.SalesQty = 1;
            salesLine.SalesUnit = "ea";


            AxdEntity_SalesLine salesLine2 = new AxdEntity_SalesLine();

            salesLine2.ItemId = "1000";
            salesLine2.SalesQty = 55;
            salesLine2.SalesUnit = "ea";


            AxdEntity_SalesLine salesLine3 = new AxdEntity_SalesLine();
            salesLine3.ItemId = "10004";
            salesLine3.SalesQty = 21;
            salesLine3.SalesUnit = "Pcs";


            AxdEntity_InventDim inventDim = new AxdEntity_InventDim();
            inventDim.InventSiteId = "1";
            salesLine3.InventDim = new AxdEntity_InventDim[1] { inventDim };


            salesTable.SalesLine = new AxdEntity_SalesLine[3] { salesLine, salesLine2, salesLine3 };
            salesOrder.SalesTable = new AxdEntity_SalesTable[1] { salesTable };

            try
            {

                proxy.create(context, salesOrder);
                Console.WriteLine("Worked");
            }


            catch (Exception e)
            {
                throw e;
            }

 实例七:使用findKeys操作查找销售订单文档键值,使用例一中的文件系统适配器入站端口,和创建销售订单的不同点就在于XML消息中的QueryCriteria部分:

<?xml version="1.0" encoding="UTF-8"?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
  <Header>
    <MessageId></MessageId>
    <Action>http://schemas.microsoft.com/dynamics/2008/01/services/SalesOrderService/findKeys</Action>
  </Header>
  <Body>
    <MessageParts xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
      <QueryCriteria xmlns = "http://schemas.microsoft.com/dynamics/2006/02/documents/QueryCriteria">
        <CriteriaElement>
          <DataSourceName>SalesTable</DataSourceName>
          <FieldName>CustAccount</FieldName>
          <Operator>Equal</Operator>
          <Value1>80012</Value1>
        </CriteriaElement>
      </QueryCriteria>
    </MessageParts>
  </Body>
</Envelope>

这里查找客户号为80012的所有销售订单,返回这些销售订单的订单号列表,结果就不再列出。如何使用QueryCriteria可以参见http://msdn.microsoft.com/EN-US/library/aa892862.aspx,更多如何创建服务操作XML消息参见http://msdn.microsoft.com/EN-US/library/jj191598.aspx

 

以上例子中演示了创建、读取销售订单,其他的服务操作雷同不多讨论,使用update操作更新数据由于有它特殊的地方,会放在单独的一篇文章中讨论。

  

posted @ 2013-01-31 15:39  断水流  阅读(1724)  评论(5编辑  收藏  举报