Creating custom services

In this section, we will discuss two custom services. One service focuses on exposing data from Microsoft Dynamics AX 2012 while the other focuses on exposing business logic.

The Title service

We will use the CVRTitleService service as an example to demonstrate how to create a simple yet powerful service. This service will allow an external program to do the following two things:

  • Retrieve the details of a title based on its ID
  • Retrieve a list of all titles

Creating the Title data contract

Let's start by creating a new class for the data contract that will contain the data for one title. Create a new class and name it CVRTitleContract. In the class declaration, add DataContractAttribute to specify that the class is a data contract. Also, declare the variable's ID, name, and description, as shown in the following code snippet:

[DataContractAttribute('Title')]
public class CVRTitleDataContract
{
    CVRTitleId      id;
    CVRTitleName    name;
    Description     description;
}

Next, add three parameter methods, one for each of the properties of the data contract. Use DataMemberAttribute to indicate that the methods are data contract members, as shown in the following code snippet:

[DataMemberAttribute('Description')]
public Description parmDescription(Description _description = description)
{    
    description = _description;
    return description;
}

[DataMemberAttribute('Id')]
public CVRTitleId parmId(CVRTitleId _id = id)
{
    id = _id;
    return id;
}

[DataMemberAttribute('Name')]
public CVRTitleName parmName(CVRTitleName _name = name)
{
    name = _name;
    return name;
}

As you can see in the preceding code, we construct the attributes using an optional string parameter. This parameter is the name. Because we do that, a client application can get the value of a member using code such as title.Description. If we don't pass a name, the client application would have to use CVRTitleDataContract.parmDescription instead, which doesn't look as neat. It's better to not expose the prefixes and other naming conventions that are specific to Microsoft Dynamics AX such as the DataContract suffix and parm prefix.

Essentially, you now have a functional data contract. However, there are a few tweaks that we can still perform when constructing the data contract. Because our contract is tied to a record of the CVRTitle type, we can create a static new() method that creates an instance of the data contract based on a record of this type. Note that these steps are optional, but performing them has the following main advantages:

  • In Microsoft Dynamics AX 2012, it is impossible to create an instance of the contract in a way other than the one used by the developer who created the intended contract, because both the new() and construct() methods are not publicly available. This way, a developer who creates an instance of the contract is less likely to make mistakes.
  • When creating an instance of the data contract, you will have less coding to do because the contract is filled in the static new() method. This will make your code cleaner and easier to understand.

Start by overriding the new() method and set it as protected so only the CVRTitleDataContract class or one of its subclasses can call the method, shown as follows:

protected void new()
{
}

Always create a construct() method for your classes, but if it doesn't return a valid instance, set it as private. A valid instance means that when constructed, all of the variables needed for execution have to be initialized. Creating an instance of the data contract using the construct() method isn't valid in this case because the properties id, name, and description are not set:

private static CVRTitleDataContract construct()
{
    return new CVRTitleDataContract();
}

Finally, create a static new() method that takes a CVRTitle record as a parameter, uses it to construct an instance of the CVRTitleDataContract class, and returns it:

public static CVRTitleDataContract newFromTableRecord(CVRTitle  _title)
{
    CVRTitleDataContract    contract = CVRTitleDataContract::construct();

    contract.parmId(_title.Id);
    contract.parmName(_title.Name);
    contract.parmDescription(_title.Description);

    return contract;
}

Tip

Best practices

These recommendations are based on the best practices defined by Microsoft at http://msdn.microsoft.com/en-us/library/aa854210.aspx.

So there you go, you have created your first data contract. That wasn't too hard, was it? Now, let's see how we can create a list data contract, which is a little more complex.

Creating the Title list data contract

