Chapter 12. AX 2012 services and integration

In this chapter

Introduction

Types of AX 2012 services

Consuming AX 2012 services

The AX 2012 send framework

Consuming external web services from AX 2012

Performance considerations

Introduction

After your company deploys AX 2012, you can benefit from automating your business processes. But to realize the full potential of AX 2012 and get the maximum return on investment (ROI) from your deployment, you should also consider automating interactions between AX 2012 and the other software in your company and in the companies of your trading partners.

In many business scenarios, external software applications require access to information that is stored in AX 2012. Figure 12-1 shows a few scenarios in which users access information that is managed in AX 2012 to accomplish a business task. It also shows sample scenarios in which AX 2012 accesses information that is managed in external applications. The arrows indicate the direction in which requests flow.

Image

FIGURE 12-1 Common integration scenarios.

You can see in Figure 12-1 that the users on the left side use applications that interact with the AX 2012 data store. These applications send request messages to AX 2012 (for example, to read a sales order). Sometimes, a response is expected from AX 2012—in this example, the requested sales order document.

In all of these scenarios, another software application exchanges information with AX 2012 to accomplish a task:

Image The company’s CEO uses an interactive application (such as a Microsoft Office application) to analyze sales data that is stored in AX 2012. The application communicates with AX 2012 on behalf of the CEO.

Image A salesperson who is visiting a prospect’s site uses a webpage or a mobile application to create a new customer account and then takes the first sales order in AX 2012 from a remote location.

Image A sales processor enters a sales order and uses customer records that are stored in a customer relationship management (CRM) application to populate the customer section of the order in AX 2012.

Image Trading partners submit sales orders as electronic documents, which need to be imported into AX 2012 periodically.

Image An accountant sends electronic payments or invoices to trading partners.

Performing these tasks manually without programmatically integrating AX 2012 with other applications and business processes doesn’t scale well and is error prone. With the AX 2012 services framework, you can encapsulate business logic—for example, functionality to create sales orders—in AX 2012 services. You can then publish these services through the Application Integration Framework (AIF). These services can participate in a service-oriented architecture (SOA).


Image Note

SOA is a significant area of software development. A complete discussion of SOA is outside the scope of this book. Good information is available about SOA, 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 (Pearson Education, Inc., 2005).


The AX 2012 service framework provides a toolset for creating, managing, configuring, and publishing AX 2012 services so that the business logic encapsulated in the service can be easily exposed through service interfaces. All service interfaces that are published through the AX 2012 service framework are compliant with industry standards and are based on core Microsoft technologies, including the software development kit (SDK) for Windows Server, Microsoft .NET Framework, Windows Communication Foundation (WCF), and Message Queuing (also known as MSMQ).

In addition to the programming model and tools for implementing services, the AX 2012 service framework includes the following:

Image A set of system services and document services that are included with AX 2012 and are ready for use

Image A set of features for manipulating inbound and outbound messages, such as support for transformations, value substitutions, and so on

Image An extensible integration framework that supports building new AX 2012 services and publishing them through a set of transport protocols such as Message Queuing, file, HTTP, or Net.tcp


Image Note

The concept of service references has been removed as of AX 2012.


Publishing AX 2012 services is a simple task that an administrator can do at run time. After a service has been published, external client applications, or service clients, can consume it.


Image Note

