从C#WCF服务返回具有动态维数的锯齿状数组

时间:2011-04-12 22:27:36

标签: c# wcf json serialization olap

我正在尝试创建一个服务,该服务将在C#/ WCF数据服务中返回OLAP多维数据集查询的结果。我这样做是为了获得对OLAP结果如何序列化,客户端如何进行身份验证/授权以及能够直接从网站中的javascript查询多维数据集的完全编程控制。

OLAP查询的结果可能具有任意数量的维度(实际上在1到5之间)。我遇到的问题是我无法弄清楚如何首先创建一个动态数量的维度的锯齿状数组而不用硬编码处理我可能使用的每个维数。所以第一个任务是:是否有一种优雅的方法来在C#中创建一个动态数量的维度的锯齿状数组?

一旦我有了这个动态维数的数组,就可以使用DataContractJsonSerializer(或任何其他免费提供的json序列化程序)将其序列化为json。目标是将其序列化为对于二维结果看起来像这样的对象:

{
  "DimensionMemberCaptions" = [["Dim1 member1", "Dim2 member2"], ["Dim2 member1"], ["Dim2 member2"]],
  "Data" = [[1, 2],
            [3, 4]],
  "FormatedData = [["1$", "2$"],
                   ["3$", "4$"]]
}

其中DimensionMemberCaptions包含每个维度的标题(OLAP成员名称),data / formateddata是结果表。

我想避免编写自己的序列化函数,但随着时间的推移它似乎更具吸引力 - 使用Array(多维数组而不是锯齿状)并编写我自己的json序列化程序,专门用于序列化OLAP输出到WCF REST方法返回的流。

1 个答案:

答案 0 :(得分:4)

我找到了一种方法来解决我的问题比Adomd更具体,而不是我指定的问题,但我认为可以应用相同的技术来解决这个问题而不依赖于Adomd。我选择使用Newtonsoft的Json序列化库(http://james.newtonking.com/projects/json-net.aspx)。有了这个,我可以创建自己的'JsonConverter'来序列化Adomd CellSet(基本上是来自多维OLAP查询的结果)。无论尺寸数量如何,这都可以。

public class CellSetConverter : JsonConverter
{

    public override bool CanRead
    {
        get
        {
            return false;
        }
    }

    public override bool CanConvert(Type objectType)
    {
        if (objectType == typeof(CellSet))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        CellSet cellSet = (CellSet)value;
        int cellCount = cellSet.Cells.Count;
        int[] axisCounts = new int[cellSet.Axes.Count];
        int[] currentIndex = new int[cellSet.Axes.Count];
        for (int i = 0; i < axisCounts.Length; i++)
        {
            axisCounts[i] = cellSet.Axes[i].Positions.Count;
        }

        for (int i = 0; i < cellSet.Axes.Count; i++)
        {
            writer.WriteStartArray();
        }

        for (int i = 0; i < cellCount; i++)
        {
            serializer.Serialize(writer, cellSet[currentIndex].Value);
            currentIndex = IncrementIndex(writer, currentIndex, axisCounts);
        }
    }

    string[] GetCaptions(CellSet cellSet, int[] index)
    {
        string[] captions = new string[index.Length];
        for (int i = 0; i < index.Length; i++)
        {
            Axis axis = cellSet.Axes[i];
            captions[i] = axis.Positions[index[i]].Members[0].Caption;
        }

        return captions;
    }

    int[] IncrementIndex(JsonWriter writer, int[] index, int[] maxSizes)
    {
        bool incremented = false;
        int currentAxis = 0;
        while (!incremented)
        {
            if (index[currentAxis] + 1 == maxSizes[currentAxis])
            {
                writer.WriteEndArray();
                index[currentAxis] = 0;
                currentAxis++;
            }
            else
            {
                for (int i = 0; i < currentAxis; i++)
                {
                    writer.WriteStartArray();
                }

                index[currentAxis]++;
                incremented = true;
            }

            if (currentAxis == index.Length)
            {
                return null;
            }
        }

        return index;
    }
}

和WCF Rest服务一起使用:

[ServiceContract]
public class MdxService
{
    const string JsonMimeType = "application/json";
    const string connectionString = "[Data Source String]";
    const string mdx = "[MDX query]";

    [OperationContract]
    [WebGet(UriTemplate = "OlapResults?session={session}&sequence={sequence}")]
    public Stream GetResults(string session, string sequence)
    {
        CellSet cellSet;
        using (AdomdConnection connection = new AdomdConnection(connectionString))
        {
            connection.Open();
            AdomdCommand command = connection.CreateCommand();
            command.CommandText = mdx;
            cellSet = command.ExecuteCellSet();
        }

        string result = JsonConvert.SerializeObject(cellSet, new CellSetConverter());
        WebOperationContext.Current.OutgoingResponse.ContentType = JsonMimeType;
        Encoding encoding = Encoding.UTF8;
        byte[] bytes = encoding.GetBytes(result);
        return new MemoryStream(bytes);
    }
}