We will create a list data contract using the data contract that we just created by performing the following steps:

  1. Start by creating a new class and name it CVRTitleListDataContract. Add the DataContractAttribute attribute to it to declare that the class is a data contract and add a list variable that will store a list of titles, shown as follows:
    [DataContractAttribute]
    public class CVRTitleListDataContract
    {
        List titleList;
    }
  2. Next, we add the usual constructers, new() and construct(). Also, don't forget to initialize the list object, shown as follows:
    protected void new()
    {
        titleList = new List(Types::Class);
    }
    
    public static CVRTitleListDataContract construct()
    {
        return new CVRTitleListDataContract();
    }
  3. Next, we have to provide you with a way to add titles to the list. Add a method that takes a title data contract and adds it to the end of the list, as shown in the following code snippet:
    public void addTitleToList(CVRTitleDataContract _titleDataContract)
    {
        titleList.addEnd(_titleDataContract);
    }
  4. Finally, we add the data member method that will return a list of titles. Add the DataMemberAttribute attribute as you would for every other data member, but also add two more attributes of the type AifCollectionTypeAttribute, as shown in the following code snippet:
    [DataMemberAttribute
    ,AifCollectionTypeAttribute('return', Types::Class, classstr(CVRTitleDataContract))
    ,AifCollectionTypeAttribute('_titleList', Types::Class, classstr(CVRTitleDataContract))]
    public List parmTitleList(List _titleList = titleList)
    {
        titleList = _titleList;
        return titleList;
    }

As we've discussed previously, the AifCollectionTypeAttribute attribute is used to specify the type of the list, because X++ does not support strongly typed lists. In this case, AifCollectionTypeAttribute takes the following three parameters:

  • The name of the parameter; in this example, _titleList. For the return value, the name is return.
  • The base type of the type, which is Class in this example.
  • The name of the type; in our case, the class name is CVRTitleDataContract.

This concludes the creation of the two contracts that we will need for our service. Now let's see how we can use them.

Creating the Title service class

We will create a service class that has the following two service operations:

  • An operation that returns the details of a title based on its ID
  • An operation that returns all of the titles

First, we create a service class. Create a new class and name it CVRTitleService, as shown in the following code snippet. We do not need to add anything more to the class declaration because a service class declaration does not need an attribute:

public class CVRTitleService
{
}

One thing we have to make sure is that this class runs on the server when it is executed. To do this, right-click on the class, click on Properties, and then set the RunOn property to Server.

Creating the Title service operation

OK, let's create a service operation that retrieves the details of a title based on its ID. Start by creating a new method. You can see the source code of this method in the following snippet. As you can see, we add the SysEntryPointAttribute attribute to specify that the method is a service operation. We add true between brackets when constructing the attribute to specify that the AOS authorization has to be performed when the code runs on the server. This will help you make sure that the user who calls the service operations has the necessary permissions on the tables that the method uses:

[SysEntryPointAttribute(true)]
public CVRTitleDataContract getTitle(CVRTitleId _titleId)
{
    CVRTitleDataContract contract;

    contract = CVRTitleDataContract::newFromTableRecord(CVRTitle::find(_titleId));

    return contract;
}

As you can see, further in the method, we use the _titleId parameter to find the record in the database and construct a new data contract with it. Then, we return the data contract.

Creating the Title list service operation

This service operation will use the list data contract to return a list of all the titles. As you can see in the following code, all titles in the CVRTitle table are traversed. Then, a data contract is constructed and added to the list contract. Finally, a list contract that contains the details of all of the titles is returned:

[SysEntryPointAttribute(true)]
public CVRTitleListDataContract getAllTitles()
{
    CVRTitleListDataContract titleListDataContract = CVRTitleListDataContract::construct();
    CVRTitleDataContract     titleContract;
    CVRTitle                 titleRecord;

    while select titleRecord
    {
        // Convert the record to a data contract
        titleContract = CVRTitleDataContract::newFromTableRecord(titleRecord);

        // Add the title data contract to the list of data contracts
        titleListDataContract.addTitleToList(titleContract);
    }

    return titleListDataContract;
}

Creating the Title service contract

The final thing we have to do before we can deploy our service is define the service contract. To create the service contract, perform the following steps:

  1. Open the AOT by pressing Ctrl + D.
  2. Right-click on the Services node and then click on New Service.
  3. Right-click on the newly created service and then click on Properties.
  4. Change the value of the Name and Class properties to CVRTitleService.
  5. Change the value of the Namespace property to http://schemas.contoso.com/ServiceContracts.
  6. Expand the CVRTitleService node, right-click on Operations, and click on Add Operation.
  7. The Add service operations form pops up. Select the Add field for the getAllTitles and getTitle methods and then click on OK.
  8. Click on the Save All button to save the changes.
..................Content has been hidden....................

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