This chapter discusses configuration and administration tasks only where necessary to help you better understand the development scenarios. For additional details and code samples, see the AX 2012 “System administrators” documentation on TechNet (http://technet.microsoft.com/en-us/library/gg731797.aspx) or the AX 2012 Developer Center on MSDN (http://msdn.microsoft.com/en-us/dynamics/ax/gg712261).


Types of AX 2012 services

AX 2012 recognizes three types of services—system services, custom services, and document services—each with its own programming model. AX 2012 publishes metadata about available services and their capabilities in the form of Web Services Description Language (WSDL) files, which can be used for automatic proxy generation. The following sections explain each type of service in more detail.

System services

AX 2012 system services are generic, infrastructural services that are not tied to specific business logic. System services are included with AX 2012 and are automatically deployed, so AX 2012 components and external components can assume that these services are always available.

The functionality published by system services is often used by interactive clients that need to inquire about the capabilities or configuration of a specific deployment at run time. System services and their interfaces are not intended to be modified or reconfigured; they can only be hosted on the Application Object Server (AOS) and cannot be invoked through asynchronous transport mechanisms such as Message Queuing.

AX 2012 system services include the following:

Image Query service Publishes service operations that allow execution of existing (static) or ad hoc queries from service clients and returns results in the form of generic .NET datasets.

Image Metadata service Can be used to request information from AX 2012 about its metadata, such as tables, queries, and forms, and thus about its configuration.

Image User session info service Can be used to retrieve certain settings for the environment in which requests for the current user are executed; for example, a client application can use the user session service to request information about the current user’s currency, company, and time zone, among other things.

Custom services

You can use AX 2012 custom services to publish eligible X++ methods as service operations through integration ports for consumption by external client applications. To do that, you use the programming model for custom services to define metadata that determines the shape of the published service operations and data contracts. Custom services do not have to be tied to AX 2012 queries or tables. For example, you can use a custom service to publish functionality to approve an invoice or to stop a payment.


Image Note

Generally, AX 2012 document services are better suited for implementing services that publish standard operations that operate on queries or tables, such as create, read, update, and delete. These operations are often referred to as CRUD operations.


After you define the service operations and data contracts, you can publish your custom services. Their external interfaces can be configured through the respective system administration forms.

Custom service artifacts

To expose an X++ method as a custom service, you need to create the following artifacts:

Image Service implementation class A class that implements the business logic and exposes it through X++ methods.

Image Service contract Service-related metadata (no code). The most important service metadata consists of the service operations that are published to external service applications, and a reference to the X++ service implementation class that implements these service operations.

Image One or more data contracts X++ classes that represent the complex parameter types used for service operations. Data contracts are not needed for primitive data types.

Service implementation classes

A service implementation class contains the code that implements the business logic to publish. You can use any X++ class as a service implementation class. Service implementation classes don’t have to implement any interfaces or extend any super-classes. A class definition for a service implementation class MyService could look like this:

public class MyService
{
}

There are, however, constraints that govern which methods of a service implementation class can be published as service operations. Eligible methods are public methods that use only parameters with data types that can be serialized and deserialized; this includes most primitive data types in addition to valid AX 2012 data contracts. Also, eligible methods must be declared as service operations in the service contract in the Application Object Tree (AOT).


Image Note

Every method that is intended to be published as a service operation must be annotated with the attribute SysEntryPointAttribute, which indicates whether authorization checks are to be performed by the AOS.


The following code shows an example of a method that can be declared as a service operation in the AOT, assuming the X++ type MyParam is a valid data contract. (For more information, see the “Data contracts” section later in this chapter.)

[SysEntryPointAttribute(true)]
public MyParam HelloWorld(MyParam in)
{
  MyParam out = new MyParam();
  out.intParm(in.intParm() + 1);
  out.strParm("Hello world. ");
  return out;
}

Service contracts

Service contracts define which methods of a service implementation class are publishable as service operations and provide additional metadata that specifies how these methods should be published.


Image Note

Declaring a method as a service operation does not publish that method as a service operation.


To create a new service contract, you need to create a new child node in the AOT under the Services node—for example, MyService.

The newly created AOT node has a few properties to initialize before any methods of the service can be published as service operations:

Image Service implementation class This required property links the service interface to the service implementation class. In this example, the value is MyService.

Image Namespace Optionally, you can specify the XML namespace that should be used in the WSDL. If the XML namespace isn’t specified, http://tempuri.org is used by default.

Image 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. To do this, expand the new AOT node, right-click, and then point to Operations > Add Operation.

Note that you can publish as service operations only those methods that have been explicitly added to the service contract in the AOT.

Data contracts

A data contract is a complex X++ data type that can be used for input and output parameters in service operations. Most importantly, data contracts must be serializable. You can control how an X++ class is serialized and deserialized by the AX 2012 service framework through the X++ attributes DataContractAttribute and DataMemberAttribute:

Image DataContractAttribute declares an X++ class as a data contract.

Image DataMemberAttribute declares a property as a member of the data contract.

The following code shows a sample definition for the data contract MyParam, which was used in the previous example:

[DataContractAttribute]
public class MyParam
{
  int intParm;
  str strParm;
}

The following code shows a sample property that is included in the data contract:

[DataMemberAttribute]
public int intParm(int _intParm = intParm)
{
  intParm = _intParm;
  return intParm;
}

X++ collections as data contracts

If you want to use X++ collection types in data contract definitions, you need to ensure that all contained elements are of a data type that is supported for data contracts. Moreover, you need to provide additional metadata with the definition of the service method that uses the parameter, specifying the exact data type of the values in the collection at design time. You do this by using the X++ attribute AifCollectionTypeAttribute, as shown here for a sample method UseIntList():

[SysEntryPointAttribute(true),
  AifCollectionTypeAttribute('inParm', Types::Integer)]
public void UseIntList(List inParm)
{
  ...
}

The two parameters you need to pass into the constructor of the attribute are the name of the parameter to which the metadata is to be applied (inParm in the example) and the type of elements in the collection (Types::Integer in the example).

If you want to store X++ class types in your collection, you must also specify the class, as shown in the following example:

[SysEntryPointAttribute(true),
  AifCollectionTypeAttribute('return', Types::Class, classStr(MyParam))]
public List ReturnMyParamList(int i)
{
  ...
}

The three parameters that are passed into the AifCollectionTypeAttribute constructor are the name of the parameter (return), the type of the elements of the collection type (Types::Class), and the specific class type (MyParam).


Image Note

The parameter name return is reserved for the return value of a method.


Registering a custom service

After you create all of the artifacts that are necessary for the custom service, you need to register the new service with the AX 2012 service framework. To register the service (in this example, MyService) with AIF, expand the Services node in the AOT, right-click the node you created earlier, and then point to Add-Ins > Register Service.

As a result of the registration, you can publish all declared service operations of your service. For more information, see the “Publishing AX 2012 services” section later in this chapter.

Document services

The term document services stems from the reality that businesses need to exchange business documents, such as sales orders and invoices, with their trading partners. Document services operate on electronic representations of such business documents.

The AX 2012 implementation of these business documents is also referred to as Axd documents. Document services are generated from AX 2012 queries. Wizards automate the process of quickly generating and maintaining all necessary artifacts for document services, with a configurable set of well-known service operations, from queries.

By nature, document services provide document-centric application programming interfaces (APIs)—that is, APIs that operate on Axd documents. Examples of document-oriented APIs for a sales order service include create sales order, read sales order, and delete 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 AX 2012 data store, and returns the sales order identifier for the persisted instance.

Document services are useful in scenarios that require the exchange of business documents such as sales orders. In these scenarios, exchanged data is transacted and thorough data validation is important, data exchanges are expensive (for example, because enterprise boundaries are crossed), and response times are not critical. Sometimes, responses are not even expected (one-way communication).

The programming model for document services supports customizations to the artifacts that are generated. AX 2012 includes a set of document services that are ready to use. However, you can customize these services to better fit your business needs. The programming model for document services supports the data access layer features that have been introduced with AX 2012, such as surrogate key expansion, table inheritance, and date effectivity. In other words, the AX 2012 service framework supports the development of services that use the tables that take advantage of the new functionality.

Document service artifacts

Just like custom services, all document services in AX 2012 require a service contract, a service implementation, and a data contract. For document services, these artifacts are generated from Axd queries; thus, their default implementation follows conventions and looks as follows:

Image Service contract Service-related metadata (no code) that is stored in the AOT nodes under the Services node, such as SalesSalesOrderService. The metadata includes the following:

• Service operations that are available to external service clients.

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

Image Service implementation The code that implements the business logic that is to be exposed. For generated document services, the service implementation includes the following key elements:

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

Axd<Document> class An X++ class that derives from AxdBase. Axd<Document> classes coordinate 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. The AxdBase class, among others, implements code for XML serialization.

Additional artifacts Optionally, the AIF Document Service Wizard can generate additional artifacts such as Ax<Table> classes.


Image Note

In earlier versions of Microsoft Dynamics AX, an Ax<Table> class was generated for each table referenced from a query that was used to generate an Axd<Document> class. By default, in AX 2012, Axd<Document> classes use the Ax<Table> class AxCommon to access tables. The AxCommon class provides a default implementation for all Ax<Table> class functionality. Ax<Table> classes are needed only in advanced scenarios, such as when a custom value mapping needs to be implemented for a table field.


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

For a complete list of document service artifacts, see the “Services and Application Integration Framework (AIF)” section of the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/gg731810.aspx).

