Reputation: 137
I have a method which has a string type parameter and returns a List where Tasks is a class defined by me.
When I want to JSON serialize the returned List it gives me an Exception: InvalidOperationException("Json serializable types must have a public, parameterless constructor");
What should I do?
My class looks like this:
public class Tasks
{
public int _taskReprogramat;
public int TaskReprogramat{ get; set; }
public string TaskName {get; set; }
public string Description{get; set; }
public string IntreOrele{get; set; }
public DateTime AssignDate{get; set; }
public string Status{get; set; }
public Tasks() { }
}
and I have the following classes:
public class DataContractJsonSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public DataContractJsonSerializerOperationBehavior(OperationDescription operation) : base(operation) { }
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractJsonSerializer(type);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractJsonSerializer(type);
}
}
and
public class JsonDataContractBehaviorAttribute : Attribute, IContractBehavior
{
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
this.ReplaceSerializerOperationBehavior(contractDescription);
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
{
this.ReplaceSerializerOperationBehavior(contractDescription);
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
foreach (MessageDescription message in operation.Messages)
{
this.ValidateMessagePartDescription(message.Body.ReturnValue);
foreach (MessagePartDescription part in message.Body.Parts)
{
this.ValidateMessagePartDescription(part);
}
foreach (MessageHeaderDescription header in message.Headers)
{
this.ValidateJsonSerializableType(header.Type);
}
}
}
}
private void ReplaceSerializerOperationBehavior(ContractDescription contract)
{
foreach (OperationDescription od in contract.Operations)
{
for (int i = 0; i < od.Behaviors.Count; i++)
{
DataContractSerializerOperationBehavior dcsob = od.Behaviors[i] as DataContractSerializerOperationBehavior;
if (dcsob != null)
{
od.Behaviors[i] = new DataContractJsonSerializerOperationBehavior(od);
}
}
}
}
private void ValidateMessagePartDescription(MessagePartDescription part)
{
if (part != null)
{
this.ValidateJsonSerializableType(part.Type);
}
}
private void ValidateJsonSerializableType(Type type )
{
if (type != typeof(void))
{
if (!type.IsPublic)
{
throw new InvalidOperationException("Json serialization is supported in public types only");
}
ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]);
if (!type.IsPrimitive && defaultConstructor == null )
{
throw new InvalidOperationException("Json serializable types must have a public, parameterless constructor");
}
}
}
}
and my method in which I am using the Tasks class is:
public List<Tasks> GetTask(string admin, DateTime date)
{
List<Tasks> tasks = new List<Tasks>();
string conn = ConfigurationManager.ConnectionStrings["qtmConnectionString"].ConnectionString;
SqlConnection myConn = new SqlConnection(conn);
myConn.Open();
SqlCommand myCommand = new SqlCommand("tasks", myConn);
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.Add("@username", SqlDbType.NChar);
myCommand.Parameters["@username"].Value = admin;
myCommand.Parameters.AddWithValue("@date", date);
SqlDataReader reader = myCommand.ExecuteReader();
string status = null;
string intreOrele = null;
Tasks task = new Tasks();
task.TaskName = reader[1].ToString();
task.Description = reader[2].ToString();
task.IntreOrele = intreOrele;
task.AssignDate = Convert.ToDateTime(reader[5]);
task.Status = status;
tasks.Add(task); return tasks;
}
Upvotes: 1
Views: 1331
Reputation: 8464
The problem is the class you are de-serializing does not have a public, parameterless constructor. It might look like this:
public class Person
{
public Person(int id, string name)
{
this.id = id;
this.person = person;
}
private int id;
private string name;
public string Name { get { return this.name; } }
public int Id { get { return this.id; } }
}
The problem is the JSON serializer needs to do this:
var obj = new Person();
obj.Id = jsonParser.Get<int>("id");
obj.Name = jsonParser.Get<string>("name");
It isn't clever enough (or designed ) to go through the constructor like this:
var obj = new Person( jsonParser.Get<int>("id"), jsonParser.Get<string>("name") );
So change your class to do this:
public class Person
{
public Person(int id, string name)
{
this.Id = id;
this.Person = person;
}
// Parameterless constructor here
public Person()
{
}
public string Name { get ; set; }
public int Id { get;set; }
}
Upvotes: 1