Chapter 17. The Application Integration Framework

The objectives of this chapter are to:

  • Introduce common software integration scenarios.

  • Show how the Microsoft Dynamics AX 2009 Application Integration Framework (AIF) can be applied to integration scenarios.

  • Introduce the Dynamics AX 2009 services and service references.

  • Explain how to exchange XML messages with other applications and trading partners.

  • Discuss the security considerations when integrating other software with Dynamics AX.

Introduction

Once you implement Dynamics AX in a production environment, you immediately benefit from using it to manage your business. To help you realize the full potential of Dynamics AX, you can use the Application Integration Framework (AIF) to integrate your company’s other software systems and those of your trading partners with Dynamics AX.

This chapter describes the AIF and the integration scenarios it enables. The chapter starts with a description of the AIF and the services that comprise it. It then explores the Dynamics AX services in greater depth—explaining what they are and how they’re created, published, and configured. The final section of the chapter discusses how to consume Dynamics AX services, Dynamics AX Web services, and external Web services. Troubleshooting tips, guidance on security, and pointers to other documentation sources that have detailed procedures for implementing AIF appear throughout the chapter.

Note

Note

In this chapter, we discuss configuration and administration tasks only where necessary to help you better understand the development scenarios. For additional details, refer to the Microsoft Dynamics AX 2009 documentation on TechNet.

Overview of the Application Integration Framework

The AIF provides a programming model, tools, and infrastructure support for services-based integration of application functionality and data with Dynamics AX.

The published AIF interfaces to Dynamics AX are compliant with industry standards and based on core Microsoft technologies including the Windows software development kit (SDK) for Windows Server 2008, Microsoft .NET Framework 3.5, Windows Communication Foundation (WCF), Microsoft Message Queuing (MSMQ), and Microsoft BizTalk Server.

In addition to the built-in programming model and tools for implementing integration scenarios, Dynamics AX also has the following functionality:

  • Provides a set of bindings to transport technologies that can be used to exchange data with Dynamics AX, such as MSMQ, BizTalk Server, and synchronous (WCF) Web services.

  • Supports the exchange of XML files through configurable file locations.

  • Through service references, provides an abstraction and related tools for integrating Dynamics AX with external applications (services) through X++ code (software), allowing partners to reap the benefits of Software-plus-Services, popularly known as S+S.

Overview Scenarios

Once your company has deployed Dynamics AX 2009, you can benefit from automating your business processes. To realize the full potential of Dynamics AX 2009 and maximum return on investment (ROI) of your Dynamics AX 2009 deployment, however, you should consider automating interactions between Dynamics AX 2009 and the other software in your company and in the companies of your trading partners.

Many business scenarios require reading or manipulating information that is stored in Dynamics AX or in external applications. Figure 17-1 shows several of the scenarios in which people access information managed in Dynamics AX to accomplish a business task. It also shows sample scenarios in which Dynamics AX accesses information that external applications manage. The large arrows show who accesses information.

Common integration scenarios

Figure 17-1. Common integration scenarios

Here are the sample scenarios with a few more details:

  • The company’s CEO analyzes sales data in Microsoft Office Excel.

  • A salesperson who is visiting a prospect’s site uses a Microsoft Office InfoPath form to create a new customer account and the first sales order. The salesperson is required to run both background and credit checks on the new customer before entering the data.

  • A sales processor enters a sales order and uses customer records that are stored in a CRM application to populate the customer section of the order.

  • An operations worker needs to find the most economical shipping rate for a certain shipment given the delivery requirements specified by the customer.

  • A trading partner manages its sales orders and inquires about the status of its orders using its own custom application.

  • An order processor needs to send an invoice to a trading partner.

These tasks are often done manually—without integrating Dynamics AX with other applications and business processes—but manual processes don’t scale well. Manual processing can also adversely affect the quality of the data managed in Dynamics AX, such as when data is entered incorrectly. In the following section, we show you how the AIF can help you automate these interactions and further streamline your business processes.

Overview of Dynamics AX Services

If you look at Figure 17-1 again, you can see that the people on the left side of the figure use applications that interact with the Dynamics AX data store. They send requests (e.g., to read a sales order) into Dynamics AX and in most cases expect a response from Dynamics AX (e.g., the requested sales order instance). For these applications to be able to submit requests into Dynamics AX, Dynamics AX must expose service interfaces that can receive requests. These service interfaces are part of Dynamics AX services, which can be created, managed, and published through the AIF.

Dynamics AX services are a service-oriented abstraction used to encapsulate Dynamics AX business logic—such as functionality to create a sales order in Dynamics AX—in a reusable way. These services can be used to participate in service-oriented architecture (SOA).

Note

Note

Service-oriented architecture (SOA) is a significant area of software development. A complete discussion of SOA is outside the scope of this book, and in this chapter we assume you have a fundamental understanding of SOA concepts. Good information on SOA abounds, including the Organization for the Advancement of Structured Information Standards (OASIS) specification "Reference Model for Service Oriented Architecture 1.0" and the book Service-Oriented Architecture: Concepts, Technology, and Design by Thomas Erl.

Dynamics AX services can be exposed to external applications, called service clients, through a variety of interfaces, such as MSMQ or WCF Web services. Publishing Dynamics AX services is a simple task that a Dynamics AX administrator can do at run time. (See the section "Publishing Dynamics AX Services" later in this chapter for more details.) Once a Dynamics AX service has been published, client applications can consume it.

Components of Dynamics AX Services

Dynamics AX services come in two flavors: document services and custom services. The following artifacts are part of the implementation of both types of services:

  • Service implementation class. An X++ class that implements the business logic encapsulated by a service. For example, the X++ class SalesSalesOrderService that comes with Dynamics AX 2009 is a service implementation class.

  • Service interface. A child node of the Services node in the Dynamics AX Application Object Tree (AOT). A service interface includes properties, such as Namespace, Class, and SecurityKey. For example, the AOT node SalesSalesOrderService (underneath the AOT node Services) is a service interface. A valid service interface references a service implementation class and exposes a subset of the methods of the service implementation class as service operations.

  • Data object. An X++ class, such as SalesSalesOrder, that can be used as a parameter for service operations.

Overview of Document Services

The term document services stems from the reality that businesses need to exchange documents, such as sales orders and invoices, with their partners. Document services provide an external application interface. These services are built on top of a query and provide a subset of create, read, update, delete, find (CRUDF) service operations for a particular Axd<Document> type. The Axd<Document> represents a business entity.

Note

Note

Document services are a subset of custom services.

Document services provide document-centric APIs—that is, APIs that operate on electronic documents. In Dynamics AX, these documents are referred to as Axd<Documents> and are derived from Dynamics AX queries.

Examples of document-oriented APIs for a sales order service include create sales order, read sales order, update sales order, delete sales order, and find sales order.

Each of these APIs operates on an instance of a sales order document. Create sales order, for example, takes a sales order document, persists it in the Dynamics AX data store, and returns the sales order identifier for the persisted instance.

Document Services Artifacts

All document services that come with Dynamics AX 2009, as well as the ones you generate from Dynamics AX queries using the Create New Document Service Wizard, include the following artifacts:

  • Service contract. Service-related metadata (no code) that is stored in AOT nodes, underneath the AOT node Services, such as SalesSalesOrderService. Service contracts are not specific to document services and are also used for custom services. The metadata includes the following information:

    • Service operations that are available to external service clients

    • A reference to the X++ service implementation class that implements these service operations

  • Service implementation. The code that exposes business logic. It mainly consists of the following elements:

    • Service implementation class An X++ class that derives from AifDocumentService and implements the service operations that are published through the service contract. There is one service implementation class for each Dynamics AX service. For example, SalesSalesOrderService is the service implementation class for SalesSalesOrderService.

    • Axd<Document> class An X++ class that derives from AxdBase. It primarily implements code for XML serialization, but it also coordinates cross-table validation and cross-table defaulting. There is one Axd<Document> class for each document service. For example, AxdSalesOrder is the Axd<Document> class for SalesSalesOrderService.

    • One or more Ax<Table> classes An Ax<Table> class is an X++ class that derives from AxInternalBase and implements validation, defaulting, and substitution logic for table fields. There is one Ax<Table> class for each table that is used in the query that is used to generate the Dynamics AX document service. For example, AxSalesTable and AxSalesLine are two Ax<Table> classes that have been generated for the SalesSalesOrderService.

  • Data object. An X++ class that represents a parameter type. The parameter types that the Create New Document Service Wizard generates derive from AifDocument represent business documents. For example, SalesSalesOrder is the data object that is created for the SalesSalesOrderService.

