从c# WCF服务返回一个具有动态维数的锯齿数组

本文关键字:动态 数组 一个 服务 WCF 返回 | 更新日期: 2023-09-27 17:50:14

我目前正在尝试创建一个服务,它将在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是结果表。

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

从c# WCF服务返回一个具有动态维数的锯齿数组

我找到了一种方法来解决我的问题,它比我的问题指定的更特定于addom,但我认为同样的技术可以应用于解决这个问题,而不依赖于addom。我选择使用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);
    }
}