最新消息:ww12345678 的部落格重装上线,希望大家继续支持。

Dynamics Ax custom WCF service with paging support

网络文摘 Kevin Roos 3811浏览

Hi all,

Lately I’ve been busy developing WCF services to communicate with .NET web applications. All of these web services are custom-made and are using .NET data contracts so that every application uses the same contracts. Due to the high amount of data and performance we had to implement some kind of paging. I had no clue that Ax even has paging support but it does and it does this with properties on the QueryRun objects.

For example purposes I’ve made a service which uses .NET request and response contracts. I prefer this way over X++ data contracts because this is more reusable and flexible on the client side. The code is self-explanatory to me but you can always pose questions of course. ;-)

The request contract:

1
2
3
4
5
6
7
8
9
[DataContract]
public class ItemListRequest
{
    [DataMember]
    public long StartingPosition { get; set; }
 
    [DataMember]
    public long NumberOfRecordsToFetch { get; set; }
}

The response contract:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[DataContract]
[KnownType(typeof(Item))]
public class ItemListResponse
{
    [DataMember]
    public int TotalNumberOfRecords { get; set; }
 
    [DataMember]
    public ArrayList Items { get; set; }
}
 
[DataContract]
public class Item
{
    [DataMember]
    public string Id { get; set; }
 
    [DataMember]
    public string Name { get; set; }
}

The service implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[SysEntryPointAttribute]
public Blog.WCFPaging.DataContracts.ItemListResponse getItems(Blog.WCFPaging.DataContracts.ItemListRequest  _request)
{
    Blog.WCFPaging.DataContracts.Item               item;
    System.Collections.ArrayList                    itemList    = new System.Collections.ArrayList();
    Blog.WCFPaging.DataContracts.ItemListResponse   response    = new Blog.WCFPaging.DataContracts.ItemListResponse();
 
    QueryRun        queryRun    = new QueryRun(queryStr(InventTable));
    InventTable     inventTable;
    ;
 
    if(     CLRInterop::getAnyTypeForObject(_request.get_StartingPosition())        > 0
        &&  CLRInterop::getAnyTypeForObject(_request.get_NumberOfRecordsToFetch())  > 0)
    {
        response.set_TotalNumberOfRecords(QueryRun::getQueryRowCount(queryRun.query(), maxInt()));
 
        queryRun.enablePositionPaging(true);
        queryRun.addPageRange(_request.get_StartingPosition(), _request.get_NumberOfRecordsToFetch());
 
        // At least one order by field should be declared when using paging
        SysQuery::findOrCreateDataSource(queryRun.query(), tableNum(InventTable)).addOrderByField(fieldNum(InventTable, ItemId));
    }
 
    while(queryRun.next())
    {
        inventTable = queryRun.get(tableNum(InventTable));
 
        item        = new Blog.WCFPaging.DataContracts.Item();
        item.set_Id(inventTable.ItemId);
        item.set_Name(inventTable.NameAlias);
        itemList.Add(item);
    }
 
    response.set_Items(itemList);
 
    return response;
}

Calling the service from a .NET application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int pageSize = 10;
 
using (var client = new BLOGPagingServiceClient())
{
    BLOGPagingServiceGetItemsResponse response = null;
 
    var request = new ItemListRequest() { StartingPosition = 1, NumberOfRecordsToFetch = pageSize };
 
    do
    {
        response = client.getItems(new BLOGPagingServiceGetItemsRequest()
        {
            CallContext = new CallContext(),
            _request = request
        });
 
        foreach (Item item in response.response.Items)
        {
            Console.WriteLine(String.Format("{0, -10} - {1}", item.Id, item.Name));
        }
 
        Console.WriteLine("-----");
        request.StartingPosition += pageSize;
    }
    while (response.response.Items.Count > 0);
}

Paging on a QueryRun is implement since Ax 2009, more info on paging: http://msdn.microsoft.com/nl-be/library/aa623755(v=ax.50).aspx

I wonder why this isn’t implemented in the AIF services or is it? If anyone knows please leave a comment about it. ;-)