[英]Convert Class on Json Deserialization
我的應用程序中有一個CoupledType
類, CoupledType
用於更大的UserObject
類型的對象中,該對象的實例通過使用Json.NET進行序列化來保存並存儲在數據庫中。
此類需要大量重構以使其在更多上下文中工作。 它的名稱也不理想,我想將其移至另一個庫。 但是,它仍將擴展相同的基類,並且至關重要的是, 當用戶反序列化保存的工作時,必須轉換原始實例。
當前狀態的類大致如下所示:
namespace FirstLibrary.Objects
{
[DataContract]
public class CoupledType : BaseType
{
[DataMember]
public double CoupledValue { get; set; }
}
}
我想將其轉換為以下類型:
namespace SecondLibrary.Objects
{
[DataContract]
public class DecoupledType : BaseType
{
[DataMember]
GenericContract Contract { get; set; }
}
}
上面提到的GenericContract
類看起來像這樣:
[DataContract]
public class GenericContract
{
[DataMember]
public ContractType ContractType { get; set; }
[DataMember]
public double ContractValue { get; set; }
}
在轉換過程中,我想創建一個新的GenericContract
對象,得到了ContractType
從其他地方(其值將始終是相同的,在這個轉換)和ContractValue
將被設置為原來的值CoupledValue
從CoupledType
。
可能更棘手的部分是我需要訪問該對象的父UserObject
(即要從其反序列化的對象)以獲取對ContractType
值的引用。
總而言之,我需要為Json.NET編寫一個轉換器,該轉換器執行以下操作:
FirstLibrary.Objects.CoupledType
為SecondLibrary.Objects.DecoupledType
GenericContract Contract
替換double CoupledValue
(其構造需要訪問ParentObject
此CoupledType
實例是/反序列化的成員)。 我在Json中轉換類型沒有很多經驗(已經編寫了Json.Net
的JsonConverter
的子類來將多個double
對象轉換為double[]
。我沒有更改類型或屬性名稱的經驗。如果任何人至少可以指出我一個潛在的解決方案,將不勝感激。
現有樣本 (推測性的,在BSON中實際序列化)
{
"$type": "FirstLibrary.Objects.CoupledType",
"CoupledValue": 4
}
{
"$type": "SecondLibrary.Objects.DecoupledType",
"Contract": {
"$type": "SecondLibrary.Objects.GenericContract",
"ContractType": {/*Refers to an object serialized elsewhere*/},
"ContractValue": 4
}
}
如果有幫助,序列化設置如下:
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
TypeNameHandling = TypeNameHandling.All
我不確定這些方法是否不能滿足某些未說的要求,但是我可以想到一些可能的方法,這些方法可以將DecoupledType
從電線連接到控制器中。
您可以創建一個自定義HttpParameterBinding
,然后在HttpParameterBinding
執行映射。 輸入的參數信息存儲在HttpParameterDescriptor
,您可以查詢參數以確定特定綁定是否適用。
public class GenericContractBinding : HttpParameterBinding
{
public GenericContractBinding(HttpParameterDescriptor descriptor) : base(descriptor){}
public override Task ExecuteBindingAsync(ModelMetadataProvider provider, HttpActionContext context, CancellationToken cancellationToken)
{
if(context.ControllerContext.Configuration.DependencyResolver != null)
{
//This is a naive eval based only on the incoming type. You'll likely want to map
var bazinga = context.Request.GetDependencyScope().GetService(Descriptor.ParameterType);
if(bazinga.GetType() == typeof(GenericContract)
context.ActionArguments[Descriptor.ParameterName] = bazinga;
}
}
}
另外,您還可以創建一個自定義Web API ModelBinder
並用ModelBinderAttribute
裝飾您的類型(或在route方法上顯式聲明綁定程序提供程序)
public class DecoupledTypeModelBinder : IModelBinder
{
public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext)
{
//I'm assuming your JSON is being sent in the content of the request
string content = actionContext.Request.Content.ReadAsStringAsync().Result;
var json = JArray.Parse(content); //you really should switch to "array by default" processing;the number of items in it is an implementation detail.
//In my opinion, this "ContractTypeService" gets injected at CompositionRoot, which would be in the IHttpControllerActivator
var contractType = actionContext.RequestContext.Configuration.DependencyResolver.GetService(typeof(ContractTypeService)).GetAmbientContractType();
List<GenericContract> contracts = new List<GenericContract>();
foreach(var item in json.Children<JObject>())
{
var contract = new GenericContract();
contract.ContractValue = (double)item["ContractValue"].Value<JToken>();
contract.ContractType = contractType;
contracts.Add(contract);
}
}
//YMMV; You could enforce a hard requirement here for singularity or do something else if multiples are inbound on the wire
DecoupledType model = new DecoupledType()
{
Contract = contracts.Single()
};
bindingContext.Model = model;
}
}
public class DecoupledTypeModelBinderProvider : ModelBinderProvider
{
public override IModelBinder GetBinder(System.Web.Http.HttpConfiguration configuration, Type modelType)
{
return new DecoupledTypeModelBinder();
}
}
...(in your controller)
public dynamic Post([ModelBinder(typeof(DecoupledTypeModelBinderProvider))]DecoupledType bazinga)
{
var contract = bazinga.Contract;
var contractType = contract.ContractType;
var contractValue = contract.ContractValue;
}
希望這能使您走上成功之路。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.