How to change element name 'ArrayOfResponse' in Soap XML WCF services - c#

My problem How to change The ArrayOfResponse Element in SOAP XML WCF services
using Message class.... see image I want change the element in red box ....
any ideas ???
enter image description here
that my code to get this result !
my interface
[ServiceContract()]
public interface IEvaluationWebService
{
[OperationContract(ReplyAction = "Evaluations")]
Message GetEvaluations(EvaluationRequest evaluationRequest);
}
this method tasks one parameter EvaluationRequest class ,to return Message ( List of Evaluation class )
Message IEvaluationWebService.GetEvaluations(EvaluationRequest evaluationRequest)
{
SqlConnection cnn = new SqlConnection("");
DateTime dtstart = new DateTime();
DateTime.TryParseExact(evaluationRequest.PeriodStart, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out dtstart);
evaluationRequest.PeriodStart = dtstart.ToString("yyyy-MM-dd");
DateTime dtend = new DateTime();
DateTime.TryParseExact(evaluationRequest.PeriodEnd, "dd/MM/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault, out dtend);
evaluationRequest.PeriodEnd = dtend.ToString("yyyy-MM-dd");
SqlCommand cmd = new SqlCommand("GetEmployeeEvaluation", cnn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#PeriodStart", SqlDbType.VarChar, 10).Value = evaluationRequest.PeriodStart;
cmd.Parameters.Add("#PeriodEnd", SqlDbType.VarChar, 10).Value = evaluationRequest.PeriodEnd;
cnn.Open();
SqlDataReader sdr = cmd.ExecuteReader();
List<Evaluation> evaluationList = new List<Evaluation>();
MessageVersion ver = OperationContext.Current.IncomingMessageVersion;
while (sdr.Read())
{
Evaluation evaluation = new Evaluation();
evaluation.EstLaborOfficeId = Convert.ToInt32(sdr["EstLaborOfficeId"].ToString());
evaluation.EstSequenceNumber = Convert.ToInt32(sdr["EstSequenceNumber"].ToString());
evaluation.IdNumber =
evaluationList.Add(evaluation);
}
Evaluation eval = new Evaluation();
cnn.Close();
return Message.CreateMessage(ver, "Evaluations", evaluationList);
}
The request class to passing the dates for method and gets data ....
[MessageContract(IsWrapped = true, WrapperName = "GetEvaluation", WrapperNamespace = "http://tempuri.org/")]
[XmlType(Namespace = "http://tempuri.org/")]
public class EvaluationRequest
{
[MessageBodyMember(Order = 1)]
public string PeriodStart { get; set; }
[MessageBodyMember(Order = 2)]
public string PeriodEnd { get; set; }
}
request class(the parameters for GetEvaluations method )
[MessageContract(IsWrapped = true, WrapperName = "GetEvaluation", WrapperNamespace = "http://tempuri.org/")]
[XmlType(Namespace = "http://tempuri.org/")]
public class EvaluationRequest
{
[MessageBodyMember(Order = 1)]
public string PeriodStart { get; set; }
[MessageBodyMember(Order = 2)]
public string PeriodEnd { get; set; }
}
Evaluation class
[DataContract()]
public class Evaluation
{
private int _EstLaborOfficeId;
private int _EstSequenceNumber;
private long _IdNumber;
[DataMember]
public int EstLaborOfficeId
{
get { return _EstLaborOfficeId; }
set { _EstLaborOfficeId = value; }
}
[DataMember(Order = 2)]
public int EstSequenceNumber
{
get { return _EstSequenceNumber; }
set { _EstSequenceNumber = value; }
}
}

Anyone, who wants to consume your service, does not know what kind of result he will reveice. It is just "Message" and has not specific MessageContract.
As far as I can see from here, you want to give back a list of Evaluation.
What you could try is this: (Untested)
[MessageContract]
public class Evaluation
{
private int _EstLaborOfficeId;
private int _EstSequenceNumber;
private long _IdNumber;
[MessageBodyMember]
public int EstLaborOfficeId
{
get { return _EstLaborOfficeId; }
set { _EstLaborOfficeId = value; }
}
[MessageBodyMember]
public int EstSequenceNumber
{
get { return _EstSequenceNumber; }
set { _EstSequenceNumber = value; }
}
}
[MessageContract]
public class EvaluationList
{
[MessageBodyMember]
public List<Evaluation> Values {get;set}
}
[ServiceContract()]
public interface IEvaluationWebService
{
[OperationContract]
EvaluationList GetEvaluations(EvaluationRequest evaluationRequest);
}
...or just try use List as return and forget EvaluationList.
[ServiceContract()]
public interface IEvaluationWebService
{
[OperationContract]
List<Evaluation> GetEvaluations(EvaluationRequest evaluationRequest);
}
Now, EvaluationList and EvaluationRequest are both MessageContracts.
Please keep in mind, that you ONLY want to use MessageContract, if you want full control of the SOAP Message. This does not seem to be the case here.
So, the more easy way would be, to change your EvaluationRequest back to DataContract:
[DataContract()]
public class Evaluation
{
private int _EstLaborOfficeId;
private int _EstSequenceNumber;
private long _IdNumber;
[DataMember]
public int EstLaborOfficeId
{
get { return _EstLaborOfficeId; }
set { _EstLaborOfficeId = value; }
}
[DataMember(Order = 2)]
public int EstSequenceNumber
{
get { return _EstSequenceNumber; }
set { _EstSequenceNumber = value; }
}
}
[DataContract]
public class EvaluationRequest
{
[DataMember]
public string PeriodStart { get; set; }
[DataMember]
public string PeriodEnd { get; set; }
}
[ServiceContract()]
public interface IEvaluationWebService
{
[OperationContract]
List<Evaluation> GetEvaluations(EvaluationRequest evaluationRequest);
}
The GOLDEN RULE IS: Try not to mix DataContract and MessageContract in a service operation, because WCF will see this as security flaw.
So define BOTH classes, result AND parameter, as DataContract OR MessageContract, but don't mix it up.

Related

How to return correct values for listview using WCF?

I want to populate listview with information retrieved from database using WCF in C# and am not able to retrieve correct data for listview binding.
public interface IServicePl
{
[OperationContract]
[OperationContract]
IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments();
}
[DataContract]
public class InterventiiCuEchipament
{
[DataMember]
public string EchipamentInterventie { get; set; }
public int id_interventie { get; set; }
public string tip_interventie { get; set; }
public string responsabil { get; set; }
public DateTime data_finalizare { get; set; }
public bool status { get; set; }
}
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments()
{
try
{
IEnumerable<InterventiiCuEchipament> query = from sel1 in dataP.interventiis
join sel2 in dataP.sesizaris
on sel1.id_interventie equals sel2.id_sesizare
select new InterventiiCuEchipament()
{
id_interventie = sel1.id_interventie,
EchipamentInterventie = sel2.echipament,
tip_interventie = sel2.tip_sesizare,
responsabil = sel1.responsabil,
data_finalizare = (DateTime)sel1.data_finalizare,
status = (bool)sel1.status
};
return query;
}
On the client side I have the following code :
if (client.InnerChannel.State != CommunicationState.Faulted)
{
List<InterventiiCuEchipament> ListaInterventii = new List<InterventiiCuEchipament>();
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();
InterventiiList.ItemsSource = ListaInterventii;
InterventiiList.Items.Refresh();
}
Output from query is ok, like in this image
Output for listview binding is like in this image
Why I can see just the count of query? and not correct values returned by query.
If the query returns values, then ListaInterventii should also have values.
I wrote a similar demo, you can compare it.
You can use foreach to see if there is a value.
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();
foreach(var a in ListaInterventii)
{
int A = a.id_interventie;
}
Demo
public class ProductService : IServicePl
{
public IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments()
{
// This comes from database.
var _dbCountries = new List<InterventiiCuEchipament>
{
new InterventiiCuEchipament {id_interventie = 1, tip_interventie="1"},
new InterventiiCuEchipament {id_interventie = 2, tip_interventie="2"},
new InterventiiCuEchipament {id_interventie = 3, tip_interventie="3"},
};
return _dbCountries;
}
}
[ServiceContract]
public interface IServicePl
{
[OperationContract]
IEnumerable<InterventiiCuEchipament> GetInterventiiCuEchipaments();
}
[DataContract]
public class InterventiiCuEchipament
{
[DataMember]
[Key]
public int id_interventie { get; set; }
public string tip_interventie { get; set; }
}
client side
ServicePlClient client = new ServicePlClient();
List<InterventiiCuEchipament> ListaInterventii = new List<InterventiiCuEchipament>();
ListaInterventii = client.GetInterventiiCuEchipamentsAsync().Result.ToList();

Return Object type as Interface C#

I am trying to return Interface as my return type from a method which provides data from two different data source with couple of different column. My implementation goes as below:
Interface:
public interface IBasicDTO
{
int ID { get; set; }
string EstablishmentCode { get; set; }
DateTime? DetailsUpdatedDate { get; set; }
DateTime? PaymentUpdatedDate { get; set; }
UpdateStatus Status { get; set; }
}
BasicDTO abstract class:
public abstract class BasicDTO : IBasicDTO, IModel
{
public int ID { get; set; }
public string EstablishmentCode { get; set; }
public DateTime? DetailsUpdatedDate { get; set; }
public DateTime? PaymentUpdatedDate { get; set; }
public UpdateStatus Status { get; set; }
}
Derived Class CBasicDTO:
public class CBasicDTO : BasicDTO
{
public CBasicDTO() : base() { }
public int? CID { get; set; }
public string UniqueIdentificationNo { get; set; }
}
Derived Class LBasicDTO
public class LBasicDTO : BasicDTO
{
public LBasicDTO() : base() { }
public int? LID { get; set; }
public string LIdentificatonNo { get; set; }
}
Implantation 1 Method:
public IList<IBasicDTO> GetBasicData(int CID_LID, bool IsByLID)
{
SqlParameter parameter = new SqlParameter { ParameterName = "#p_CID", Value = CID_LID };
if (IsByLID)
{
LLDbContext dataContext = new DBContextProvider().GetContext<LLDbContext>();
var data = dataContext.Database.ExecuteProcedure<LBasicDTO>("Read_BasicDetails", parameter);
return (IList<IBasicDTO>) data;
}
else
{
CIDbContext dataContext = new DBContextProvider().GetContext<CIDbContext>();
var data = dataContext.Database.ExecuteProcedure<CBasicDTO>("Read_BasicDetails", parameter);
return (IList<IBasicDTO>)data;
}
}
I am not getting any error at Compile time, but at run-time I am getting bellow error at return (IList<IBasicDTO>)data;
Error:
Unable to cast object of type 'System.Collections.Generic.List 1[NonTableTypes.CBasicDTO]' to type 'System.Collections.Generic.IList1[NonTableTypes.IBasicDTO]'.
If I go with below implementation:
public IList<IBasicDTO> GetBasicData(int CID_LID, bool IsByLID)
{
SqlParameter parameter = new SqlParameter { ParameterName = "#p_CID", Value = CID_LID };
if (IsByLID)
{
LLDbContext dataContext = new DBContextProvider().GetContext<LLDbContext>();
var data = dataContext.Database.ExecuteProcedure<IBasicDTO>("Read_BasicDetails", parameter);
return (IList<IBasicDTO>) data;
}
else
{
CIDbContext dataContext = new DBContextProvider().GetContext<CIDbContext>();
var data = dataContext.Database.ExecuteProcedure<IBasicDTO>("Read_BasicDetails", parameter);
return (IList<IBasicDTO>)data;
}
}
I am getting below error at run-time:
The result type 'NonTableTypes.IEPFBasicDTO' may not be abstract and must include a default constructor.
Merging this data points in single data source is not an option for us as these data source is very large and CBasicDTO is already in production.
Please help me to solve this problem.
You need to cast each of the elements in the collection to the instance type, linq has a .Cast<T>() extension that will help:
public IList<IBasicDTO> GetBasicData(int CID_LID, bool IsByLID)
{
SqlParameter parameter = new SqlParameter { ParameterName = "#p_CID", Value = CID_LID };
if (IsByLID)
{
LLDbContext dataContext = new DBContextProvider().GetContext<LLDbContext>();
var data = dataContext.Database.ExecuteProcedure<LBasicDTO>("Read_BasicDetails", parameter);
return data.ToList().Cast<IBasicDTO>().ToList();
}
else
{
CIDbContext dataContext = new DBContextProvider().GetContext<CIDbContext>();
var data = dataContext.Database.ExecuteProcedure<CBasicDTO>("Read_BasicDetails", parameter);
return data.ToList().Cast<IBasicDTO>().ToList();
}
}
You cannot simply cast the result, because in many implementations the result will be IEnumerable<T> but not an IList<T>
It IS necessary to call data.ToList() to execute the DB query first.
It is NOT necessary to cast to IList<T> as a List<T> already matches that signature
We have to call .ToList() at the end to match the IList<T> return signature.

How to Properly use Custom Class Generics

I am trying to use Custom Generic class and interface.Im having problems to find a solution for the logic and code of my small Project.
THE BLUEPRINT INTERFACE
public interface IDepartment<T>
{
T CreateAndGetValues(SqlDataReader dataReader);
}
THE POSSIBLE DTO
public class Bank<T> : IDepartment<T>
{
public int LfdNr { get; set; }
public string Kennung { get; set; }
public string Name { get; set; }
public string Straße { get; set; }
public string PLZ { get; set; }
public string Ort { get; set; }
public DateTime TSCREATE { get; set; }
public DateTime TSUPDATE { get; set; }
public T CreateAndGetValues(SqlDataReader dataReader)
{
Bank<T> TheReturnObject = new Bank<T>();
ThereturnObject.LfdNr = Convert.ToInt32(dataReader.GetValue(0));
ThereturnObject.Kennung = dataReader.GetValue(1).ToString();
ThereturnObject.Name = dataReader.GetValue(2).ToString();
ThereturnObject.Straße = dataReader.GetValue(3).ToString();
ThereturnObject.PLZ = dataReader.GetValue(4).ToString();
ThereturnObject.Ort = dataReader.GetValue(5).ToString();
ThereturnObject.TSCREATE = DateTime.ParseExact(dataReader.GetValue(6).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
ThereturnObject.TSUPDATE = DateTime.ParseExact(dataReader.GetValue(7).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
return TheReturnObject;
}
}
THE GENERAL DATABASE READER.
public class Mssql<T> where T :class, IDepartment<T>, new()
{
public List<T> ReadTable()
{
string sqlcommand = "Select * from Bank; ";
List<T> TheListofObject = new List<T>();
using (SqlConnection cnn = new SqlConnection(connetionString))
{
cnn.Open();
using (SqlCommand command = new SqlCommand(sqlcommand, cnn))
{
SqlDataReader dataReader;
try
{
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
IDepartment<T> Object = new T();
Object.CreateAndGetValues(dataReader);
TheListofObject.Add(Object);
}
return TheListofObject;
}
catch (Exception ex)
{
throw;
}
dataReader.Close();
}
cnn.Close();
}
}
}
THE MAIN PROGRAM
class Program
{
static void Main(string[] args)
{
Mssql<Bank<T>> TEST = new Mssql<Bank<T>>();
List<Bank<T>> TheList = TEST.ReadTable();
Console.ReadLine();
}
}
I am expecting that i can use a interface with a method where classes can inherit and return a new type of itself with the Type T and to pass the Type. So that the classes are not dependent that much to each other. And code can be reusable. I hope that is not confusing. Thanks
For this task I strongly recommend using an ORM. They are popular and mostly free. Stackoveflow runs on one of them.
Wikipedia's List of object-relational mapping software gives 9 .NET examples as of Oct 2019.
Here is an example from Dapper's doco.
public class Dog
{
public int? Age { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public float? Weight { get; set; }
public int IgnoredProperty { get { return 1; } }
}
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = #Age, Id = #Id", new { Age = (int?)null, Id = guid });
If you add Dapper.Contrib you don't even need to write the query if you want all records.
public class Car
{
public int Id { get; set; } // Works by convention
public string Name { get; set; }
}
(...)
var cars = connection.GetAll<Car>();
Thank You for your time guys.
I have found an answer with out using any tool to my Problem. And I would like to share it.
//THE BLUEPRINT INTERFACE
public interface IDepartment
{
Object GetAndReadValues(SqlDataReader dataReader);
}
// The Possible DTO
public class Bank : IDepartment
{
public int LfdNr { get; set; }
public string Kennung { get; set; }
public string Name { get; set; }
public string Straße { get; set; }
public string PLZ { get; set; }
public string Ort { get; set; }
public DateTime TSCREATE { get; set; }
public DateTime TSUPDATE { get; set; }
public void CreateAndGetValues(SqlDataReader dataReader)
{
}
public Object GetAndReadValues(SqlDataReader dataReader)
{
Bank ThereturnObject = new Bank();
ThereturnObject.LfdNr = Convert.ToInt32(dataReader.GetValue(0));
ThereturnObject.Kennung = dataReader.GetValue(1).ToString();
ThereturnObject.Name = dataReader.GetValue(2).ToString();
ThereturnObject.Straße = dataReader.GetValue(3).ToString();
ThereturnObject.PLZ = dataReader.GetValue(4).ToString();
ThereturnObject.Ort = dataReader.GetValue(5).ToString();
ThereturnObject.TSCREATE = DateTime.ParseExact(dataReader.GetValue(6).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
ThereturnObject.TSUPDATE = DateTime.ParseExact(dataReader.GetValue(7).ToString().Trim(), "dd.MM.yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
return ThereturnObject;
}
//THE GENERAL DATABASE READER.
public class Mssql<T> where T :class, IDepartment, new()
{
public List<T> ReadTable()
{
string sqlcommand = "Select * from Bank; ";
List<T> TheListofObject = new List<T>();
using (SqlConnection cnn = new SqlConnection(connetionString))
{
cnn.Open();
using (SqlCommand command = new SqlCommand(sqlcommand, cnn))
{
SqlDataReader dataReader;
try
{
dataReader = command.ExecuteReader();
while (dataReader.Read())
{
IDepartment Object = new T();
object ReturnObject = Object.GetAndReadValues(dataReader);
TheListofObject.Add((T)ReturnObject);
}
return TheListofObject;
}
//Error handling with th DB must be handeld correctly with the specific error
catch (Exception ex)
{
throw;
}
dataReader.Close();
}
cnn.Close();
}
}
}
//THE MAIN PROGRAM
class Program
{
static void Main(string[] args)
{
Mssql<Bank> TEST = new Mssql<Bank>();
List<Bank> TheList = TEST.ReadTable();
foreach (var item in TheList)
{
Console.WriteLine(item.LfdNr);
Console.WriteLine(item.Kennung);
Console.WriteLine(item.Name);
Console.WriteLine(item.Ort);
Console.WriteLine(item.PLZ);
Console.WriteLine(item.Straße);
Console.WriteLine(item.TSCREATE);
Console.WriteLine(item.TSUPDATE);
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine("");
}
Console.ReadLine();
}
}

Return my object from WCF service.

I have application that host WCF service and I want to return this class object:
namespace classes
{
[DataContract]
public class NetworkAdapter
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string ID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public string IPAddress { get; set; }
[DataMember]
private string gatewayIpAddress;
[DataMember]
public string Speed { get; set; }
[DataMember]
public string NetworkInterfaceType { get; set; }
[DataMember]
public string MacAddress { get; set; }
[DataMember]
private LivePacketDevice livePacketDevice;
[DataMember]
public PacketDevice PacketDevice { get { return livePacketDevice; } }
public NetworkAdapter(LivePacketDevice packetDevice)
{
livePacketDevice = packetDevice;
}
public override string ToString()
{
return Description;
}
public static NetworkAdapter[] getAll()
{
List<NetworkAdapter> list = new List<NetworkAdapter>();
foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
foreach (UnicastIPAddressInformation uniCast in adapter.GetIPProperties().UnicastAddresses)
{
if (!System.Net.IPAddress.IsLoopback(uniCast.Address) && uniCast.Address.AddressFamily != AddressFamily.InterNetworkV6)
{
StringBuilder gatewayIPAddresses = new StringBuilder();
string gatewayIPAddressesDisplay = string.Empty;
foreach (var address in adapter.GetIPProperties().GatewayAddresses)
{
gatewayIPAddresses.Append(address.Address);
gatewayIPAddresses.Append(" ");
}
if (gatewayIPAddresses.Length > 0)
{
gatewayIPAddressesDisplay = gatewayIPAddresses.ToString().TrimEnd(' ');
}
if (!list.Any(l => l.ID == adapter.Id))
{
list.Add(new NetworkAdapter(getDevice(adapter.Id))
{
Name = adapter.Name,
ID = adapter.Id,
Description = adapter.Description,
IPAddress = uniCast.Address.ToString(),
NetworkInterfaceType = adapter.NetworkInterfaceType.ToString(),
Speed = adapter.Speed.ToString("#,##0"),
MacAddress = getMacAddress(adapter.GetPhysicalAddress().ToString()),
gatewayIpAddress = gatewayIPAddressesDisplay
});
}
}
}
//return list.GroupBy(n => n.ID).Select(g => g.FirstOrDefault()).ToArray();
return list.ToArray();
}
private static LivePacketDevice getDevice(string id)
{
return LivePacketDevice.AllLocalMachine.First(x => x.Name.Contains(id));
}
private static string getMacAddress(string oldMAC)
{
int count = 0;
string newMAC = oldMAC;
for (int i = 2; i < oldMAC.Length; i += 2)
{
newMAC = newMAC.Insert(i + count++, ":");
}
return newMAC;
}
public string defaultGateway
{
get
{
if (gatewayIpAddress != "")
{
return gatewayIpAddress;
}
return "n/a";
}
}
private static string getIpFourthSegment(string ipAddress)
{
try
{
string[] arr = ipAddress.Split('.');
return arr[3];
}
catch (Exception)
{
return null;
}
}
}
}
This is my service:
[ServiceContract()]
public interface IService1
{
[OperationContract]
NetworkAdapter[] GetAdapters();
[OperationContract]
string GetDate();
}
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerSession)]
public class service1 : IService1
{
public NetworkAdapter[] GetAdapters()
{
IEnumerable<NetworkAdapter> adapters = NetworkAdapter.getAll();
return adapters.ToArray();
}
public string GetDate()
{
return DateTime.Now.ToString();
}
}
When I am try to run GetAdapters function got this error:
An unhandled exception of type 'System.ServiceModel.CommunicationException' occurred in mscorlib.dll
Additional information: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9599960'.
When try to run GetDate function it works fine and return simple string.
maybe I need to configure my class in other way ? I have added [DataMember] to each member
LivePacketDevice and PacketDevice need to be [DataContract]s, while it might also work if they are just [Serializable]. Otherwise WCF does not know how to transfer them to the client.
Also it is advisable to only transfer objects that just hold data, not functionality, as that functionality will not be available to the client. The stub created on the client side will only contain data fields, not methods, as code is not transferred/cloned.

Parsing JSON into Object

Trying to get the result from a webservice call to return a Model. I eep getting the error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'CI.Models.Schedule' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
public Schedule getCourseSchedule()
{
var obj = new
{
States = new[] { new { State = "MX" } },
Zip = "",
Miles = "",
PaginationStart = 1,
PaginationLimit = 3
};
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "apoplication/json";
var url = "http://192.168.1.198:15014/ShoppingCart2/CourseSchedule";
var json = JsonConvert.SerializeObject(obj);
byte[] data = Encoding.UTF8.GetBytes(json);
byte[] result = client.UploadData(url, data);
string returnjson = Encoding.UTF8.GetString(result);
Schedule sched = JsonConvert.DeserializeObject<Schedule>(returnjson);
return sched;
}
}
Schedule Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Globalization;
namespace CI.Models
{
public class Schedule
{
public IEnumerable<Course> Courses { get; set; }
}
public class Course
{
/*
JSON Data returned from web service:
{
"ProgramGroup":"MR",
"ProgramCode":"RM",
"EventCode":"20160901MXMR",
"FormalDate":"September 1-2, 2016",
"StartDate":"2016\/09\/01",
"Price":5,
"LocName":"WB Hotel",
"LocAddress":"Av. Speedy Gonzales 220",
"LocCity":"Monterrey",
"LocState":"MX",
"LocZipCode":null,
"LicenseeURL":null,
"AgendaURL":"NA",
"SeatsAreAvailable":"2",
"GeneralInfoHTML":"General Info goes here.",
"GateKeeperHTML":null,
"EventType":"SS",
"TotalCourses":3
}
*/
public string ProgramGroup { get; set; }
public string ProgramCode { get; set; }
public string EventCode { get; set; }
public string FormalDate { get { return FormalDate; } set { FormalDate = convertFormalDateToSpanish(value); } }
public string StartDate { get; set; }
public double Price { get; set; }
public string LocName { get; set; }
public string LocAddress { get; set; }
public string LocCity { get ; set; }
public string LocState { get; set; }
public string LocZipCode { get; set; }
public string LicenseeURL { get; set; }
public string AgendaURL { get { return AgendaURL; } set { AgendaURL = buildAgendaLink(value); } }
public string SeatsAreAvailable { get; set; }
public string GeneralInfoHTML { get; set; }
public string GateKeeperHTML { get; set; }
public string EventType { get; set; }
public int TotalCourses { get; set; }
public string convertFormalDateToSpanish(string val)
{
DateTime TheDate = DateTime.Parse(StartDate);
string[] FormalDate = val.Split(" ".ToCharArray());
CultureInfo ci = new CultureInfo("es-ES");
string _Date = FormalDate[1].Replace("-", " al ").Replace(",", "");
string _Month = ci.TextInfo.ToTitleCase(TheDate.ToString("MMMM", ci));
val = string.Concat(_Date, " ", _Month);
return val;
}
private string buildAgendaLink(string val)
{
if (val.Trim() != "")
{
val = string.Concat("Agenda");
}
else
{
val = "Agenda";
}
return val;
}
}
}
Your server returns an array. Just try
Course[] courses = JsonConvert.DeserializeObject<Course[]>(returnjson);
Note that this is not an answer to your original problem, but I added it like an answer in order to explain my comment above with some actual code.
First problem with your code is that FormalDate and AgendaUrl properties simply won't work. Accessing them will result in a StackOverflowException, because you basically defined them recursively.
A property is merely syntax sugar for two separate getter/setter methods, so by writing this:
public class Course
{
public string FormalDate
{
get { return FormalDate; }
}
}
You are basically writing this:
public class Course
{
public string GetFormalDate()
{
// recursive call, with no terminating condition,
// will infinitely call itself until there is no
// more stack to store context data (and CLR
// will then throw an exception)
return GetFormalDate();
}
}
To fix that, you need to add an actual backing field, e.g.:
public class Course
{
private string _formalDate; // <-- this is a backing field;
// and this property uses the backing field to read/store data
public string FormalDate
{
get { return _formalDate; }
set { _formalDate = convertFormalDateToSpanish(value); }
}
}
Additionally, it's unusual for a property getter to return a different value than the one set through a setter. In other words, I would never expect this from a class:
var course = new Course();
course.StartDate = "2016/09/01";
course.FormalDate = "September 1-2, 2016";
Console.WriteLine(course.FormalDate); // prints "1 al 2 Septiembre" ?
I would rather move this functionality into a different class, or at least create different properties which return these values:
public class CourseInfo
{
// this is now a "dumb" auto-implemented property
// (no need for a backing field anymore)
public string FormalDate { get; set; }
// this read-only property returns the converted value
public string LocalizedFormalDate
{
get
{
return convertFormalDateToSpanish(FormalDate);
}
}
}

Categories