You can find a complete list of document services artifacts in the AIF documentation in the Microsoft Dynamics AX 2009 SDK on MSDN.

Axd<Document> Classes

Axd<Document> classes (e.g., AxdSalesOrder) derive from the X++ class AxdBase and are generated from Dynamics AX queries. Axd<Document> classes provide default implementations for the XML serialization of used data objects as well as hooks for validation code. Axd<Document> classes also call Ax<Table> classes to perform value mapping and can filter data.

Axd<Document> classes derive XML schema definitions used for XML serialization directly from the structure of the underlying query; all generated schema definitions comply with principles described in the Reference Model for Service Oriented Architecture 1.0 mentioned earlier in the chapter. The generated XML serialization code leverages Dynamics AX concepts such as extended data types (EDTs) to further restrict valid XML schemas and improve XML schema validation. During serialization, Axd<Document> classes use Ax<Table> classes to persist data to tables and to read from tables. Because Ax<Table> classes implement business logic such as defaulting and value mapping, Axd<Document> classes never bypass Ax<Table> classes to access tables directly.

Figure 17-2 illustrates the mapping between a Dynamics AX query used for the Axd<Document> class Axd<Document> and the generated XML schema definition.

Correlation between the AOT query and the XML document structure

Figure 17-2. Correlation between the AOT query and the XML document structure

Axd<Document> classes also provide an API for orchestrating cross-table validation and defaulting. Validation and defaulting logic that is relevant only for a specific document service can also be implemented in Axd<Document> classes, such as by using the methods prepareForSave, prepareForUpdate, and prepareForDelete.

The AifEntityKey class is used for all service operations that require one or more specific records. It is also used for the return values for service operations of type create. An AifEntityKey instance uniquely identifies an entity. It consists of a table identifier (ID), the field IDs for a unique index of that table, and the values of the respective fields. In addition, it holds the record ID of the retrieved records. The following code shows a partial implementation from the AxdBaseCreate class.

protected void setEntityKey()
{
    Map keyData;
    ;
    keyData = SysDictTable::getKeyData(axBcStack.top().currentRecord());

    entityKey = AifEntityKey::construct();
    entityKey.parmTableId(axBcStack.top().currentRecord().TableId);
    entityKey.parmRecId(axBcStack.top().currentRecord().RecId);
    entityKey.parmKeyDataMap(keyData);

    // More code lines go here.

}

The section "Customizing Document Services" later in the chapter offers additional information on using Axd<Document> classes.

Note

Note

An in-depth discussion of Axd<Document> and Ax<Table> classes is beyond the scope of this book. Refer to the Document Services section in the Microsoft Dynamics AX 2009 SDK for complete information.

Ax<Table> Classes

Ax<Table> classes (e.g., AxSalesTable and AxSalesLine) derive from the X++ class AxInternalBase. There is one Ax<Table> class for each table that is used in a document service. More specifically, the same Ax<Table> class is used by Axd<Document> classes that are based on queries referencing the same table. Here are some uses of Ax<Table> classes:

  • Help implement defaulting scenarios, such as automatically changing a table field when a related table field is changed. For example, an Ax<Table> class can automatically update or reset the table field Delivery Address when the related Sales Order table field, Customer Account, is changed.

  • Keep track of the defaulting state of table fields. For example, when a Dynamics AX user sets a specific table field explicitly, the defaulting logic must not overwrite the explicitly set value.

  • Implement validation logic for table fields, value substitution, and logic for fetching numbers or identifiers from number sequences.

  • Implement parm methods for fields on the underlying table.

Note

Note

Ax<Table> classes are frequently referred to as AxBC classes, both in code and in documentation.

Document Services Use Cases

The standard create, read, update, delete (CRUD) service operations for document services are particularly useful and efficient in business-to-business (B2B) scenarios or in offline integration scenarios in which communication between systems is unreliable and slow and changes to documents occur infrequently.

Document services are also useful for integrating Dynamics AX with systems through the exchange of coarse-grained business documents, such as sales orders and leads. This type of data exchange is commonly used in the following scenarios:

  • Exchanged data is transacted. For example, if a request to create a sales order fails, the state of the Dynamics AX database must remain unchanged. No side-effects must occur: artifacts such as address or customer records that were created as part of the processing of the failed request must not be left; instead, the entire transaction must be rolled back.

  • Data exchanges are expensive because, for example, the request and response messages are exchanged through the Internet. Coarse-grained data exchange in the form of business documents can help reduce the number of exchanged messages.

  • The response time—that is, the time between sending the request (e.g., to create a sales order) to Dynamics AX and receiving a response—isn’t critical.

In addition to their use in B2B integration scenarios, coarse-grained document services are helpful in application-to-application (A2A) integration scenarios, such as when you’re integrating Dynamics AX with certain document-centric Microsoft Office products.

Document Service Development Tools

Although you can create document services manually, we don’t recommend it. Instead, you should use the Create New Document Service Wizard to quickly generate new document services from AOT queries and the Update Document Service form to update existing document services. You can find this wizard and form at ToolsDevelopment Tools Application Integration Framework. (To read more about the AOT, see Chapter 2.)

Dynamics AX 2009 also includes more than 50 ready-to-use document services. These include services such as SalesOrderService and CustomerService. You can find a complete list of these built-in services in the AOT Services node at design time or through the AIF Services Administration form at run time.

You can also extend out-of-the-box services with more fine-grained custom service operations, such as updating the delivery address for a specific sales order.

Overview of Custom Services

Custom services can provide any kind of API. Even so, you should never use custom services to replace document services, and you should not use them to implement CRUD functionality for query-based entities. Instead, you should be use custom services to implement functionality that can’t be directly tied to a Dynamics AX query, such as when you want to stop payment on a check or start an invoice approval process.

Custom Service Use Cases

Custom services are indispensible in A2A scenarios in which systems are tightly integrated and small chunks of data need to be exchanged efficiently between external applications and Dynamics AX. Examples of such applications are interactive applications that manipulate data managed in Dynamics AX, such as Microsoft Office Business Applications (OBAs).

Custom Services Development

Dynamics AX 2009 doesn’t provide wizards or other tools for implementing custom services. Instead, custom services must follow certain rules, which we cover in the following section.

Note

Note

Although the design-time experience for document and custom services differs, both service types are configured and published in the same way.

Working with Custom Services

Because document services are a subset of custom services, the concepts described in this section apply to both custom services and document services.

To implement a custom service, follow these steps:

  1. Create a service implementation class.

  2. Create a service contract.

  3. Implement data objects—if necessary.

  4. Discover services.

Creating a Service Implementation Class

Service implementation classes contain the business logic that can be published through service contracts for consumption by external service clients.

You can use any X++ class as a service implementation class; service implementation classes don’t need to implement any interfaces or extend any super classes. A class definition for a service implementation class MyDataObjectService could look like this.

public class MyDataObjectService
{
}

The following code sample illustrates how one of the service operations of MyDataObjectService could look. All input and return parameters of service operations must be either of primitive X++ types or of X++ classes that implement the X++ interface AifXmlSerializable.

public MyDataObject CreateMyDataObject(str _s)
{
  MyDataObject mdo; // see below for a definition of class MyDataObject
  ;

  mdo = new MyDataObject();
  mdo.parmMyString(_s);

  // do something with 'mdo', for instance persist it ...

  return mdo;
}

Creating a Service Contract

Service contracts define the subset of functionality implemented by a service that can be published for consumption by external service clients.

To create a new service contract, you need to create a new AOT node under the AOT node Services. In this example, the service contract is named MyDataObjectService, just like the service implementation class.