The following sections cover a few selected topics for both Axd<Document> and Ax<Table> classes. For more information, see the “AIF Document Services” section of the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/bb496530.aspx).

Axd<Document> classes

Axd<Document> classes (such as AxdSalesOrder) extend the X++ class AxdBase. Among other things, Axd<Document> classes do the following:

Image Implement XML serialization for data objects.

Image Invoke value mapping.

Image Orchestrate cross-table field validation and defaulting.

Axd<Document> classes provide default implementations for XML serialization for all data objects that are used. These classes derive XML schema definitions used for XML serialization directly from the structure of the underlying query. The XML serialization code uses Microsoft Dynamics AX concepts such as extended data types (EDTs) to further restrict valid XML schemas and improve XML schema validation. Moreover, when generating XML schemas, Axd<Document> classes take the data access layer features that have been introduced in AX 2012 into consideration. For example, the generated XML schema definitions reflect date-effective table fields, expanded dimension fields, and the inheritance structure of the tables used in the underlying Axd query, if applicable; surrogate foreign key fields are replaced with alternate keys, if configured.

Axd<Document> classes always access tables through the Ax<Table> classes. During serialization, Axd<Document> classes rely on AxCommon or custom Ax<Table> classes to persist data to tables and to read data from tables.

Figure 12-2 illustrates the mapping between an AX 2012 query used for the Axd<Document> class AxdSalesOrder and the generated XML schema definition.

Image

FIGURE 12-2 Correlation between the AOT query and the XML document structure.

Axd<Document> classes also provide an API for orchestrating cross-table field validation and defaulting. Validation and defaulting logic that is relevant only for a specific Axd<Document> class but not for all Axd<Document> classes that use the same table can also be implemented in Axd<Document> classes.

Axd<Document> instances can be uniquely identified through AifEntityKeys, which consist of a table name (name of the root table for the Axd query), the field names for a unique index of that table, and the values of the respective fields for the retrieved record. In addition, AifEntityKeys holds the record ID of the retrieved records.

Ax<Table> classes

Ax<Table> classes (such as AxSalesTable and AxSalesLine) derive from the X++ class AxInternalBase. Unlike in earlier versions of Microsoft Dynamics AX, an Ax<Table> class is not needed for each table that is used in a document service; instead, the Ax<Table> class AxCommon has been introduced in AX 2012, which Axd<Document> classes use by default to access tables.


Image Note

Document services that are included with AX 2012 might still rely on custom Ax<Table> classes for tables used in the underlying query, especially if those services were created in earlier versions of Microsoft Dynamics AX, before the introduction of the AxCommon class.


However, there are scenarios in which custom Ax<Table> classes are required—for example, when parm methods for fields on the underlying table are needed to do the following:

Image Support calculated fields for a table in the Ax<Table> class.

Image Support a custom value mapping, which is different from the default implementation in AxCommon.


Image Note

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


Although optional in AX 2012, Ax<Table> classes can be generated as part of the document service with the AIF Document Service Wizard.

Creating document services

You generate document services based on Axd queries by using the AIF Document Service Wizard. This section discusses a few selected aspects of generating and maintaining document services.

Creating Axd queries

Although general guidelines for working with AX 2012 queries apply to Axd queries, some additional constraints and guidelines apply:

Image Name AX 2012 queries that are used for document services with the prefix Axd followed by the document name. For example, the document service query for the document SalesOrder should be AxdSalesOrder. This is a best practice.

Image Only one root table for each 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.

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

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


Image Note

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


Generating a document service

To generate a document service from an existing Axd query, you can use the AIF Document Service Wizard. To start the wizard, on the Tools menu, point to Application Integration Framework > Create Document Service. This section provides a high-level description of the AIF Document Service Wizard and some important notes about how to use it.

In the wizard, you can select the service operations you want to generate for your service: create, read, update, delete, find, findKeys, getKeys, and getChangedKeys. 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 tables used in the query.

The AIF Document Service Wizard uses the document name—which you enter on the first screen—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 produces names that are too long for one or more artifacts, you might get error messages.

After the wizard finishes, it displays a report of all generated artifacts and any errors encountered. You need to fix all errors before you start customizing the code that the wizard generates.


Image Tip

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


You can use the Update Document Service dialog box to update existing document services—for example, to add a service operation that you had not selected initially.


Image Note

Although you can create and update document services manually, it is not recommended. Instead, always use the AIF Document Service Wizard to generate new document services from AOT queries, and use the Update Document Service dialog box to quickly update existing document services.


AX 2012 includes more than 100 ready-to-use document services. These include services such as SalesOrderService and CustomerService. You can find a list of these services in the AOT Services node, or in the topic “Standard Document Services” in the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/aa859008.aspx).

For a more comprehensive discussion of the AIF Document Service Wizard and generating Axd<Document> and Ax<Table> classes, see the “AIF Document Services” section of the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/bb496530.aspx).

Customizing document services

In many cases, you might need to customize the document services that you have generated from queries or that are included with AX 2012 to better fit your business needs. This section addresses some of the most common scenarios for customizing document services, including customizing the tables or queries, service operations, validation, defaulting, queries, and security.

Customizing tables

When you customize a table that is used by a document service (for example, by adding a column), you need to update the service implementation—that is, the Axd<Document> and Ax<Table> classes and the data objects—to reflect these changes.


