2

ユーザーを公開するWebAPIがあります。

各ユーザーには、ユーザーでもあるマネージャーがいます。

私のEDMXには、「user」エンティティに自己1 .. *ナビゲーションプロパティがあります。これは、マネージャーからユーザーへのナビゲーション用の「コラボレーター」であり、ユーザーからマネージャーへのナビゲーション用の「マネージャー」です。

私のJSONAPIは、NewtonJSONを使用してエンティティをシリアル化します。

API呼び出しのJSON結果をカスタマイズするために、クエリ文字列にキーワード「fields」を実装しました。「フィールド」を使用すると、ユーザーの部分的なJSON表現を取得できるようになります。

呼び出しは次のようになります:/ api / users?fields = id、name、department、picture

そして、完全なC#ユーザーオブジェクトから、id、name、department、およびpictureプロパティのみを含むJSONを取得します。

IContractResolverのカスタム実装を使用してこれを達成しました。

問題は、NewtonJSONコントラクトリゾルバーが「オブジェクトごと」ではなく「タイプごと」に機能することです。つまり、宣言型のそのようなメンバーを別のメンバーではなくシリアル化するようにシリアライザーに指示できますが、それを指示することはできません(私の知る限り、それが私がここで尋ねる理由です)同じタイプのこのオブジェクトのそのようなメンバーをシリアル化し、同じタイプの別のオブジェクトの同じメンバーではありません。

そうは言っても、私の問題は私が尋ねるときです:/ api / users?fields = id、name、manager

次のように、各ユーザーオブジェクトのマネージャーメンバーの再帰的なシリアル化で応答を受け取ります。

[{
    id: 123,
    name: "Foo",
    manager:
    {
        id: 124,
        name: "Foo",
        manager:
        {
            id: 125,
            name: "Foo",
            manager:
            {
            ...
            }
        }
    }
},
{
    id: 124,
    name: "Foo",
    manager:
    {
        id: 125,
        name: "Foo",
        manager:
        {
        ...
        }
    }
},
{
    id: 125,
    name: "Foo",
    manager:
    {
    ...
    }
}]

次のように、部分的なサブエンティティの応答を要求する機能も実装しました。

/api/users?fields=id,name,manager.id

ただし、メインオブジェクト(ここではユーザー)とサブオブジェクト(マネージャー)が両方とも同じタイプであるため、機能していません。

部分応答WebAPIを実装するためにNewtonJSONをすでに使用している人はいますか?埋め込まれた自己タイプエンティティをどのように操作しますか?

アドバイスありがとうございます。

4

1 に答える 1

0

fields パラメーターを理解し、応答を変換するアクション フィルターを作成できます。応答オブジェクトをディクショナリに変換するサンプル実装があります。キーはクライアントが要求したフィールドで、値は応答で返されるオブジェクトのフィールドの値です。実装はサンプルであり、完全に近いわけではありません:)

public class FieldFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var fieldsParameter = actionExecutedContext.Request.GetQueryNameValuePairs().Where(kvp => kvp.Key == "fields");
        if (fieldsParameter.Count() == 1)
        {
            object response;
            object newResponse;

            if (actionExecutedContext.Response.TryGetContentValue(out response))
            {
                string[] fields = fieldsParameter.First().Value.Split(',');

                IEnumerable<object> collection = response as IEnumerable<object>;
                if (collection != null)
                {
                    newResponse = collection.Select(o => SelectFields(fields, o));
                }
                else
                {
                    newResponse = SelectFields(fields, response);
                }

                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, newResponse);
            }
        }
    }

    private static Dictionary<string, object> SelectFields(string[] fields, object value)
    {
        Dictionary<string, object> result = new Dictionary<string, object>();

        foreach (string field in fields)
        {
            result.Add(field, GetValue(field, value));
        }

        return result;
    }

    private static object GetValue(string indexer, object value)
    {
        string[] indexers = indexer.Split('.');

        foreach (string property in indexers)
        {
            PropertyInfo propertyInfo = value.GetType().GetProperty(property);
            if (propertyInfo == null)
            {
                throw new Exception(String.Format("property '{0}' not found on type '{1}'", property, value.GetType()));
            }

            value = propertyInfo.GetValue(value);

            if (value == null)
            {
                return null;
            }
        }

        return value;
    }
}
于 2013-02-08T19:36:30.033 に答える