Вернуть зубчатый массив с динамическим числом измерений из C # WCF Service - PullRequest
1 голос
/ 13 апреля 2011

В настоящее время я пытаюсь создать службу, которая будет возвращать результаты запроса куба OLAP в службе данных C # / WCF.Я делаю это, чтобы получить полный программный контроль над тем, как сериализуются результаты OLAP, как клиенты аутентифицируются / авторизуются, и чтобы можно было напрямую запрашивать кубы из javascript на веб-сайте.

Результаты запросов OLAP могутиметь любое количество измерений (реально где-то от 1 до 5 макс).Проблема, с которой я столкнулся, заключается в том, что я не могу понять, как сначала создать зубчатый массив с динамическим числом измерений без жесткой кодировки обработки каждого числа измерений, которые я, возможно, буду использовать.Итак, первый квест: существует ли элегантный способ создания зубчатого массива с динамическим числом измерений в C #?

Если у меня есть этот массив динамического числа измерений, можно ли затем сериализовать его в json с помощью DataContractJsonSerializer (или любого другого свободно доступного сериализатора 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 в поток, возвращаемый методом REST WCF.

1 Ответ

4 голосов
/ 14 апреля 2011

Я нашел способ решить мою проблему, которая более специфична для Adomd, чем мой вопрос, но я думаю, что тот же метод может быть применен для решения этой проблемы без зависимости от Adomd. Я решил использовать библиотеку Newsonoft Json для сериализации (http://james.newtonking.com/projects/json-net.aspx).. Таким образом, я мог бы создать свой собственный JsonConverter для сериализации набора ячеек Adomd (в основном результаты многомерного запроса 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);
    }
}
...