Image Tip

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 dialog box to update the Axd<Document> class, Ax<Table> classes, and data objects to reflect the changes.



Image Caution

Because document services are based on AX 2012 queries, changing the structure of a query that is used in a document service (for example, by adding a column to a table used in the query) also changes the data contract for that document service. Changes in external interfaces such as service interfaces can potentially break integrations that were built by using the original data contract. Always consider the impact of changing queries or tables that are used in document services, and apply common best practices for nonbreaking service interface changes, such as not removing service operations or data contract fields, and adding only optional fields.



Image Tip

If you use a static field list for the query from which an Axd document service is generated, you can prevent the data contract for the Axd document service from implicitly changing when a field is added to a table.


Adding custom service operations

You can change the behavior of any service operation 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

Validation logic is crucial for enforcing data hygiene. Ideally, invalid data is never persisted in the AX 2012 data store.


Image Tip

To achieve this goal, always verify the validation logic of each service operation that you generate or customize to make sure that it meets your requirements.


Well-designed validation logic has the following characteristics:

Image Reusability Ideally, the same (generic) validation logic can be used from the AX 2012 client and from AX 2012 services. Keep in mind that nongeneric validation code—code that applies only to the AX 2012 client or only to AX 2012 services—is also possible.

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

Image Sufficiency Validation logic must guarantee a sufficient level of data hygiene. You might have to trade sufficiency for performance in a way that satisfies your application’s requirements.

Validation code consists mainly of the following elements:

Image 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.

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

Image 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 are called for each Ax<Table> class.

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

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

public boolean prepareForSave(AxdStack _axdStack, str _dataSourceName)
{

    // ...

    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;

        // ...
    }

    return false;
}

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 client applications and AX 2012 service interfaces. It derives initial values for table fields from other data such as values of other table fields, and thus it 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:

Image Reusability You should implement defaulting logic so that it is reusable—that is, so the same logic can be used regardless of which AX 2012 client (for example, 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 AX 2012 client is interactive (a user interface) or noninteractive (a request from a service client).

Image Good performance Because the defaulting logic for a table field is invoked every time the field is set, its execution time directly affects the processing time for manipulating the entity, such as a sales order. In particular, try to avoid redundant defaulting steps—that is, setting a field value that is overwritten again as part of the same defaulting logic.

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

AX 2012 still supports the approach to implementing defaulting logic that was supported in previous versions of Microsoft Dynamics AX. However, in AX 2012, mechanisms for tracking field states (such as not set and defaulted) have been added to tables, which means that you can implement defaulting logic directly in table classes. This allows for defaulting logic to be used not only by Axd<document> classes, but also from forms, and so on. Note that because now you can implement defaulting logic directly in the table class, an Ax<Table> class is not necessary for implementing standard defaulting code.

For more details about implementing and customizing defaulting logic in AX 2012 and information about how to customize document services in general, see the “AIF Document Services” section of the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/bb496530.aspx).

Security considerations

Service operations are entry points through which external applications can submit requests on behalf of users. As mentioned earlier, all X++ methods that are intended to be published as service operations must be annotated with the X++ attribute SysEntryPointAttribute, indicating whether the method is to be invoked in the context of the calling user. If so, authorization checks must be performed for tables accessed within the method. In addition, all concepts related to role-based security also apply to services and service operations.

System services are generally accessible and executed in the calling user’s context. Because as the developer, you are in charge of the implementation of custom services, you must add the SysEntryPointAttribute manually to all service operations and create permissions when necessary.

When you generate document services by using the AIF Document Service Wizard, all generated service operations are automatically annotated with SysEntryPointAttribute. Moreover, the wizard attempts to infer all security permissions for the generated service automatically.


Image Tip

When using the AIF Document Service Wizard, always verify that the generated artifacts meet your requirements, and adjust them if they don’t.


Publishing AX 2012 services

After you create and customize your service, you need to publish it for external applications to be able to consume it. Developing a service and publishing a service are two separate and largely independent processes.