The newly created AOT node MyDataObjectService has a few properties that need to be initialized before external clients can consume the service:

  • (Service implementation) class. This property links the service interface to the service implementation; in the preceding example, the value would be MyDataObjectService.

  • Security key. Each service needs its own security key. The security key should have the same name as the service it protects; for example, MyDataObjectService should have the parent key Services in a functional area like Accounts Receivable. For this example, it makes sense to create a new security key, MyDataObjectService, without a parent key because the new service really doesn’t fit into a functional area.

  • Namespace. Optionally, you can specify the XML namespace that should be used in the Web Services Description Language (WSDL). If the XML namespace isn’t specified, http://tempuri.org is used by default. This example uses the namespace http://schemas.contoso.com/axbook/2009/services.

  • External name. Optionally, you can assign an external name for each service. In this example, the external name is left blank.

Finally, you need to add service operations to the service contract. You do this by right-clicking the new AOT node and selecting Add Operations. The service exposes only service operations that have been explicitly added to the service interface.

Implementing Data Objects

Service operations can automatically use primitive X++ types (e.g., int and str) as types for input and return parameters. X++ classes that are to be used as data objects—that is, as input or return parameters for service operations—must implement the interface AifXmlSerializable. Here’s an example.

public class MyDataObject implements AifXmlSerializable
{
  str myString;
  // more fields ...

  #define.MyDataObjectNS ('http://schemas.contoso.com/samples/MyDataObject')
  #define.MyDataObjectRoot ('MyDataObject')
}

Note

Note

Axd<Document> classes implement the AifXmlSerializable interface and thus can be used as parameter types.

You need to use AifXmlSerializable mainly to define the serialization to and the deserialization from XML for that class. Note that the methods serialize and deserialize must be inverse functions because they use the same XML schema definition. In other words, it must be possible to deserialize an XML document that was created by serializing a data object, and vice versa.

The following code examples show what such implementations can look like. For additional information about any of the implemented methods, see the AIF information in the Microsoft Dynamics AX 2009 SDK.

The method serialize defines the serialization of the data object to XML. The code for serializing the previously defined class to XML could look like this.

