Intent: Receive data in json format, from diferent web sources, returning diferent list of data, and deserializing it.
Almost sure this is a newbie C# question :( No experience with derived classes ... Maybe i'm trying an impossible data manipulation ...
1 - Created an abstract Data class with and abstract index (to access data via named string). Then created 2 derived classes with the fields from each source. No problem so far.
public abstract class Data
{
public abstract object this[string index] { get; set; }
}
public class Type1 : Data
{
public DateTime DATA_COTA { get; set; }
public string MOEDABASE { get; set; }
public override object this[string index]
{
get
{
switch (index.Substring(1))
{
case "DATA_COTA":
return DATA_COTA;
case "MOEDABASE":
return MOEDABASE;
default:
throw new InvalidOperationException($"campo {index} inválido");
}
}
set
{
;
}
}
}
public class Type2 : Data
{
public string MOEDA { get; set; }
public decimal VALFIX { get; set; }
public override object this[string index]
{
get
{
switch (index.Substring(1))
{
case "MOEDA":
return MOEDA;
case "VALFIX":
return VALFIX;
default:
throw new InvalidOperationException($"campo {index} inválido");
}
}
set
{
;
}
}
}
2 - Create an abstract Root class with a common string field (odatacontext) and a list of fields returned from each site. As i dont´mention each type in each class definition, i supose it will never work. I've tried so many variation/tricks, but this is the only version that compiles, but doesn't work :(
public abstract class Root
{
[JsonProperty("@odata.context")]
public string odatacontext { get; set; }
public abstract List<Data> value { get; set; }
}
public class RootType1 : Root
{
public override List<Data> value
{
get
{
return this.value;
}
set
{
//List<Type1> value = value.Select(s => (Type1)s).ToList();
this.value = value;
}
}
}
public class RootType2 : Root
{
public override List<Data> value
{
get
{
return this.value;
}
set
{
//List<Type2> value = value.Select(s => (Type2)s).ToList();
this.value = value;
}
}
}
3 - Finally the code ... getting a stack overflow when refering to obj.value
using (HttpClient httpClient = new HttpClient())
{
HttpResponseMessage httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
string json = httpResponseMessage.Content.ReadAsStringAsync().Result;
if (!httpResponseMessage.IsSuccessStatusCode)
throw new InvalidOperationException(json);
Root obj;
switch (name)
{
case "Type1":
obj = JsonConvert.DeserializeObject<RootType1>(json);
break;
case "Type2":
obj = JsonConvert.DeserializeObject<RootType2>(json);
break;
default:
throw new InvalidOperationException($"{name} não previsto");
}
foreach (var item in **obj.value**)
{
foreach (SqlParameter param in cmdUPD.Parameters)
{
string paramName = param.ParameterName;
if (name != "@RETURN_VALUE")
cmdUPD.Parameters[paramName].Value = item[paramName];
}
cmdUPD.ExecuteNonQuery();
}
}
As i've been asked for the json ... then i've to send "the real thing" ... I'm sending the actual solution (1 and 2 ... working, but with duplicated code) ... then the json streams ... and then the intended solution (4 and 5). I'm not showing the derived classes (or any other solution), because i dont know how :( The intent is to have ALL (i've several) the classes Root* to be derived from a Root class, and a indistinct piece of code, only changing the json deserialization.
1 - the ACTUAL classes definition
public abstract class Data
{
public abstract object this[string index] { get; set; }
}
public class Câmbios : Data
{
public int SGC_ID { get; set; }
public DateTime DtCâmbio { get; set; }
public string MdaBase { get; set; }
public string Mda { get; set; }
public decimal Fixing { get; set; }
public override object this[string index]
{
get
{
switch (index.Substring(1))
{
case "DtCâmbio":
return DtCâmbio;
case "MdaBase":
return MdaBase;
case "Mda":
return Mda;
case "Fixing":
return Fixing;
default:
throw new InvalidOperationException($"campo {index} inválido");
}
}
set
{
;
}
}
}
public class RootCâmbios
{
[JsonProperty("@odata.context")]
public string odatacontext { get; set; }
public List<Câmbios> value { get; set; }
}
public class Índice : Data
{
public int SGC_ID { get; set; }
public string Indexante { get; set; }
public DateTime Data { get; set; }
public decimal Valor { get; set; }
public string OmitirLista { get; set; }
public override object this[string index]
{
get
{
switch (index.Substring(1))
{
case "Indexante":
return Indexante;
case "Data":
return Data;
case "Valor":
return Valor;
case "OmitirLista":
return OmitirLista;
default:
throw new InvalidOperationException($"campo {index} inválido");
}
}
set
{
;
}
}
}
public class RootÍndices
{
[JsonProperty("@odata.context")]
public string odatacontext { get; set; }
public List<Índice> value { get; set; }
}
2 - the ACTUAL program (duplication :()
switch (name)
{
case "Câmbios":
//RESOLVER ... analisar se há forma de consumir o registo no caso do odatacontext ser null ... ler Root ???
//Root obj = JsonConvert.DeserializeObject<RootCâmbios>(json);
RootCâmbios objCâmbios = JsonConvert.DeserializeObject<RootCâmbios>(json);
if (!objCâmbios.odatacontext.StartsWith($"{urlBase}/$metadata#{SGC_name}"))
throw new InvalidOperationException("falha na validação do contexto");
foreach (Data item in objCâmbios.value)
{
foreach (SqlParameter param in cmdINS.Parameters)
{
string paramName = param.ParameterName;
if (!(param.ParameterName == "@RETURN_VALUE" || param.ParameterName == "@EXEC_Dia"))
cmdINS.Parameters[paramName].Value = item[paramName];
}
cmdINS.ExecuteNonQuery();
}
break;
case "Índices":
RootÍndices objÍndices = JsonConvert.DeserializeObject<RootÍndices>(json);
if (objÍndices.odatacontext != null)
{
if (!objÍndices.odatacontext.StartsWith($"{urlBase}/$metadata#{SGC_name}"))
throw new InvalidOperationException("falha na validação do contexto");
foreach (Data item in objÍndices.value)
{
foreach (SqlParameter param in cmdINS.Parameters)
{
string paramName = param.ParameterName;
if (!(param.ParameterName == "@RETURN_VALUE" || param.ParameterName == "@EXEC_Dia"))
cmdINS.Parameters[paramName].Value = item[paramName];
}
cmdINS.ExecuteNonQuery();
}
}
break;
default:
throw new InvalidOperationException($"{name} não previsto");
}
3 - json data
Câmbios {"@odata.context":"http://gasgc.montepio.com/odatacustom/maintenancedata/$metadata#fixingrates#9ee42a020a03ff123ae687ecfc1ce91ee9e2768e0a1274c518516e62c66fcc175b8adda21cf69cd59a70afcc8a08c334cda15b00f1c78239c8e1430f5f363da3","value":[{"fixingrates_ID":1,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"USD","Mda":"EUR","Fixing":1.075100000000000},{"fixingrates_ID":2,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"GBP","Mda":"EUR","Fixing":0.868130000000000},{"fixingrates_ID":3,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"JPY","Mda":"EUR","Fixing":150.240000000000000},{"fixingrates_ID":4,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"SEK","Mda":"EUR","Fixing":11.528000000000000},{"fixingrates_ID":5,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"CHF","Mda":"EUR","Fixing":0.970700000000000},{"fixingrates_ID":6,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"NOK","Mda":"EUR","Fixing":11.821800000000000},{"fixingrates_ID":7,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"DKK","Mda":"EUR","Fixing":7.448900000000000},{"fixingrates_ID":8,"DtC\u00e2mbio":"2023-05-26T00:00:00+01:00","MdaBase":"BRL","Mda":"EUR","Fixing":5.387800000000000}]}
Índices {"@odata.context":"http://gasgc.montepio.com/odatacustom/maintenancedata/$metadata#interestindexvalues#8f2b6731ceade8d332dec84a53057e906a421270f07a52de17d3fc5e1160c1700c454af1437737f8e674fd151e4df4ad57da7ea78a66d81aa54177609cb7fd77","value":[{"interestindexvalues_ID":1,"Indexante":"77","Data":"2023-05-25T00:00:00+01:00","Valor":3.45700000,"OmitirLista":"N"}]}
4 - the intended Root base class
public abstract class Root
{
[JsonProperty("@odata.context")]
public string odatacontext { get; set; }
public abstract List<Data> value { get; set; }
}
5 - the intended code
Root obj;
switch (name)
{
case "Câmbios":
obj = JsonConvert.DeserializeObject<RootCâmbios>(json);
break;
case "Índices":
obj = JsonConvert.DeserializeObject<RootÍndices>(json);
break;
default:
throw new InvalidOperationException($"{name} não previsto");
}
if (!obj.odatacontext.StartsWith($"{urlBase}/$metadata#{SGC_name}"))
throw new InvalidOperationException("falha na validação do contexto");
foreach (Data item in obj.value)
{
foreach (SqlParameter param in cmdINS.Parameters)
{
string paramName = param.ParameterName;
if (!(param.ParameterName == "@RETURN_VALUE" || param.ParameterName == "@EXEC_Dia"))
cmdINS.Parameters[paramName].Value = item[paramName];
}
cmdINS.ExecuteNonQuery();
}