With the AIF, you can publish AX 2012 services through various transport technologies. In addition, the AIF provides a variety of configuration options that administrators can use to customize how service interfaces are published. This chapter limits the discussion of the AIF to publishing services through basic integration ports. For more information, see the services administration documentation for AX 2012 on TechNet (http://technet.microsoft.com/en-us/library/hh209600.aspx). You can also find guidance on how to develop, set up, and use concepts such as data policies, transformations, pipeline components, and value mappings in this documentation.

For development and debugging purposes, you can easily publish registered custom services and document services through basic integration ports directly from the AOT. You can also use service groups to ensure that services are deployed and activated automatically when the AOS is started by using the AutoDeploy property of the respective service group. This is useful when you need to be able to consume a service without administrator intervention—for example, to enable the service manually after deploying AX 2012.

To publish a service through a basic integration port, you first need to add it to a service group in the AOT. Then you can deploy the service group with a default configuration by using NetTcpBinding in WCF, right from the AOT. For more information, see the topics “Services, service operations, and service groups” (http://technet.microsoft.com/en-us/library/gg731906.aspx) and “Using Basic Integration Ports” (http://technet.microsoft.com/en-us/library/hh496420.aspx) on TechNet.

AX 2012 services that are published through basic integration ports can only be hosted directly on the AOS. There are limited configuration options available for services published through basic integration ports. From the Inbound ports form (System Administration > Setup > Services And Application Integration Framework > Inbound Ports), you can activate and deactivate basic integration ports, you can use SvcConfigUtil to modify WCF configuration parameters, and you can enable logging for the respective ports.


Image Note

If you need to publish a service through a WCF binding other than NetTcpBinding, if you need to send unsolicited messages (outbound messages), or if you need more control over message processing and, for example, use XSLT transformations, you must create an enhanced integration port. You can create enhanced integration ports from the Inbound Ports form or the Outbound Ports form, respectively.


Discussions in this chapter generally assume that services have been published through basic integration ports unless noted otherwise. For details about how to publish services through bindings other than NetTcpBinding (for example, Message Queuing or file system adapters) by using enhanced integration ports and how to create ports for outbound messages, and for additional configuration options, see the services and AIF documentation for AX 2012 on TechNet (http://technet.microsoft.com/en-us/library/gg731810.aspx).

The Microsoft Azure Service Bus adapter, which is new for AX 2012 R2 cumulative update 6, extends existing AIF functionality by deploying AX 2012 services to the cloud by means of the Azure Service Bus Relay. You can use this adapter to develop client applications that communicate with AX 2012 R3 over the Internet. The Service Bus Relay works without any changes to existing enterprise network security settings. It acts as a message relay to pass service messages that are received over the Internet to AX 2012 services and returns the message responses to the client application. For more information about deploying the Service Bus adapter, see the AIF documentation on MSDN (http://go.microsoft.com/fwlink/?LinkId=391768&clcid=0x409).

The Service Bus adapter supports a solution architecture that enables applications to receive information and send transactions to AX 2012 R3, even if the applications are not in the same domain or network as the on-premises instance of AX 2012 R3. For example, you can create a Windows Phone application that communicates with AX 2012 R3 by using a service that runs behind a firewall. For more information, see Chapter 22, “Developing mobile apps for AX 2012.”

Consuming AX 2012 services

After you publish your AX 2012 services, external client applications can consume them and invoke the exposed business logic. For example, after the SalesOrderService is exposed, client applications can consume it to create or read AX 2012 sales orders.

This section highlights a few aspects of consuming AX 2012 services from client applications. As mentioned earlier, this chapter assumes that services are published through basic integration ports on the AOS. Services that are published through basic integration ports are accessible through Net.tcp. For a more complete description of how to publish AX 2012 services, including the use of asynchronous adapters and related technologies, see the services and AIF documentation for AX 2012 on TechNet (http://technet.microsoft.com/en-us/library/gg731810.aspx).

Sample WCF client for CustCustomerService

If you want to consume an AX 2012 service that has been published through a basic integration port, you need to generate proxy classes from the WSDL of the service you want to consume. Typically, you do this either from within your development environment (Microsoft Visual Studio) or by using a command-line tool such as SvcUtil.

After you generate the proxy classes from the WSDL and add them to a project in your development environment, you need to write code to do the following:

Image Instantiate and initialize parameters.

Image Optionally instantiate and initialize a call context.

Image Instantiate a service proxy.

Image Consume the service operation.

Image Evaluate the response.

Image Handle errors and exceptions.

This section contains an example that illustrates what the code for consuming the service operation find on the document service CustCustomerService (included with AX 2012) might look like.

For the example, assume that the document service CustCustomerService has been published through the service group MyServiceGroup and that a Visual Studio project has been created. Also, in Visual Studio, the service reference MyServiceGroup was added by using the WSDL for the basic integration port MyServiceGroup. For details about where AX 2012 publishes WSDL files, see the topic “Locating the WSDL for Services” in the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/gg843514.aspx).

The following code snippets show C# code for the steps to consume the service operation find of the AX 2012 document service CustCustomerService.

First, you need to instantiate and initialize the parameters needed for the call. The service operation find accepts two input parameters: an optional call context and a query criterion that specifies which customer records should be returned. The following example retrieves all customer records in the company named CEU with an account number greater than or equal to 4,000:

// instantiate and initialize parameters

// parameter: call context
MyServiceGroup.CallContext cc = new MyServiceGroup.CallContext();
cc.Company = "CEU";

// parameter: query criteria
MyServiceGroup.QueryCriteria qc = new MyServiceGroup.QueryCriteria();
MyServiceGroup.CriteriaElement[] qe = { new MyServiceGroup.CriteriaElement() };
qe[0].DataSourceName = "CustTable";
qe[0].FieldName = "AccountNum";
qe[0].Operator = MyServiceGroup.Operator.GreaterOrEqual;
qe[0].Value1 = "4000";
qc.CriteriaElement = qe;


Image Tip

You can use a CallContext object to execute a request in a different context than the default context, which is used if a null or empty CallContext object is used for a request. In the CallContext object, you can specify the company, language, and more.


Next, you need to instantiate a service proxy and consume the service operation find, which executes a query and returns matching entities:

// instantiate a service proxy
MyServiceGroup.CustomerServiceClient customerService =
    new MyServiceGroup.CustomerServiceClient();

// consume the service operation find()
MyServiceGroup.AxdCustomer customer = customerService.find(cc, qc);

Finally, you need to evaluate the response from the server, which can be either query results or exception and error messages:

// error handling (additionally, exceptions need to be handled properly)
if (null == customer)
{
    // error handling...
}

// evaluate response
MyServiceGroup.AxdEntity_CustTable[] custTables = customer.CustTable;
if (null == custTables || 0 == custTables.Length)
{
    // handle empty response...
}
foreach (MyServiceGroup.AxdEntity_CustTable custTable in custTables)
{
    custTable...
}


Image Note

Exception handling and other common best practices for developing web service clients are omitted from the simplified code examples.


Here are some tips for working with document services:

Image Many document services support both service operations find (which returns all Axd documents in the result set) and findKeys (which returns only the entity keys for Axd documents in the result set). If you expect the response message for invoking find to be very large, you might want to use findKeys to retrieve the entity keys. You can then, for example, implement paging to retrieve the matching Axd documents in sizeable chunks.

Image When developing new services, it is usually useful to turn on logging on the server side. To do that, open the Inbound Ports form, deactivate the integration port that publishes the service group containing your service, enable logging in the Troubleshooting section of the Inbound Ports form, and then reactivate your integration port.

Image If a service operation returns large response messages, you might need to tweak the default settings in your WCF configuration files for both the service and the client. By default, both service and client WCF configurations allow messages of sizes up to 65,536 bytes. The maximum message and buffer sizes are defined through the parameters maxReceivedMessageSize and maxBufferSize in the binding section of standard WCF configuration files. Before changing these parameters, refer to .NET Framework developer documentation to understand implications and valid values for these parameters. The .NET Framework Developer Center is located at http://msdn.microsoft.com/en-us/netframework/aa496123.

Other service operations for custom or document services can be consumed in similar ways. For more information and code examples, see the AX 2012 SDK at http://msdn.microsoft.com/en-us/library/aa496079.aspx.

Consuming system services

Unlike custom services and document services, system services are automatically published (on the AOS by using the NetTcpBinding) and are ready for consumption by client applications when the AOS starts.

Like all AX 2012 services, system services publish metadata in the form of WSDL files, which you can use for proxy generation (see the previous examples). However, whereas the user session info service is published explicitly through an integration port (UserSessionService), similar to custom and document services, an integration port does not exist for the query service or the metadata service.

The following code provides an example of how to work with the metadata service and the query service and shows how to do the following:

Image Retrieve query metadata (the definition of a query named MyQuery) from AX 2012 by using the metadata service.

Image Convert the query metadata from the data contract used by the metadata service to the data contract used by the query service. This conversion is necessary although both data contracts are structurally identical (see the method ConvertContract in the next code example).

Image Add a range to the metadata object; in this case, include all rows with a value greater than 1996 for the Year column.

Image Execute the converted query definition by using the query service.

In .NET code, these steps could be implemented in a similar way to the code sample that follows. Assume that you’ve created a Visual Studio project and added the references MetadataService and QueryService by using the WSDLs for the metadata service and the query service, respectively. For details about where AX 2012 publishes WSDL files, see the topic “Locating the WSDL for Services” in the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/gg843514.aspx).

// instantiate proxies
var metadataClient = new MetadataServiceReference.AxMetadataServiceClient();
var queryClient = new QueryServiceReference.QueryServiceClient();

// retrieve query metadata
MetadataService.QueryMetadata[] query =
  metadataClient.GetQueryMetadataByName(new string[] { "MyQuery" });

// convert query metadata
QueryService.QueryMetadata convertedQuery = ConvertContract
  <MetadataService.QueryMetadata, QueryService.QueryMetadata>(query);

// add a range to the query metadata object
QueryDataRangeMetadata range = new QueryDataRangeMetadata()
{
  Enabled = true,
  FieldName = "Year",
  Value = ">1996"
};
convertedQuery.DataSources[0].Ranges = new QueryRangeMetadata[] { range };

// initialize paging (return 3 records or less)
QueryService.Paging paging = new QueryService.ValueBasedPaging();
((QueryService.ValueBasedPaging)paging).RecordLimit = 3;

// instantiate a service proxy
QueryService.QueryServiceClient queryService =
  new QueryService.QueryServiceClient();

// execute the converted query with the range, receive results into .NET dataset
System.Data.DataSet ds =
  queryClient.ExecuteQuery(convertedQuery, ref paging);

Note that although the QueryMetadata definition is identical in both the query service and the metadata service, the proxy generator generates an identical class in two different namespaces, one for each service. A ConvertContract method that implements the conversion of two contracts of the same structure by using generics could look similar to the following code:

static TTargetContract ConvertContract<TSourceContract, TTargetContract>
    (TSourceContract sourceContract)
        where TSourceContract : class
        where TTargetContract : class
{
  TTargetContract targetContract = default(TTargetContract);
  var sourceSerializer = new DataContractSerializer(typeof(TSourceContract));
  var targetSerializer = new DataContractSerializer(typeof(TTargetContract));
  using (var stream = new MemoryStream())
  {
    sourceSerializer.WriteObject(stream, sourceContract);
    stream.Position = 0;
    targetContract = (TTargetContract)targetSerializer.ReadObject(stream);
  }
  return targetContract;
}

As mentioned earlier, the CallContext is used to override the default context (such as company and language) in which a request is executed. A CallContext is optional for all service requests; if it is not present in a request, the request is executed by using default values for the CallContext properties.

In AX 2012, the WSDL files for the query service and the metadata service do not contain the XML schema definitions for CallContext. Consequently, proxies generated from the WSDL files for those services do not include proxy classes for CallContext; however, CallContext can still be used for the query service and the metadata service the same way it is used with other services. To use CallContext in requests sent to the metadata service or the query service, you need to add a service reference to an integration port (such as UserSessionService), which generates the proxy classes necessary for CallContext. You can then instantiate and initialize a CallContext object and add it to your request, as shown in the following code:

// get OperationContextScope (see WCF documentation)
using (System.ServiceModel.OperationContextScope ocs =
    new System.ServiceModel.OperationContextScope((queryService.InnerChannel))) {

  // instantiate and initialize CallContext (using class from other service)
  CustomerService.CallContext callContext = new CustomerService.CallContext();
  callContext.Company = "CEU";

  // explicitly add header "CallContext" to set of outgoing headers
  System.ServiceModel.Channels.MessageHeaders messageHeadersElement =
  System.ServiceModel.OperationContext.Current.OutgoingMessageHeaders;
  messageHeadersElement.Add(
    System.ServiceModel.Channels.MessageHeader.CreateHeader(
      "CallContext",
      "http://schemas.microsoft.com/dynamics/2010/01/datacontracts",
      callContext));

  // initialize paging (return 3 records or less)
  QueryService.Paging paging = new QueryService.ValueBasedPaging();
  ((QueryService.ValueBasedPaging)paging).RecordLimit = 3;

  // instantiate a service proxy
  QueryService.QueryServiceClient queryService =
      new QueryService.QueryServiceClient();

  // consume query service using CallContext
  System.Data.DataSet ds =
      queryService.ExecuteStaticQuery("MyQuery", ref paging);
}


Image Note

The query service returns query results in chunks that are defined through a required paging parameter. The paging algorithms assume that queries use relations with FetchMode set to 1:1 (AOT property). The query service produces an error message for queries that use relations with FetchMode set to 1:n.


Refer to the product documentation for further details about the CallContext or capabilities of system services.

Updating business documents

In many scenarios, you need to update data in already-existing Axd documents, such as to add a sales line to a sales order or to update a customer address. Through the service operation update, document services support different semantics for document-centric updates: full updates and partial updates.

For the following examples, assume that the standard document service SalesSalesOrderService has been added to a service group named MyServiceGroup and published through a basic integration port named MyServiceGroup.

Applying a full update

Full updates are the default behavior for document services. To use this mode, add code to your client application to do the following:

Image Read the document.

Image Apply changes to the document.

Image Send the updated document back to the server.

Image Handle errors, if any.

The following C# code provides a conceptual example of how to apply a full update to an existing sales order:

// instantiate and initialize callContext, entityKeys, serviceOrderService
MyServiceGroup.EntityKey[] entityKeys = ...
MyServiceGroup.CallContext callContext = ...
MyServiceGroup.SalesOrderServiceClient salesOrderService = ...
...

// read sales order(s) (including document hash(es)) using entityKeys
MyServiceGroup.AxdSalesOrder salesOrder =
    salesOrderService.read(callContext, entityKeys);

// handle errors, exceptions; process sales order, update data
...

// persist updates on the server (exception handling not shown)
salesOrderService.update(callContext, entityKeys, salesOrder);

Applying a partial update

In many scenarios, full updates are inefficient. Imagine a large sales order with many sales lines—having more than 1,000 is not uncommon. If you use a full update, 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 back the entire sales order—including all unchanged sales lines. This operation can be costly when you consider the validation and defaulting logic invoked on the server for each sales line.

Instead of performing a full update, you can apply a partial update. Partial updates use the same service operation as full updates do: update. However, with partial updates, you can send partial documents that contain only the changed (added, modified, or deleted) data. For child elements, documents sent in partial update requests contain processing instructions specifying how to handle each (child) record included in the partial document to avoid ambiguity. Consequently, the process for updating documents by using partial updates contains one additional step:

Image Read the document.

Image Apply changes to the document. To take advantage of partial updates, ensure that you send back to the server only those fields that are either mandatory or that have changed.

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

Image Send the updated document with the update request.

Image Handle errors, if any.

The following code provides a conceptual example of how to apply a partial update to a sales order:

// instantiate and initialize callContext, entityKeys, serviceOrderService
MyServiceGroup.EntityKey[] entityKeys = ...
MyServiceGroup.CallContext callContext = ...
MyServiceGroup.SalesOrderServiceClient salesOrderService = ...
...

// read sales order(s) (including document hash(es)) using entityKeys
MyServiceGroup.AxdSalesOrder salesOrder =
    salesOrderService.read(callContext, entityKeys);

// handle errors, exceptions; process sales order, update data
...

// example: update the first sales order and mark it for partial update
AxdEntity_SalesTable[] salesTables = salesOrder.SalesTable;
salesOrder.SalesTable = new AxdEntity_SalesTable[] { salesTables[0] };
// document-level directive, requesting a partial update
salesOrder.SalesTable[0].action = AxdEnum_AxdEntityAction.update;

// table-level directive, requesting to delete the first sales line
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 child data sources w/o updates (DocuRefHeader, etc.) from salesTable
...

// persist updates on the server (exception handling not shown)
salesOrderService.update(callContext, entityKeys, salesOrder);


Image Note

In XML request messages, these processing instructions are reflected through occurrences of the XML attribute action. This is true for both XML messages sent to asynchronous adapters and for Simple Object Access Protocol (SOAP) messages sent to synchronous WCF services. For more details, see the “AIF Document Services” section of the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/bb496530.aspx).


Optimistic concurrency control

The services framework relies on optimistic concurrency control (OCC) to resolve conflicts when multiple concurrent update requests occur. To be able to detect whether a document has changed since it was last read, and to avoid inadvertently overwriting such changes, the service framework uses document hashes to identify versions of a business document.

Document hashes are computed for a specific document instance from its contents; they are derived not only from the root-level data source (such as the sales header) but also from all of the joined data sources (such as a sales line). In other words, if a field in any table that is included in the business document changes, the document hash changes, too.

To obtain the document hash for a business document, your code must first read the document. It can then use the document hash that was returned inside the document in a subsequent update request.


Image 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.


Invoking custom services asynchronously

Because publishing a service is separate from developing the service, both custom services and document services can be published through the supported transport mechanisms. More specifically, a custom or document service’s operations can be published synchronously (for example, by using the Net.tcp or HTTP protocol) through basic integration ports, as shown in the previous examples, or they can be published asynchronously (for example, by using the file system adapter or Message Queuing) through enhanced integration ports. Administrators can select various options to configure how service operations are bundled and published at run time and to configure logging, among other things. For more information about publishing services through enhanced integration ports, see the services and AIF documentation for AX 2012 on TechNet (http://technet.microsoft.com/en-us/library/gg731810.aspx).

When AX 2012 services are consumed synchronously, generated service proxies usually take care of producing and consuming the XML that is exchanged between the client application and AX 2012. However, AX 2012 services are consumed through asynchronous transports; you need to make sure that the request messages comply with the XML schema definitions for the AIF message envelope and the business document as expected by the AX 2012 service framework. For more information about how to get the XML schema definitions (XSDs) for message envelopes, see the “AIF Messages” section in the AX 2012 SDK (http://msdn.microsoft.com/en-us/library/aa627117.aspx).

The following code example shows a sample XML message that can be sent asynchronously from a client application to AX 2012 to consume the service operation MyService.HelloWorld(MyParam in) of a custom service that was discussed in a previous example (see the “Custom services” section earlier in this chapter). It illustrates how the service name, the service operation name, and the structure of the input parameters map to the corresponding elements of the XML request message. It also shows how you can specify the context in which the request is executed: through the Header element, which recognizes the same properties the CallContext knows in the case of synchronous service interfaces.

<?xml version="1.0" encoding="UTF-8"?>
<Envelope
    xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
  <Header>
    <!-- Service operation: "MyService.HelloWorld(MyParam)" -->
    <Company>CEU</Company>
    <Action>http://tempuri.org/MyService/HelloWorld</Action>
  </Header>
  <Body>
    <MessageParts
        xmlns="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">

      <!-- Complex input parameter: "MyParam in" -->
      <in xmlns="http://tempuri.org"
          xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:b="http://schemas.datacontract.org/2004/07/Dynamics.Ax.Application">

        <!—Property of complex input parameter: "in.b" -->
        <b:intParm>0</b:intParm>
      </in>
    </MessageParts>
  </Body>
</Envelope>


Image Note

To run this example, you need to create an enhanced integration port that is configured to receive files asynchronously. That integration port must publish the service operation MyService.HelloWorld.


So far, this chapter has discussed how AX 2012 functionality can be published through services for consumption by external client applications and how external client applications can consume these services. But what if you want to send unsolicited data out of AX 2012? The following section discusses how to use the AX 2012 send framework to send unsolicited data asynchronously.

The AX 2012 send framework

AIF provides APIs and infrastructure for using AX 2012 services to send unsolicited one-way messages. The AX 2012 client has features like the Send Electronically button on several forms that allow users to transmit business documents (such as invoices) as unsolicited one-way messages through outbound integration ports. For information about how to configure outbound integration ports, see the services and AIF documentation for AX 2012 on TechNet (http://technet.microsoft.com/en-us/library/gg731810.aspx).

AX 2012 doesn’t rely on 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 AX 2012 services.

Implementing unsolicited one-way messages requires the following two steps:

1. Implement a trigger for transmission (design time).

2. Configure an enhanced outbound integration port for sending documents (administration 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 features a set of methods that can be used to send unsolicited one-way messages from AX 2012 by means of integration ports through which the consumers can pick up the messages. This API sends a single message; the body of the message contains the XML that is generated by invoking the read service operation of the AIF document service referenced by the 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
)

By using the two optional parameters processingMode and conversationId in the preceding signature, you can take advantage of the parallel message processing feature for asynchronous adapters:

Image 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).

Image conversationId If this is specified, AIF moves the message 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 other messages with different conversationIds isn’t guaranteed.

AxdSend API

The AxdSend API provides functionality to send unsolicited one-way messages. The user selects the outbound integration port through which the documents are sent at run time. If more than one document needs to be sent, the user also selects the exact set of entities at run time. This feature has been implemented for several AX 2012 document services, such as AxdPricelist and AxdBillsOfMaterials.

The AxdSend framework provides default dialog boxes for selecting integration ports and entity ranges and allows the generation of XML documents with multiple records. You can use the framework to provide specific dialog boxes for documents that require more user input than the default dialog box provides.

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

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

An example dialog box for the AxdSend framework is shown in Figure 12-3.

Image

FIGURE 12-3 The Send Document Electronically dialog box for bills of materials.

If an Axd<Document> requires a more specific dialog box, you 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 just add one line of code to implement parmShowDocPurpose from the AxdSend class and to make this field appear on the dialog box:

static public void main(Args args)
{
   AxdSendBillsOfMaterials axdSendBillsOfMaterials;
   AifConstraintList       aifConstraintList;
   AifConstraint           aifConstraint;
   BOMVersion              bomVersionRecord;

   axdSendBillsOfMaterials = new  AxdSendBillsOfMaterials();
   aifConstraintList       = new AifConstraintList();
   aifConstraint           = new AifConstraint();

   aifConstraint.parmType(AifConstraintType::NoConstraint);
   aifConstraintList.addConstraint(aifConstraint);

   if (args && args.record().TableId == tablenum(BOMVersion))
   {
       bomVersionRecord = args.record();
       axdSendBillsOfMaterials.parmBOMVersion(bomVersionRecord);
   }

   // added line to make the field appear on the dialog box
   axdSendBillsOfMaterials.parmShowDocPurpose(true) ;

   axdSendBillsOfMaterials.sendMultipleDocuments(
      classnum(BomBillsofMaterials),
      classnum(BomBillsofMaterialsService),
      AifSendMode::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. Because of this need for matching, the AxdSend class enforces these sorting and structure limitations. The query dialog box shows only the fields in the top-level tables because of the mechanics of queries with an outer join predicate. The result set will likely be different from what a user would expect. 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 find operation.


Image Note

For details about configuring enhanced outbound integration ports and other administrative features related to sending unsolicited messages asynchronously by using the AX 2012 send framework, see the services and AIF documentation for AX 2012 on TechNet (http://technet.microsoft.com/en-us/library/gg731810.aspx).


Consuming external web services from AX 2012

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, and productivity applications such as Office.

Integrating applications with third-party web services over the Internet has also become viable and in many cases is the preferred approach for 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.

Similar to sending unsolicited data asynchronously by using the AX 2012 send framework, you can customize AX 2012 to send requests to external web services—in other words, to consume external web services. Because consuming external web services implies a tight coupling with the respective web service (and usually involves a service proxy for the web service), and because Visual Studio provides a rich set of tools for building such integrations, you should create a Visual Studio project and build a .NET dynamic-link library (DLL) that contains the code to consume the external web service. You can then add this library as a reference to AX 2012 and write X++ code that calls methods exposed by this .NET library.


Image Note

The Microsoft Dynamics AX service framework does not provide any tools specific to writing code to consume external web services. The concept of service references as it existed in AX 2009 has been removed from AX 2012, and the related AOT node no longer exists.


Performance considerations

To meet performance requirements for a specific AX 2012 implementation scenario, planning for and sizing the hardware infrastructure is critical. For guidance on how to size your deployment properly, see the Microsoft Dynamics AX Implementation Planning Guide at http://www.microsoft.com/en-us/download/details.aspx?id=4007.

By default, integration ports process all request messages in sequence. This is true for both incoming and outgoing request messages. To increase the number of request messages that can be processed, you can use the AIF parallel processing capabilities in combination with additional AOS instances. For more information about how to configure inbound ports for parallelism and how to use extensions to the AIF Send API, see the “Services and AIF operations” section of the AX 2012 system administrator documentation on TechNet (http://technet.microsoft.com/en-us/library/gg731830.aspx).

Note that for synchronous WCF services, 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
18.227.111.33