2012-08-01 61 views
6

我正在寻找将现有的JSON API从hacky MVC3实现转换为最新的MVC4 Web Api。 MVC3实现使用JSON.NET来完成所有序列化操作,这将使升级更加流畅。自定义ASP Web API通过其调用Action的Json序列化

我被困在定制某些动作的结果如何被序列化。例如,我想要一些操作只返回输出对象的一些属性,而其他操作可能会做很深的序列化。在我目前的实现中,一个动作可以通过在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 
     })); 
    } 
} 

在网页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继承,并在那里做某些工作?我还有什么其他选择?

回答

2

我从来没有见过任何人想以这种方式控制序列化。但要实现与返工的最小量你的目标,我将返回所有这些信息从你的方法是直接:

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

我会再创建一个自定义格式不是能够处理这些对象:

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 
}