AifXml serialize()
{
  str xml;
  XmlTextWriter xmlTextWriter;
  ;

#Aif

  xmlTextWriter = XmlTextWriter::newXml();

  // turn off indentation to reduce file size
  xmlTextWriter.formatting(XmlFormatting::None);

  // initialize XML document
  xmlTextWriter.writeStartDocument();

  // write root element
  xmlTextWriter.writeStartElement2(#MyDataObjectRoot, #MyDataObjectNS);

  // write custom data
  xmlTextWriter.writeElementString('MyString', myString);
  // more fields ...

  // serialize XML document into XML string
  xmlTextWriter.writeEndDocument();
  xml = xmlTextWriter.writeToString();
  xmlTextWriter.close();

  return xml;
}

The method deserialize defines the deserialization of a data object from XML. The code for deserializing an instance of the class defined from XML could look like this.

void deserialize(AifXml xml)
{
  XmlTextReader xmlReader;
  ;
  xmlReader = XmlTextReader::newXml(xml);

  // turn off whitespace handling to avoid extra reads
  xmlReader.whitespaceHandling(XmlWhitespaceHandling::None);

  xmlReader.moveToContent();
  while ((xmlReader.nodeType() != XmlNodeType::Element) && !xmlReader.eof())
  xmlReader.read();

  xmlReader.readStartElement3(#MyDataObjectRoot, #MyDataObjectNS);
  if (!xmlReader.eof() && xmlReader.isStartElement())
  {
    myString = xmlReader.readElementString3('MyString', #MyDataObjectNS);
    // more fields ...
  }

  xmlReader.readEndElement();
  xmlReader.close();
}

In X++, parm methods are used to define properties. In data objects, all fields that are used for serialization or deserialization must be accessible through parm methods; they must also be optional and thus have a default value. Here’s an example.

public str parmMyString(str _myString = '')
{
  if (!prmisdefault(_myString))
  {
    myString = _myString;
  }
  return myString;
}

The method getRootName returns the root name used for deriving names for service artifacts, as shown here.

public AifDocumentName getRootName()
{
  return #MyDataObjectRoot;
}

The method getSchema returns the XML schema definition (XSD) that is used for serializing and deserializing the data object.

public AifXml getSchema()
{
  str schema =
    @'<?xml version="1.0"?>
    <xsd:schema xmlns="http://schemas.contoso.com/samples/MyDataObject"
    targetNamespace="http://schemas.contoso.com/samples/MyDataObject"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified">
      <xsd:complexType name="MyDataObjectType">
        <xsd:sequence>
          <xsd:element name="MyString" type="xsd:string" />
          <!-- more fields ... -->
        </xsd:sequence>
      </xsd:complexType>
      <xsd:element name="MyDataObject" type="MyDataObjectType"/>
    </xsd:schema>'
  ;

  return schema;
}

Tip

Tip

XML schemas are used for validation, to avoid processing request messages with invalid content, for example. To ensure that your XML schema definition is valid, you should always use a data modeling tool or an XML editor to generate the XSD rather than typing it manually.

Discovering Custom Services

Once you’ve created a custom service, you need to register it with AIF. To register the custom service (in this example, MyDataObjectService) with AIF, expand the Services node in the AOT, select MyDataObjectService and open its context menu, point to Add-Ins, and then click Register Actions. Alternatively, you can register the service with AIF through the AIF administration form Services, which is located in BasicSetupApplication Integration Framework. Click the Refresh button; this refreshes all service entries and thus takes longer than using the AOT Services node.

As a result of the registration, MyDataObjectService shows up along with all other services and is now ready for use. It can be published for external service clients to consume. The section "Publishing Dynamics AX Services" later in this chapter explains how to publish these services.

Working with Document Services

In this section, we go into greater detail about how to create, generate, customize, publish, configure, and consume Dynamics AX document services. Before getting into those details, we’re going to remind you of the best way to create document services and look at an overview of the life cycle of Dynamics AX document services.

As we mentioned earlier in the chapter, even though you could create document services manually, we don’t recommend that you do it. Creating them in either of the following ways is more efficient and less prone to error:

  • Use the Create New Document Service Wizard to generate new document services from queries.

  • Use the Update Document Service form to update existing document services.

Again, you can find this wizard and form at ToolsDevelopment ToolsApplication Integration Framework.

In this section, we assume that this AIF wizard and form manage both the document services and the document services artifacts.

Figure 17-3 shows the typical life cycle of a document service.

Typical life cycle of a Dynamics AX document service

Figure 17-3. Typical life cycle of a Dynamics AX document service

You can find out more about publishing and republishing document services in the "Publishing Dynamics AX Services" section and more about configuring the interface of a document service in the "Configuring Dynamics AX Services" section, both later in this chapter.

Creating Dynamics AX Queries

Document services are generated from queries. (See the Database Queries section of the Microsoft Dynamics AX 2009 SDK for details on creating Dynamics AX queries.) Although general guidelines for working with Dynamics AX queries apply to document services queries, some constraints and additional guidelines apply:

  • As a best practice, always name Dynamics AX queries that are used for document services with the prefix Axd and then the document name. For example, the document service query for the document SalesOrder should be AxdSalesOrder.

  • Only one root table per query is allowed. You can associate the unique entity key that is used to identify document instances with this root table. For example, the entity key SalesId is defined on the AxdSalesOrder root table SalesTable.

  • When your query’s data sources are joined by an inner join, you should use fetch mode 1:1; when they are joined by an outer join, you should use fetch mode 1:n. If you don’t use these settings, your query and thus the service operations that use this query could yield unexpected results.

  • If you want to use a Dynamics AX document service to write data back to the database—that is, if you need to support the service operation update—you need to set the AOT property Update to Yes for all data sources the query used to generate the service.

Note

Note

For security reasons, checks in X++ code by default prevent system tables from being used in queries that are used for document services.

Dynamics AX queries that are used to generate Dynamics AX document services and thus comply with the preceding rules are also referred to as Axd queries.

Generating Document Services

As mentioned earlier, you should always use the Create New Document Service Wizard to generate document services from existing Axd<Document> queries. Find this wizard from the Dynamics AX drop-down menu. In this section, we provide a high-level description of the Create New Document Service Wizard and some important notes that govern its use.

In the wizard, you can select the service operations you want to generate: create, read, update, delete, find, and findKeys. If you select Generate AxBC classes when running the wizard, the wizard generates new Ax<Table> classes with parm methods for the fields of the underlying table when necessary. It then adds missing parm methods to existing Ax<Table> classes. The wizard never removes any parm methods from existing Ax<Table> classes—even if the corresponding table fields have been removed from the underlying table.

The Create New Document Service Wizard uses the document name—which you enter on the first screen of the wizard—to derive names for the generated artifacts. You can change the document name (and thus the derived names for the artifacts) in the wizard before the artifacts are generated. Names of AOT objects are limited to 40 characters. If you choose a document name that yields names that are too long for one or more artifacts, you could get an error message.

Once the wizard finishes, it displays a report of all generated artifacts and any errors encountered. You need to fix any before you start customizing the generated code with additional validation or defaulting logic, which we talk about next.

Tip

Tip

The wizard creates a new project for each generated service. It then adds the generated artifacts automatically to the created project.

For a more comprehensive discussion of the Create New Document Service Wizard and generating Axd<Document> and AX<Table> classes and related APIs, refer to the Microsoft Dynamics AX 2009 SDK.

Customizing Document Services

In many cases, you need to customize the document services that have been generated from a query or that come with Dynamics AX 2009 to better fit business needs. In this section, we touch on some of the most common scenarios for customizing document services, including customizing the application, service operations, validation, defaulting, queries, and security.

Customizing Tables

When you customize a table (e.g., by adding a column) that a document service uses, you need to update the service implementation—that is, the Axd<Document> and Ax<Table> classes and the data objects—to reflect these changes. You should always enable best practice checks with the Best Practices tool to detect potential discrepancies between the table structure and the service implementation.

If the best practice checks on any of your customized tables fail, you can use the Update Document Service form to update the Axd<Document> class, Ax<Table> classes, and data objects to reflect the changes.

Caution

Caution

When you modify the structure of tables or queries (e.g., by adding a column to a table), you must also change your service contract—for example, the XSD for the corresponding data objects. This change in turn potentially breaks integrations that were built using the original service contract.

Adding Custom Service Operations

You can change the behavior of any service operation simply by modifying its X++ implementation. In addition, you can add custom service operations to any document service by following the same steps used for adding service operations to custom services.

Customizing Validation Logic

You can customize the validation logic that is used when the service operations create, update, and delete are executed. Validation logic is crucial to enforce data hygiene. Ideally, invalid data must never be persisted in the Dynamics AX database. You must add validation logic to any services—custom services or document services—that you create or customize. Well-designed validation logic has the following characteristics:

  • Reusable. Ideally, the same (generic) validation logic can be used from the Dynamics AX client as well as from Dynamics AX services. Keep in mind that nongeneric validation code, code that applies only to the Dynamics AX client or Dynamics AX services, is also possible.

  • Well performing. Validation code runs whenever the respective Dynamics AX entity is modified. As a consequence, one of your key goals for writing validation logic must be adequate performance.

  • Sufficient. Validation logic must guarantee a sufficient level of data hygiene. You might have to trade off sufficiency versus performance in a way that satisfies your application’s requirements.

Validation code consists mainly of the following elements:

  • Code that orchestrates cross-table validation by invoking validation code that is implemented on the respective tables; this code is implemented in the respective Axd<Document> class methods prepareForSave, prepareForUpdate, and prepareForDelete. These prepareForXxx methods are called once for each Ax<Table> class that the Axd<Document> class uses.

  • Code that enforces table-level validation logic is implemented by the table methods validateField and validateWrite for maximum code reusability. These methods call into specific validation methods, such as checkCreditLimit on SalesTable.

  • Code that performs document-level validation, which is implemented by the Axd<Document> class method validateDocument. This method is called immediately before changes are persisted to tables, and after the prepareForXxx methods have been called for each Ax<Table> class.

  • Code that performs validation once data has been persisted to the table, which is implemented by the Axd<Document> class method updateNow.

The following code, the prepareForSave method for AxdSalesOrder, is an example of cross-table validation. It calls validation methods for the Ax<Table> classes AxSalesTable and AxSalesLine (as well as other Ax<Table> classes, which have been removed from this sample).

public boolean prepareForSave(AxdStack _axdStack, str _dataSourceName)
{

    // ...
    // code removed

    switch (classidget(_axdStack.top()))
    {
        case classnum(AxSalesTable) :
            axSalesTable = _axdStack.top();
            this.checkSalesTable(axSalesTable);
            this.prepareSalesTable(axSalesTable);
            return true;

        case classnum(AxSalesLine) :
            axSalesLine = _axdStack.top();
            this.checkSalesLine(axSalesLine);
            this.prepareSalesLine(axSalesLine);
            return true;

        // ...
        // code removed
}

Customizing Defaulting Logic

You can customize the defaulting logic for table fields that is executed as part of creating or updating table rows. Defaulting logic helps increase the usability of both interactive Dynamics AX client applications and Dynamics AX service interfaces. It derives initial values for table fields from other data—such as values of other table fields—and thus doesn’t require explicit value assignments for the defaulted table fields. It also helps reduce the amount of data required to manipulate more-complex entities, such as sales orders, while lowering the probability of erroneous data entry.

Well-designed defaulting logic has the following characteristics:

  • Reusable. You should implement defaulting logic so that it is reusable—that is, so the same logic can be used regardless of which Dynamics AX client (e.g., a user interface or a service client) creates or updates the entity. In certain scenarios, the defaulting of table fields might require different logic, depending on whether the Dynamics AX client is interactive (e.g., a user interface) or noninteractive (e.g., a request from a service client).

  • Well performing. Because the defaulting logic for a table field is invoked every time the field is set, its execution time directly impacts the processing time for manipulating the entity (e.g., a sales order). In particular, you should try to avoid redundant defaulting steps—that is, setting a field value that is overwritten again as part of the same defaulting logic.

  • Sufficient. To reduce the number of required fields for manipulating entities, as many fields as possible should be defaulted—while still meeting the performance goals.

The defaulting logic consists mainly of the following elements:

  • Defaulting rulesAx<Table> classes provide methods for setting fields, which the framework uses for assigning values to table fields. This method, set<Fieldname>, implements the defaulting logic for the table field Fieldname of the table that is associated with the Ax<Table> class.

  • State tracking of the defaulting state of table fields

    • The method isMethodExecuted, which is implemented by Ax<Table> classes, is used to check whether the respective set<Fieldname> method has already been invoked (see the following code). This check is necessary to detect and avoid loops in the defaulting logic.

    • The method isFieldSet, which is implemented by Ax<Table> classes, checks whether a table field has been set.

The following code shows the set<Fieldname> method for the table field DeliveryCounty, that is, setDeliveryCounty, as implemented by the Ax<Table> class AxSalesTable. You should add defaulting logic similar to that shown in this example to new set<Field> methods of newly generated or updated Ax<Table> classes, if applicable.

protected void setDeliveryCounty()
{
    if (this.isMethodExecuted(funcname(), fieldnum(SalesTable, DeliveryCounty)))
    {
        return;
    }

    this.setZipCodeRecordFields();

    if (this.isZipCodeRecordFieldsSet())
    {
        this.parmDeliveryCounty(this.zipCodeRecord().County);
        return;
    }

    this.setCustAccount();

    if (this.isFieldSet(fieldnum(SalesTable, CustAccount)))
    {
        if (this.axAddress().addressTable())
        {
            this.parmDeliveryCounty(this.axAddress().parmCounty());
        }
        else
        {
            this.parmDeliveryCounty(this.custAccount_CustTableRecord().County);
        }
    }
}

Customizing Axd<Document> Queries

You can customize the Axd<Document> queries that come with Dynamics AX to generate document services for new or existing AOT elements. For example, assume that you’ve created a new table containing several illustrations per inventory item. Now you want to include those illustrations with purchase orders and to update the document service associated with the purchase orders. To do that, you would modify the query AxdPurchaseRequisition to include the new table and then use the Update Document Service form to update the document service associated with AxdPurchaseRequisition.

Your process would look like this:

  1. Modify the query AxdPurchaseRequisition to include the new ItemIllustration table. Figure 17-4 shows what the query looks like after the new table has been added. The boxed area must be added to the original query that came with Dynamics AX 2009.

    Query after adding the ItemIllustration table

    Figure 17-4. Query after adding the ItemIllustration table

  2. Open the Update Document Service form and enter AxdPurchaseRequisition for the query name. The remaining fields are indifferent to the processing because no modifications are made to existing Axd<Document> classes. If you carefully created the relationships in the query, the form can construct all required code in the prepareForSave method.

  3. You need to generate new Ax<Table> classes, but you shouldn’t need to update existing Ax<Table> classes.

After you close the Update Document Service form, you must fix potential compilation errors and all the to-do comments that the Create New Document Wizard produces in the generated code. First, you remove the caching if it isn’t needed. You do this by removing the methods CacheObject and CacheRecordRecord. When removing these classes, you must also remove the two static variables from the class declarations cacheRecordIdx and cacheObjectIdx. Assume that InventDim isn’t influencing the illustration; then you simply remove the optional parameter so that the parmItemId method looks like the code shown here.

public str parmItemId(str _itemId = '')
{
    DictField dictField;
    ;
    if (!prmisdefault(_itemId))
    {
        dictField = new DictField(tablenum(ItemIllustration),fieldnum(ItemIllustration,ItemId));
        this.validateInboundItemIdString(_itemId,dictField);
        if(this.valueMappingInbound())
        {
            item = _itemId;
        }

        this.setField(fieldNum(ItemIllustration, ItemId), _itemId);
    }

    if (this.valueMappingOutbound())
    {
        return conpeek(this.axSalesItemId('', itemIllustration.ItemId),1);
    }
    else
    {
        return itemIllustration.ItemId;
    }
}

To use the updated service, you have to open and refresh the Services form. If you published PurchaseRequisitionService as a Web service, you also need to regenerate the Web service on the Services form.

Customizing Security

By default, record-level and column-level security are applied to all data retrieval. In certain scenarios, however, you need to ignore record-level and column-level security—for example, when invoices need to be sent. In those scenarios, the user must be able to see the same data that is posted, regardless of the security settings. The following code sample shows how to override the default behavior.

protected void unpackPropertyBag(AifPropertyBag _aifPropertyBag)
{
    AxdSendContext axdSendContext = AxdSendContext::create(_aifPropertyBag);
    ;
    // Get send context properties.
    ...
    this.security(axdSendContext.parmSecurity());
    ...
}

Caution

Caution

Be very diligent when customizing security mechanisms, and make sure you understand the implications of your modifications.

Publishing Dynamics AX Services

You have now created and customized your service; however, external applications can’t yet consume it. To allow external applications to consume your service, you need to publish it. Figure 17-5 gives an overview of the transport technologies that AIF supports out of the box.

Overview of transport interfaces

Figure 17-5. Overview of transport interfaces

Consult the Microsoft Dynamics AX 2009 documentation on TechNet for detailed instructions on how to publish Dynamics AX services using AIF administration forms through synchronous WCF Web services or asynchronous transports such as MSMQ, BizTalk Server, or XML file exchange. The guide is available for download at http://www.microsoft.com/dynamics/ax/using/default.mspx.

Configuring Dynamics AX Services

In this section, we briefly cover some key concepts related to configuring Dynamics AX services. A complete discussion of configuring Dynamics AX services is well beyond the scope of this book. Refer to the "Configuring and Managing AIF" topic on TechNet for more information.

Configuring WCF Parameters

When Dynamics AX services are published as synchronous WCF Web services, a WCF configuration file (web.config) is generated. This file is not generated when Dynamics AX services are published through any of the asynchronous AIF adapters. Note that a single web.config file contains the WCF configuration for all published Dynamics AX services.

Be sure to install Windows SDK for Windows Server 2008 before you modify any WCF configuration settings. Always use SvcConfigEditor instead of Notepad or an XML editor. Dynamics AX services published through WCF Web services support three bindings:

  • basicHttpBinding (used as the default binding when Dynamics AX services are published as WCF Web services)

  • customBinding (with WS-Addressing)

  • wsHttpBinding (with WS-Addressing)

Caution

Caution

Publishing Dynamics AX services as WCF Web services introduces additional dependencies on .NET Framework 3.5, Internet Information Server (IIS) 6.0 or later, and Windows Server 2008. Improper or incomplete installation of these external dependencies or default configurations that are inadequate for Dynamics AX services can prevent Dynamics AX services that have been published through WCF from working properly.

Configuring AIF Parameters

AIF provides a variety of configuration options for administrators of Dynamics AX services, including action policies, data policies, pipeline components, value mappings, and constraints.

Refer to the Microsoft Dynamics AX 2009 Server and Database Administration Guide for more details about service administration and related concepts, such as setting up and using AIF endpoints, action policies, and data policies.

Configuring Access to Services

Security keys protect access to each Dynamics AX service from external service clients. These security keys represent an additional security gate that helps guard Dynamics AX from unauthorized access by external users over the network; these security keys do not protect data. The existing Dynamics AX data access control applies in addition to these service security keys. Just as is recommended for general security in Dynamics AX, you should grant administrators access to services only when necessary and try to configure minimal access.

Refer to the Microsoft Dynamics AX 2009 documentation on TechNet for details on how to create and manage security keys and for detailed instructions on how to protect services with security keys.

Troubleshooting Tips for Services

When troubleshooting integrations, you can generally start with these two steps:

  1. The forms Queue Manager, Document History, and Exception Log—all located under BasicPeriodicApplication Integration Framework—provide additional information about errors that have occurred during request processing in Microsoft Dynamics AX.

  2. The Event Log provides additional information about errors that occurred in external components such as IIS or BizTalk Server.

The Microsoft Dynamics AX AIF blog at http://blogs.msdn.com/aif/. also offers a good set of troubleshooting tips for AIF. Here’s a sample of some of the troubleshooting guidance you can find on the AIF blog:

  • If the AIF administration Services form is empty, click Refresh and wait until the form has been populated.

  • If a service contract or data object doesn’t reflect changes you’ve applied to the service (e.g., added service operations or modified data objects), open the Services form in the Dynamics AX client, click Refresh, and then click Generate.

  • If a service returns error messages related to validation logic, first verify that your requests messages are well-formed XML and comply with the expected XML schema definitions. If your request messages don’t use message headers to override the default settings for message identifier, target company, source endpoint, or source endpoint user, check the default values (e.g., the submitting user’s default company, which is used for the target company).

Consuming Dynamics AX Services

Now that you’ve published your Dynamics AX services through one of the supported transport technologies, external service clients can consume them. By consuming published Dynamics AX services, service clients can leverage business functionality that is implemented in Dynamics AX. For instance, they can consume the SalesOrderService to manage sales orders in Dynamics AX—to create, read, update, delete, and find them.

How the published Dynamics AX services are consumed depends on what transport technology you use to publish your services. We don’t go into the details of configuring asynchronous adapters for message exchanges in this book; instead, we use WCF Web service clients to illustrate the overall process and highlight a few features.

For a more complete description of the available functionality and of asynchronous adapters, refer to the Dynamics AX 2009 Server and Database Administration Guide.

Sample WCF Client for Dynamics AX Services

For the following discussions, we use a .NET service client. If you want to consume a Dynamics AX service that has been published as a WCF Web service, you need to do the following:

  1. Instantiate and initialize parameters for the call.

  2. Instantiate the service proxy.

  3. Set (optional) SOAP headers if necessary.

  4. Consume the service.

  5. Evaluate the response and handle exceptions.

The following samples show C# code for each of these steps to consume the find service operation of the Dynamics AX document service CustomerService as it ships with Dynamics AX 2009, with its default configuration. We assume a service reference with the name CustomerService has been added to the project.

To consume the service operation find of the CustomerService document service, you need to instantiate and populate an object of the class QueryCriteria. The following code formulates a query for all Customer entities with an account number that is greater than or equal to 4000.

CustomerService.CriteriaElement[] qe = { new CustomerService.CriteriaElement() };
qe[0].DataSourceName = "CustTable";
qe[0].FieldName = "AccountNum";
qe[0].Operator = CustomerService.Operator.GreaterOrEqual;
qe[0].Value1 = "4000";
CustomerService.QueryCriteria qc = new CustomerService.QueryCriteria();
qc.CriteriaElement = qe;

The following code shows how to instantiate a service proxy and consume the service operation find, which executes a query and returns matching entities.

// instantiate proxy
CustomerService.CustomerServiceClient customerService =
    new CustomerService.CustomerServiceClient();

CustomerService.AxdCustomer customer;

// see [4] for details about this using directive
using (new OperationContextScope(customerService.InnerChannel))
{
    // set optional SOAP headers (see "Overriding Default Values in SOAP Headers")
    ...
    // consume the service operation find()
    customer = customerService.find(qc);
}

// error handling – additionally, exceptions should be handled properly
if (null == customer || 0 == ekList.Length)
{
    // error handling
}
CustomerService.AxdEntity_CustTable[] custTables = customer.CustTable;
if (null == custTables || 0 == custTables.Length)
{
    // error handling
}

// evaluate response
foreach (AxdEntity_CustTable custTable in custTables)
{
    custTable.AccountNum = ...
}

When you instantiate the proxy, you should always specify the name of a WCF client configuration. In addition, if you expect large amounts of data as a result of the consumption of the service operation find, you might want to use findKeys, which returns only entity keys for the matching entities instead of the entire record. You can then, for example, implement pagination logic that retrieves the matching entities in sizeable chunks.

The other service operations that are supported for document services are consumed in similar ways.

Updating Business Documents

In many scenarios, you need to update data that already exists in the Dynamics AX data store, for example, to add a line to a sales order or to update a customer address. Dynamics AX offers several ways to update your business documents, from full and partial updates to a document hash.

Full updates

The framework for Dynamics AX services supports document-centric update operations, that is, updating business documents (e.g., sales orders). The default behavior for updating documents is full updates, which includes the following:

  1. Read the document.

  2. Apply changes to the document.

  3. Send the updated document with the update request.

  4. Handle errors, if any.

The following C# code sample shows the programmatic process of updating a sales order conceptually, using full updates.

// instantiate and populate entityKeys
EntityKey[] entityKeys;
...

// read sales order(s) (including document hash(es)) using entityKeys
AxdSalesOrder salesOrder = service.read(entityKeys);

// process sales order, update data
...

// consume the service to update the record (exception handling not shown)
service.update(entityKeys, salesOrder);

In many scenarios, using full updates is inefficient. Imagine a large sales order with many sales lines—more than 1000 sales lines are not uncommon. According to the full updates process, you would have to retrieve the entire sales order with all sales lines, apply your changes to the one sales line you want to update, and then send the entire sales order with all sales lines—including all unchanged sales lines—back. This operation can be costly when you consider the validation and defaulting logic invoked for each sales line.

Partial updates

Instead of performing full updates, you can apply partial updates. Partial updates use the same service operation as full updates do, that is, update. Partial updates allow you to send partial documents instead of full documents. Partial documents contain only changed (added, modified, or deleted) records and processing instructions for AIF that specify how to handle each (child) record included in the partial document; the processing instructions are necessary to avoid ambiguity. Consequently, the process for updating documents using partial updates contains one more step in addition to the steps for full updates:

  1. Read the document (e.g., a sales order).

  2. Apply changes to the document.

  3. Explicitly request the mode partial update and add processing instructions.

  4. Send the updated document with the update request.

  5. Handle errors, if any.

The following code shows the programmatic process of updating a sales order conceptually, using partial updates.

// instantiate and populate entityKeys
EntityKey[] entityKeys;
...
// read sales order(s) (including document hash(es)) using entityKeys
AxdSalesOrder salesOrder = service.read(entityKeys);

// process sales order, pick data to be updated
...

// update the first sales order and mark it for partial update
AxdEntity_SalesTable[] salesTables = salesOrder.SalesTable;
salesOrder.SalesTable = new AxdEntity_SalesTable[] { salesTables[0] };
salesOrder.SalesTable[0].action = AxdEnum_AxdEntityAction.update;

// delete the first sales line; send only the modified data as part of update()
AxdEntity_SalesLine[] salesLines = salesOrder.SalesTable[0].salesLine;
salesOrder.SalesTable[0].SalesLine = new AxdEntity_SalesLine[] { salesLines[0] };
salesOrder.SalesTable[0].SalesLine[0].action = AxdEnum_AxdEntityAction.delete;

// remove other child data sources (DocuRefHeader, etc.) from salesTable
...

// consume the service to update the record (exception handling not shown)
service.update(entityKeys, salesOrder);

In request messages, these processing instructions present themselves in the form of XML action attributes; this is true for both XML messages sent to asynchronous adapters as well as for SOAP messages sent to synchronous WCF Web services. For more details, refer to the Document Services classes documentation in the Microsoft Dynamics AX 2009 SDK.

Document hashes

Document hashes are hashes that are computed for a specific document. They include data not only from the root level data source (e.g., the sales header) but also from all the joined data sources (e.g., a sales line). In other words, if a table field included in the business document changes, the document hash changes too.

AIF uses the document hash to implement optimistic concurrency control (OCC) to compare versions of business documents. Your code must always read the document before updating it using the service operation update.

Tip

Tip

Caching a document for a long time on a service client without refreshing it increases the probability of update requests being rejected because of colliding updates from other client applications.

Overriding Default Values in SOAP Headers

To streamline both AIF setup and configuration, AIF doesn’t require values to be specified in requests for context information, such as destination endpoint, source endpoint, source endpoint user, and message identifier. To override the default values for each of those parameters, you can use code similar to samples in this section. All the code examples use standard WCF APIs to set the respective SOAP headers. For these SOAP headers to take effect in the current message, you must wrap the code in a using directive (for OperationContextScope) as outlined in the section "Sample WCF Client for Dynamics AX Services" earlier in this chapter.

Message identifier

By default, WCF generates and uses a message identifier. Alternatively, you can explicitly specify the message identifier to be used for sending a request message by explicitly setting the value for the SOAP header used to exchange message identifiers. The client application can then use this message identifier to correlate received response messages with the original requests, for example.

// generate guid
Guid guid = new Guid();

// use guid as message identifier
OperationContext.Current.OutgoingMessageHeaders.MessageId =
  new System.Xml.UniqueId(guid);

// store guid for later use ...

Destination endpoint (target company)

By default, AIF uses the default company that the admninistrator has configured for the user sending the request. If the request needs to be executed in the context of another company, you can can specify that company explicitly.

// This assumes that a local endpoint with the name "Contoso" has been configured
// in Dynamics AX and is associated with a company that exists in Dynamics AX
String targetCompany = "Contoso";

// Execute the request in the context of "targetCompany"
OperationContext.Current.OutgoingMessageHeaders.Add(
  MessageHeader.CreateHeader(
    "DestinationEndpoint",
    "http://schemas.microsoft.com/dynamics/2008/01/services",
    targetCompany
  )
);

Source endpoint and source endpoint user

By default, AIF uses the default endpoint as the default value for the source endpoint and the submitting user as the default value for the source endpoint user. If the request needs to be executed in the context of another source endpoint and source endpoint user, both can be specified explicitly using a standard SOAP header.

// We assume that a source endpoint user "submittingUser" exists in the domain
// "ContosoDomain"; we also assume that the user credentials used to authenticate
// a user from "NorthwindTraders" have been mapped onto an identity within the
// domain "Contoso".
Uri sourceEndpoint = new Uri("urn:NorthwindTraders");
String sourceEndpointUser = "submittingUserContosoDomain";

// Create a WCF endpoint address builder.
EndpointAddressBuilder eab = new EndpointAddressBuilder(
  new EndpointAddress(
    sourceEndpoint
    AddressHeader.CreateAddressHeader(
      "User",
      "http://schemas.microsoft.com/dynamics/2008/01/services",
      endpointUser
    )
  )
);

// Initialize standard SOAP header "From" (see WS Addressing).
OperationContext.Current.OutgoingMessageHeaders.From =
  endpointAddress.ToEndpointAddress();

// Execute the request in the context of the given source endpoint and source
// endpoint user ...

Sample SOAP message

The following SOAP message represents a request to create a sales order. This SOAP message overrides the default values for all the optional headers as described earlier. The overriding XML elements are shown in bold.

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
    xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://schemas.microsoft.com/dynamics/2008/01/
services/SalesOrderService/create
    </a:Action>
    <a:From>
      <a:Address>urn:RemoteEP</a:Address>
      <a:ReferenceParameters>
        <SourceEndpointUser xmlns="http://schemas.microsoft.com/dynamics/2008/01/
services">redmondapurvag</SourceEndpointUser>
      </a:ReferenceParameters>
    </a:From>
    <DestinationEndpoint xmlns="http://schemas.microsoft.com/dynamics/2008/01/
services">LocalEP</DestinationEndpoint>
    <a:MessageID>urn:uuid:670bf145-5be2-4c9f-920c-468a4199aa75</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SalesOrderServiceCreateRequest
        xmlns="http://schemas.microsoft.com/dynamics/2008/01/services">
      <!-- sales order document -->
    </SalesOrderServiceCreateRequest>
  </s:Body>
</s:Envelope>

Sending One-Way Requests from Dynamics AX

In many scenarios, receiving a response or an error message from the consuming application isn’t required. An acknowledgment that the message has successfully been delivered to the next hop in a chain of reliable transport links (e.g., MSMQ) can be sufficient. Messages that are transmitted without a synchronous end-to-end feedback channel for response or error messages are referred to as one-way messages.

When you think about exchanging business documents electronically with your trading partners, you need to accept that it might not be realistic to assume that your trading partners’ applications will always be online and ready to receive your messages. With some partners, building more robust, loosely coupled integrations using one-way messages might be a better solution.

AIF provides APIs to send unsolicited one-way messages by using Dynamics AX services and the AIF infrastructure (e.g., channels and endpoints). The Dynamics AX client features Send Electronically buttons on several forms that allow you to transmit business documents (such as invoices) as unsolicited one-way messages through AIF channels to AIF endpoints. Dynamics AX is aware of only the AIF channel it needs to send the message to (i.e., the next hop); it doesn’t know the final destination of the message. Moreover, Dynamics AX doesn’t rely on any external document schema definitions to be provided by the remote receiving application; it uses its own format instead—the same Axd<Document> class-based XSDs that are also used as data contracts for published Dynamics AX services.

Implementing unsolicited messages exchanges requires the following two steps:

  1. Implementing a trigger for transmission (design time)

  2. Configuring transmission mechanisms (admin time)

Implementing a Trigger for Transmission

You can implement a trigger for transmission by using either the AIF Send API or the AxdSend API.

AIF Send API

The Send API in AIF features a set of methods that can be used to send unsolicited one-way messages from Dynamics AX to AIF channels, through which the consumers can pick up the messages. This API sends a single message; the body of the message is the XML that is generated by invoking the service operation read of the AIF document service referenced by serviceClassId (it must reference a class that derives from AifDocumentService) with the parameter entityKey.

To see a working example of how you can use this API, look at the code behind the method clicked for the button SendXmlOriginal on the form CustInvoiceJournal. The API methods are defined on the class AifSendService and include the method submitDefault.

public static void submitDefault(
    AifServiceClassId serviceClassId,
    AifEntityKey entityKey,
    AifConstraintList constraintList,
    AifSendMode sendMode,
    AifPropertyBag propertyBag = connull(),
    AifProcessingMode processingMode = AifProcessingMode::Sequential,
    AifConversationId conversationId = #NoConversationId
)

The two optional parameters in the preceding signature, processingMode and conversationId, are new in Dynamics AX 2009. They allow you to leverage the newly introduced parallel message processing feature for asynchronous adapters:

  • processingMode. Specifies whether messages can be moved from the AIF outbound processing queue to the AIF gateway queue in parallel (AifProcessingMode:: Parallel) or whether first in first out (FIFO) order must be enforced for all messages (AifProcessingMode::Sequential).

  • conversationId. If specified, moves from the AIF outbound processing queue to the AIF gateway queue in FIFO order, relative to all other messages with the same conversationId. The order relative to all other messages with other conversationIds isn’t guaranteed.

AxdSend API

The AxdSend API provides functionality to send unsolicited one-way messages for which the user needs to select AIF endpoints dynamically at run time or in which the message body contains more than a single entity. The user dynamically selects the exact range of entities, such as a range of ledger accounts, at run time. This feature has been implemented for several Dynamics AX document services, including AxdChartOfAccounts and AxdPricelist.

The AxdSend framework provides default dialog boxes for selecting endpoints and entity ranges and allows the generation of XML documents with multiple records. The framework allows you to provide specific dialog boxes for documents that need more user input than the default dialog box provides.

The default dialog box includes an endpoint drop-down list and, optionally, a Select button to open the standard query form. The query is retrieved from the Axd<Document> class the caller specifies. Many endpoints can be configured in the AIF, but only a few are allowed to receive the current document. The lookup shows only the endpoints that are valid for the document, complying with the constraint set up for the service operation read for the current document.

The framework requires minimal coding to support a new document. If a document requires you to simply select an endpoint and fill out a query range, most of the functionality is provided by the framework, without requiring additional code.

The standard dialog box for the AxdSend framework is shown in Figure 17-6.

Send Document Electronically dialog box for Chart of accounts

Figure 17-6. Send Document Electronically dialog box for Chart of accounts

If a document requires a more specific dialog box, you simply inherit the AxdSend class and provide the necessary user interface interaction to the dialog box method. In the following code example, an extra field has been added to the dialog box. You simply add one line of code (shown in bold in the following code from the AxdSendChartOfAccounts class) to implement parmShowDocPurpose from the AxdSend class and to make this field appear on the dialog box.

static public void main(Args args)
{
   AxdSendChartofAccounts axdSendChartofAccounts ;
   AifConstraintList aifConstraintList;
   AifConstraint aifConstraint;
   ;
   axdSendChartofAccounts = new AxdSendChartofAccounts();
   aifConstraintList = new AifConstraintList();
   aifConstraint = new AifConstraint();

   aifConstraint.parmType(AifConstraintType::NoConstraint);
   aifConstraintList.addConstraint(aifConstraint);
   axdSendChartofAccounts.parmShowDocPurpose(true) ;

    axdSendChartofAccounts.sendMultipleDocuments(classnum(AxdChartOfAccounts),A
ifSendMode::Async,aifConstraintList) ;

}

Sorting isn’t supported in the AxdSend framework, and the query structure is locked to ensure that the resulting query matches the query defined by the XML document framework. This need for matching is why the AxdSend class enforces these sorting and structure limitations. The query dialog box shows only the fields on the top-level tables because of the mechanics of queries with an outer join predicate. The result set will likely be different from what would be expected from a user perspective. For example, restrictions on inner data sources filter only these data sources, not the data sources that contain them. The restrictions are imposed on the user interface to match the restrictions on the query when using the document service’s operation find.

Configuring Transmission Mechanisms

For details on configuring AIF channels and information on AIF channels and AIF endpoints in general, refer to the Dynamics AX 2009 Server and Database Administration Guide.

Consuming Web Services from Dynamics AX

Web services are a popular and well-understood way of integrating applications that are deployed within an enterprise’s perimeter, or intranet. Examples of such applications include enterprise resource planning (ERP) applications, CRM applications, productivity applications such as Microsoft Office, and so on.

Integrating applications with third-party Web services over the Internet has also become viable and in many cases is the preferred approach to quickly adding new functionality to complex applications. Web services can range from simple address validation or credit card checks to more-complex tax calculations or treasury services. Integrating applications such as Dynamics AX with external Web services is often referred to as Software-plus-Services (S+S).

Note

Note

To find out more about S+S, see the article "Microsoft Software + Services—Bring It All Together" at http://www.microsoft.com/softwareplusservices.

The power of S+S lies in the opportunity to leverage the functionality of (almost) any Web service that is available as needed and thus in being able to outsource certain parts of business processes to trusted, specialized service providers in a cost-efficient way.

If you look at Figure 17-1 again, you can see the S+S scenarios in which Dynamics AX consumes external Web services on the right side.

Dynamics AX Service References

Dynamics AX service references can help you quickly integrate Dynamics AX with external Web services. Dynamics AX service references are conceptually similar to the service references in Microsoft Visual Studio 2008: each service reference represents a local interface to a remote Web service. A local API, that is, a proxy, can be used to communicate with the Web service. The proxy that is generated with Dynamics AX service references consists of .NET artifacts that can be discovered and used from X++ through CLR interop. Figure 17-7 illustrates how an external Web service can be integrated with Dynamics AX.

Integrating an external Web service with Dynamics AX

Figure 17-7. Integrating an external Web service with Dynamics AX

You generate Dynamics AX service references by using standard Microsoft tools that are part of .NET Framework 3.5 and Windows SDK for Windows Server 2008.

Consuming an External Web Service

In Dynamics AX, you can write code that consumes external Web services fairly easily. You need to take these simple steps at design time:

  1. Get the WSDL file for the external Web service.

  2. Create a Dynamics AX service reference.

  3. Write integration code.

  4. Then at run time, consume just the Web service as part of a business task and configure the service references as needed. We go over these steps in more detail in the following subsections.

Tip

Tip

Once you make sure Dynamics AX can connect to the external Web service, it is ready to go.

Getting the WSDL and Creating a Service Reference

First, you need to get access to the WSDL file for the service you want to consume. You can generate service references from WSDL files that are available online (addressed through http or https URLs) or offline in the file system (addressed through Universal Naming Convention [UNC] file paths).

Tip

Tip

Make sure the service contract (WSDL file) hasn’t changed since the integration was implemented.

To create a service reference, right-click the AOT node References, select Add Service Reference, and enter four pieces of information:

  • WSDL URL. The (http or https) URL or UNC file path pointing to the WSDL file for the target Web service.

  • .NET code namespace. Lets you discover the generated .NET artifacts with IntelliSense.

  • Reference name. A unique name by which the service reference can be identified in the Dynamics AX client.

  • Description (optional). A short text description of the service reference.

Tip

Tip

If you get the error "Cannot load CLR Object" while creating a service reference at run time, restart the AOS.

Once you fill in the information required for creating the service reference and click OK, an AOT node representing the new service reference is added.

Writing Integration Code

When the service reference is created, a .NET proxy for the external Web service is generated. You can use this .NET proxy from X++ code, through CLR interop, to communicate with the external Web service. You must grant CLR interop permissions to the code that accesses .NET assemblies to instantiate parameters used for invoking an operation of an external Web service or for consuming the service itself.

Use the .NET namespace you provided when you created the service reference and IntelliSense to discover the generated .NET artifacts from X++.

When you write code to consume external Web services from X++, you need to make sure it has the following characteristics:

  • It is marked to run on the server (AOS).

  • It grants and revokes interop permissions.

  • It explicitly passes a WCF endpoint name into the proxy constructor. The names of the available WCF endpoints are in the proxy’s WCF configuration file (in the AIF administration form Service References, click Configure).

  • It uses a valid license code for the external Web service (if applicable).

The following code sample uses the .NET proxy to consume the external Web service.

public static server boolean CheckCustomer (str customerName)
{
    DynamicsOfac.OfacSoapClient c;
    boolean b;

    // grant interop permissions
    new InteropPermission(InteropKind::ClrInterop).assert();

    // instantiate proxy using WCF endpoint name
    c = new DynamicsOfac.OfacSoapClient("OfacSoap");

    // consume Dynamics OFAC Web service
    b = c.LookupSdnByName(customerName);

    // revoke interop permissions
    CodeAccessPermission::revertAssert();

    // return results
    return b;
}

You need to write or modify code to use the results returned by the external Web service: for example, validation code that invokes a method similar to the one above that consumes an external Web service and returns the results.

Configuring Service References

You can view a list of available service references in the form Service References. To configure the WCF parameters for the new service reference, click Configure. Keep in mind that any changes you apply to the WCF configuration of the service proxy must be compatible with the WCF configuration of the service.

For more details on available WCF configuration parameters, see the Microsoft Dynamics AX 2009 SDK.

Note

Note

To configure Dynamics AX Services, we strongly recommend that you install Windows SDK for Windows Server 2008 so you can leverage the WCF configuration tools that are part of that SDK.

Guidelines for Consuming External Web Services

The main driver for programmatically consuming external Web services is improved efficiency—both technically and economically.

Integration Guidelines

Web services are a means for machine-to-machine integration. To streamline business processes, you should minimize the user’s interaction with the external Web service. The consumption of external Web services should always be in the background whenever possible and involve the user only when additional input is needed. The fact that the implementation of the business task consumes an external Web service is an internal implementation detail that isn’t relevant to the user.

When integrating external Web services, you should try to avoid duplicate data entry, which is time-consuming and error-prone. For example, assume that a sales order form has been filled out and a Web service needs to be invoked to calculate the best shipping option for delivering the goods to the recipient. It wouldn’t make sense to launch a form that prompts for details such as delivery address, weight, and so on. Instead, that information can be retrieved from the sales order form, transparent to the user; other data, such as weight, might be easily read from the database. Automatic data correlation helps reduce the risks inherent in data entry.

You should integrate external Web services in a way that allows you to switch service providers without affecting the rest of your Dynamics AX application code. One way of achieving this is through defining X++ interfaces for (relevant) functionality the external Web service exposes. This switching capability also shields your application logic from changes in the service contract (WSDL) published by the service provider.

Security Guidelines

You need to be very careful in choosing your service providers whenever you plan on exchanging confidential or business-critical data. Service-level agreements with your service providers should clearly define the provided security precautions as well as other parameters that are necessary for your scenario, such as guaranteed system uptime, response times, and so on. Be sure to conduct a proper security review before you go live with integrations with external Web services.

Refer to other literature or expert advice for more-complete information on securing integrations.

Privacy

When you exchange data with an external system—especially when that external system is outside the perimeter of your enterprise—you should always make sure that both data integrity and privacy are guaranteed. Because it is the external service that dictates the communication protocol and its configuration (including security), you should consider the supported security mechanisms when making a decision on what service provider to use for a particular integration.

Authentication

Because the code that consumes the external Web service is executed on the Dynamics AX server (AOS), AOS’s identity—not the user’s identity—is used for authenticating requests to external Web services. In most scenarios in which a third-party service provides the external Web service, using AOS’s identity isn’t a restriction. Authentication (and billing) would typically be per Web service call per company instead of per user.

To prevent spoofing, we strongly recommend that you request server certificates for server authentication.

Authorization

When consuming external Web services that are published by a third-party service provider, users who are authorized to perform a business task should automatically be authorized to consume all Web services needed to accomplish that task. For example, a user who is authorized to create a new customer record should automatically be authorized to use an external Web service for running a background check. The user shouldn’t have to be explicitly authorized to consume the Web service that performs the background check.

Custom SOAP Headers

If configured, WCF automatically inserts standard SOAP headers (such as used for WS-Addressing) into messages. Custom SOAP headers—that is, SOAP headers that are not understood by the WCF stack—are not supported in Dynamics AX 2009. In other words, the service proxies generated for service references don’t have an API for setting SOAP headers programmatically.

Keep in mind that the use of custom SOAP headers isn’t yet widely spread. Most commercial Web services don’t rely on them to increase interoperability.

Performance Considerations

In scenarios with more stringent performance requirements, the topology that supports the Dynamics AX deployment becomes even more critical. Consult the Dynamics AX Implementation Guide for details on properly sizing your deployment. It’s available for download from http://www.microsoft.com/dynamics/ax/using/default.mspx.

By default, messages received in AIF channel adapters process all request messages in sequence; this is true for incoming request messages as well as outgoing ones. To increase the number of request messages that can be processed, you can leverage additional instances of the AOS. Refer to the Microsoft Dynamics AX 2009 SDK on MSDN for more information on how to configure inbound channels for parallelism and how to use extensions to the AIF Send API.

Note that because synchronous WCF Web services are deployed to IIS, request processing is inherently parallel.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset