8

既存の JSON API をハッキーな MVC3 実装から最新の MVC4 Web Api に変換することを検討しています。MVC3 の実装では、JSON.NET を使用してすべてのシリアル化を行うため、アップグレードがスムーズに行われます。

アクションの結果をシリアル化する方法をカスタマイズすることに行き詰まっています。たとえば、出力されたオブジェクトのいくつかのプロパティのみを返すアクションもあれば、かなり深いシリアル化を行うアクションもあります。私の現在の実装では、HttpContext. これらは、 から派生したクラスを介してカスタム シリアル化のために後で取得されJsonResultます。カスタムを追加する主な用途は、JsonConvertersシリアル化されるキー/値の数を制御および削減し、アクションに応じてシリアル化するパラメーターを変更することです (特定のアクションは、他のアクションよりも多くのオブジェクト パラメーターを返す必要があります)。

現在の MVC3 実装で json シリアル化を制御するコントローラーとクラスの要約例:

public class TestController : JsonController {
    public JsonResult Persons() {
        ControllerContext.HttpContext.Items[typeof(IEnumerable<JsonConverter>)] = new JsonConverter[] {
            new InterfaceExtractorJsonConverter<IPersonForList>(),
            new StringEnumConverter()
        };

        ControllerContext.HttpContext.Items[typeof(IContractResolver)] = new SpecialCamelCasePropertyNamesContractResolver();
     }
}

public class JsonNetResult : JsonResult {
    public override void ExecuteResult(ControllerContext context) {
        var response = context.HttpContext.Response;

        var additionalConverters = context.HttpContext.Items[typeof(IEnumerable<JsonConverter>)] as IEnumerable<JsonConverter> ?? Enumerable.Empty<JsonConverter>();

        var contractResolver = context.HttpContext.Items[typeof(IContractResolver)] as IContractResolver ?? new JsonContractResolver();

        var typeNameHandling = TypeNameHandling.None;
        if (context.HttpContext.Items.Contains(typeof(TypeNameHandling)))
            typeNameHandling = (TypeNameHandling)context.HttpContext.Items[typeof(TypeNameHandling)];

        response.Write(JsonConvert.SerializeObject(Data, Formatting.Indented, new JsonSerializerSettings {
            ContractResolver = contractResolver,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            Converters = additionalConverters,
            TypeNameHandling = typeNameHandling
        }));
    }
}

Web Api では、構成から Json フォーマッターを取得し、シリアライゼーションをグローバルに変更できることがわかりました。

var config = new HttpSelfHostConfiguration("http://localhost:8080");

var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().Single();

jsonFormatter.SerializerSettings.ContractResolver = new SpecialCamelCasePropertyNamesContractResolver();
jsonFormatter.SerializerSettings.Converters = new[] { new InterfaceExtractorJsonConverter<ITesting>() };

ただし、使用する属性をいくつか追加して、個別に (またはコントローラーごとに) アクションのシリアル化を制御することを計画していましたJsonConverter's。したがって、Jsonシリアライザーが、呼び出されたアクション/コントローラーに与えられた関連する属性を見つけ、それに応じてシリアライゼーションを変更することを望みます。どこでどのようにこれを行うのかわかりません。何らかの方法で継承しJsonMediaTypeFormatter、そこで作業を行う必要がありますか? 他にどのようなオプションがありますか?

4

1 に答える 1

2

そのような方法でシリアライゼーションを制御したい人を見たことがありません。ただし、最小限のやり直しで目標を達成するには、メソッドからすべての情報を直接返します。

class JsonNetResponse {
    public IContractResolver ContractResolver { get;set; }
    // Other Json.Net bits
    public object Value { get; set; }
}

次に、これらのオブジェクトを処理できるカスタム Formatter を作成します。

class JsonNetFormatter : MediaTypeFormatter {
    public override bool CanWriteType(Type t) {
        return typeof(JsonNetResponse).IsAssignableFrom(t);
    }
    // TODO WriteToStreamAsync which is basically a copy of your original JsonNetResult
}
于 2012-08-14T09:50:18.987 に答える