Sending List of objects in c# web service - c#

I have the following two objects:
public class Dog
{
public string Name {get;set;}
public int Age {get;set;}
}
public class Person
{
public string Name {get;set;}
public string City {get;set;}
public string ID {get;set;}
}
Now, in the server side, I build a mix List of Person and Dog, and I would like to return this List to the client via web-service (asmx).
The order is important, and eventually my list will hold more types.
How can I return a list of mixed object in web-service?
Thank you.

I think you should create new class that encapsulate your many classes
public class Dog : MyClass
{
public string Name {get;set;}
public int Age {get;set;}
}
public class Person : MyClass
{
public string Name {get;set;}
public string City {get;set;}
public string ID {get;set;}
}
public class NewClass
{
public enum OBJType {
Dog,Person
} // like a constant for specific object type
public Dog D_Dog { get; set; }
public Person D_Person { get; set; }
public OBJType Type { get; set; }
public int seq { get; set; }
}
Then it should be use like this
//At Server
List<NewClass> newList = new List<NewClass>();
NewClass Item1 = new NewClass();
Item1.D_Dog = new Dog() { Name = "Woof", Age = 3 };
Item1.seq = 1;
Item1.Type = NewClass.OBJType.Dog;
newList.Add(Item1);
NewClass Item2 = new NewClass();
Item2.D_Person = new Person() { Name = "John", City = "TPP" , ID =111 };
Item2.seq = 2;
Item2.Type = NewClass.OBJType.Person;
newList.Add(Item2);
//At Client
List<NewClass> newList = //..get form webservice
foreach (var Item in newList)
{
if (Item.Type == NewClass.OBJType.Dog)
{
// using Item.D_Dog;
}
else {
// using Item.D_Person
}
}

Not a pro at C# so excuse if its not the most efficient.
1st class ie Person.cs
public class Person : MyClass
{
public string Name { get; set; }
public string City { get; set; }
public string ID { get; set; }
}
2nd Class ie Dog.cs
public class Dog : MyClass
{
public string Name { get; set; }
public int Age { get; set; }
}
The inherited class ie MyClass.cs
public class MyClass
{
public string Type { get; set; }
}
Notice I have added a field Type to differentiate between objects in the program consuming the webservice. You can improve this with enums for type.
The Example function to return the data.
public List<MyClass> returnData()
{
List<MyClass> returningdata = new List<MyClass>();
Person pers = new Person();
pers.City = "NELSPRUIT";
pers.Name = "TED";
pers.ID = "5502226585665";
pers.Type = "PERSON";
returningdata.Add(pers);
Dog doggy = new Dog();
doggy.Name = "Tiny";
doggy.Age = 2;
doggy.Type = "DOG";
returningdata.Add(doggy);
return returningdata;
}
Hope this is what you wanted.

Related

Objects with same properties as unic parameter?

I have two objects with the same properties like this:
ObservableCollection<A> FooA
ObservableCollection<B> FooB
both model A and B have a property in common. I've created this method for update the property without create redundancy code:
public static void UpdateItemInCollection(A person, ObservableCollection<A> collection)
{
foreach (var m in collection)
{
m.Name = m.id == person.id;
}
}
But I can only pass as parameter FooA. How can I pass also FooB?
You have to use an interface or a parent (most likely abstract) class, if that property actually represents the same kind of data in both classes.
public interface INamed
{
string Name { get; }
}
public Person : INamed
{
public string Name {get; set;}
// etc.
}
public People : INamed
{
public string Name {get; set;}
// etc.
}
public static void UpdateItemInCollection(INamed person, ObservableCollection<INamed> collection)
{
foreach (var m in collection)
{
m.Name = m.id == person.id;
}
}
You can create an interface for both classes:
public interface AandB
{
string Name { get; set; }
}
Then implement it in the classes:
public interface AandB
{
string Name { get; set; }
}
public class A : AandB
{
public string Name { get; set; }
public string id { get; set; }
}
class B : AandB
{
public string Name { get; set; }
public string id { get; set; }
}
Modify your method to get the interface instead of the class:
public static void UpdateItemInCollection(AandB person, ObservableCollection<AandB> collection)
{
foreach (var m in collection)
{
m.Name = "whatever";
}
}
The collections must be the interface type:
ObservableCollection<AandB> FooA;
ObservableCollection<AandB> FooB;
And finally,you can call the method with both classes:
FooA = new ObservableCollection<AandB>();
A objA = new A();
objA.id = "1";
objA.Name = "test";
FooA.Add(objA);
FooB = new ObservableCollection<AandB>();
B objB = new B();
objB.id = "1";
objB.Name = "test";
FooB.Add(objB);
UpdateItemInCollection(objA, FooA);
UpdateItemInCollection(objB, FooB);

How to set list A equal to list B, where on B a property does not exist which does exist on A

I have a C# list which is of type Person. This list needs to be converted into JSON data format. The Person C# class look like this:
public class Person
{
public int ID { get; set; }
public static int PSID = 1;
public string name { get; set; }
public string nameToken { get; set; }
public double DOB { get; set; }
public List<Award> awards { get; set; }
public List<Link> links { get; set; }
public Person()
{
awards = new List<Award>();
links = new List<Link>();
ID = PSID;
PSID++;
}
}
As I am required to convert a C# list of type Person into JSON. I made another Class in C# called PersonJS. It is exactly like the Person C# class the only difference is that I have removed some of the properties that are not required in the JSON front-end. Namely: nameToken, PSID.
public class PersonJS
{
public int ID { get; set; }
public string name { get; set; }
public double DOB { get; set; }
public List<AwardJS> awards { get; set; }
public List<Link> links { get; set; }
}
One of the properties of PersonJS is a List called awards which is of Type AwardJS. A problem occurs below because I try and equal Person.awards List equal to PersonJS.awards List. However, they are of difference types so it is not possible to equal both lists. The reason why I have put them equal to different types is because the JSON data does not need all of the properties that I have used in C#. So I made two classes Award and AwardJS. The only difference is that Award contains a property called filmWebToken whereas AwardJS does not.
public class Award
{
public int filmID { get; set; }
public int categoryID { get; set; }
public string filmWebToken { get; set; }
}
public class AwardJS
{
public int filmID { get; set; }
public int categoryID { get; set; }
}
In my code I iterate over all of the properties in C# list of type Person and I attempt to create a personjs object and add it to a PersonJS C# list. The PersonJS list will go back to the front-end as JSON. However, because the award property in the class PersonJS is different to the award property in Person I get the error "Cannot implicitly convert type AwardJS to Award". The reason I get this error is because PersonJS does not contain filmWebToken which exists in the Person class. I don't want the filmWebToken to be in the PersonJS list as it is not meant to be a property in my JSON data. However, as there are property fields in Person.Award I still want access to: filmID and CategoryID how can I ignore/by-pass the filmWebToken field. This is what I have tried:
List<Person> allPersons = DataRepository.GetAllPersons(); // contains the C# data
List<PersonJS> personjs = new List<PersonJS>(); // empty to start with
foreach (var person in allPersons)
{
foreach (var award in person.awards)
{
personjs.Add(
new PersonJS
{
ID = person.ID,
links = person.links,
name = person.name,
DOB = person.DOB,
awards = person.awards // The types are not equal: Person contains filmWebToken whereas PersonJS does not
});
}
}
Add a method called ToAwardJS in Award:
public AwardJS ToAwardJS() {
return new AwardJS { filmID = this.filmID, categoryID = this.categoryID };
}
Then when you create the PersonJS object, do:
new PersonJS
{
ID = person.ID,
links = person.links,
name = person.name,
DOB = person.DOB,
awards = person.awards.Select(x => x.ToAwardJS()).ToList(),
});
What serializer are you using? Most provide attributes to specify which members to include in the serialization. For example, the DataContractJsonSerializer uses [DataContract] and [DataMember]. I think Json.net uses [JsonIgnore]. There's no need for multiple classes.
void Main()
{
var jsSer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Person));
var p = new Person {
ID = 1,
name = "John",
DOB = 1234.5,
nameToken = "token"
};
string result = null;
using (var ms = new MemoryStream())
{
jsSer.WriteObject(ms, p);
byte[] json = ms.ToArray();
ms.Close();
result = Encoding.UTF8.GetString(json, 0, json.Length);
}
Console.WriteLine(result);
}
[DataContract]
public class Person
{
//included
[DataMember]
public int ID { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string nameToken { get; set; }
[DataMember]
public double DOB { get; set; }
//ignored
public static int PSID = 1;
public List<string> awards { get; set; }
public List<string> links { get; set; }
public Person()
{
awards = new List<Award>();
links = new List<Link>();
ID = PSID;
PSID++;
}
}
Result:
{"DOB":1234.5,"ID":1,"name":"John","nameToken":"token"}

Match names in list with elements in class

I wonder if there's any way to match the names in a list with the elements in a class:
I have a class:
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
and a List: List<exampleClass> EnfSist
So that's the way the list is made. Now I would like to know how to match or identify the string inside "name" from my list. To match this class:
tbl_sistematicas b = new tbl_sistematicas
{
ap_enf_id_enfermedad = Convert.ToInt32(EnfSist[0].value),
ap_pac_inicio = Convert.ToInt32(EnfSist[1].value),
ap_pac_inicio_periodo = Convert.ToInt32(2].value),
ap_pac_duracion = Convert.ToInt32(EnfSist[3].value),
ap_pac_duracion_periodo = Convert.ToInt32(EnfSist[4].value),
ap_pac_tratamiento = EnfSist[5].value
};
Once being able to match the same names I won't have to specify each index of every element in the list. The elements in the list have the same name as in the table. Not all elements of the class are being used.
I have something like this: tbl_sistematicas bh = EnfSist.FindAll(x => x.name == bh.?????? );
If I understand the question, you can do this using something like automapper or ValueInjector
An example using ValueInjector
void Main()
{
List<exampleClass> EnfSist = new List<exampleClass>();
EnfSist.Add(new exampleClass { name = "ap_enf_id_enfermedad", value = "12" });
EnfSist.Add(new exampleClass { name = "apap_pac_inicio" , value = "34" });
// etc
tbl_sistematicas b = new tbl_sistematicas();
b.InjectFrom<MyInjection>(EnfSist);
}
public class MyInjection : KnownSourceValueInjection<List<exampleClass>>
{
protected override void Inject(List<exampleClass> source, object target)
{
foreach(var entry in source)
{
var property = target.GetProps().GetByName(entry.name, true);
if (property != null)
property.SetValue(target, Convert.ChangeType(entry.value, property.PropertyType));
}
}
}
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
public class tbl_sistematicas
{
public int ap_enf_id_enfermedad { get; set; }
public int apap_pac_inicio { get; set; }
public int ap_pac_inicio_periodo { get; set; }
public int ap_pac_duracion { get; set; }
public int ap_pac_duracion_periodo { get; set; }
public string ap_pac_tratamiento { get; set; }
}
Note, this will throw an exception if the value can not be converted to an int

Passing dynamic type, iterating fields and replacing values

I have 3/4 different models that each contain their own nested model. I need a way of iterating all fields, including those of the nested model and do a string replace (although not all fields are strings).
My initial idea was to write a method which allows for a 'dynamic' type to be passed.
Input model:
Name = Joe
Surname = Smith
Address = new ClientAddress
{
Line1: Item A
Line2: mistake
Line3: mistake
}
My example method:
MyMethod (dynamic passInModel)
{
....
passInModel.Replace("mistake","correction");
return passInModel;
}
Output:
Name = Joe
Surname = Smith
Address = new ClientAddress
{
Line1: Item A
Line2: correction
Line3: correction
}
Despite trying various ways of doing it I've not had any success in writing something that does the job.
You could write a method that accepts an object and use reflection to iterate through all the fields, but you're getting into messy territory there. In my opinion, even using dynamic here is messy.
Consider using a modified visitor pattern here. If your domain objects look like this:
public class ModelBase
{
}
public class MyModel1 : ModelBase
{
public string Name { get; set; }
public string Surname { get; set; }
public ClientAddress Address { get; set; }
}
public class MyModel2 : ModelBase
{
public string CompanyName { get; set; }
public string Region { get; set; }
public CompanyAddress Address { get; set; }
}
public class ClientAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}
public class CompanyAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public List<string> AdditionalLines { get; set; }
}
Write a visitor that takes an abstract ModelBase and dispatches the correct type-safe visitor:
public class ModelFixVisitor
{
public ModelBase Visit(ModelBase model)
{
var asModel1 = model as MyModel1;
if (asModel1 != null)
{
return new Model1FixVisitor().Visit(asModel1);
}
var asModel2 = model as MyModel2;
if (asModel2 != null)
{
return new Model2FixVisitor().Visit(asModel2);
}
throw new NotImplementedException("Unknown model type.");
}
}
Then write a simple class for each type (and subtype) you need to visit:
public class Model1FixVisitor
{
public MyModel1 Visit(MyModel1 model)
{
model.Name = new StringFixVisitor().Visit(model.Name);
model.Surname = new StringFixVisitor().Visit(model.Surname);
model.Address = new ClientAddressFixVisitor().Visit(model.Address);
return model;
}
}
public class Model2FixVisitor
{
public MyModel2 Visit(MyModel2 model)
{
model.CompanyName = new StringFixVisitor().Visit(model.CompanyName);
model.Region = new StringFixVisitor().Visit(model.Region);
model.Address = new CompanyAddressFixVisitor().Visit(model.Address);
return model;
}
}
public class ClientAddressFixVisitor
{
public ClientAddress Visit(ClientAddress address)
{
address.Line1 = new StringFixVisitor().Visit(address.Line1);
address.Line2 = new StringFixVisitor().Visit(address.Line2);
address.Line3 = new StringFixVisitor().Visit(address.Line3);
return address;
}
}
public class CompanyAddressFixVisitor
{
public CompanyAddress Visit(CompanyAddress address)
{
address.Line1 = new StringFixVisitor().Visit(address.Line1);
address.Line2 = new StringFixVisitor().Visit(address.Line2);
address.AdditionalLines = new StringListFixVisitor().Visit(address.AdditionalLines);
return address;
}
}
public class StringFixVisitor
{
public string Visit(string element)
{
return element.Replace("mistake", "correction");
}
}
public class StringListFixVisitor
{
public List<string> Visit(List<string> elements)
{
return elements
.Select(x => new StringFixVisitor().Visit(x))
.ToList();
}
}
I'm sure the code could be refactored and optimized, but it should express the general idea.
What I like about this type of solution is that it breaks the problem down into small, manageable chunks: How do I fix a string? How do I fix a ClientAddress?
Fixing entire models then becomes simple composition of these smaller classes. It's a little more verbose, but you get to keep type safety, and don't have to mess with reflection.
You can use the power of .Net reflection to solve this.
I created a class called DeepStringReplacer. Using reflection it iterates through object properties and if the type is string, perform string replace.
Check the code below:
public class DeepStringReplacer
{
public object Replace(object input, string oldValue, string newValue)
{
if (input is string)
{
return input.ToString().Replace(oldValue, newValue);
}
var fields = input.GetType().GetProperties();
foreach (var field in fields)
{
var fieldValue = field.GetValue(input);
field.SetValue(input, Replace(fieldValue, oldValue, newValue));
}
return input;
}
}
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public ClientAddress Address { get; set; }
}
public class ClientAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}

How to write LINQ query on Generic List

I have a situation where I have a generic method which accepts an object of type generic and I want to write a LINQ query on that object.
Here is an example:
Generic Method:
public static void GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
// How To Write LINQ Here to get non verified person
}
Student Class:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
Teacher Class:
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
Person Class:
public class Person<T>
{
public List<T> PersonList { get; set; }
}
Main Class:
// 1. Get Non Verified Students
var persons = new Person<Student>();
var students = new List<Student>()
{
new Student { Id = 1, Name = "Student_A", IsVerified = true },
new Student { Id = 2, Name = "Student_B", IsVerified = false },
};
persons.PersonList = new List<Student>();
persons.PersonList.AddRange(students);
GetNonNonVerifiedPersons(persons);
// 2. Get Non Verified Teachers
var persons2 = new Person<Teacher>();
var teachers = new List<Teacher>()
{
new Teacher { Id = 1, Name = "Teacher_A", IsVerified = true },
new Teacher { Id = 2, Name = "Teacher_B", IsVerified = false },
new Teacher { Id = 3, Name = "Teacher_C", IsVerified = false },
};
persons2.PersonList = new List<Teacher>();
persons2.PersonList.AddRange(teachers);
GetNonNonVerifiedPersons(persons2);
You should use interface to be able to specify the type of Teacher and Student in generic type. When you use where clause compiler is able to do the type checks at compile time.
public interface IHuman
{
string Name { get; set; }
bool IsVerified { get; set; }
}
public class Teacher : IHuman
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
public class Student : IHuman
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
And then your method should be like this. Here we have where clause that says only accept generic type TResult when implements IHuman.
public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model) where TResult : IHuman
{
return model.PersonList.Where(x => !x.IsVerified);
}
Update : I highly suggest you to make the big changes because its how it should be.
Other way which is not common and extremely slow is to check for the types at runtime.
public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
var list = model.PersonList;
var t = list.FirstOrDefault() as Teacher;
if (t != null)
{
return model.PersonList.Where(x => !(x as Teacher).IsVerified);
}
var s = list.FirstOrDefault() as Student;
if (s != null)
{
return model.PersonList.Where(x => !(s as Student).IsVerified);
}
return null;
}
May be this can do the trick:
IList<Person<TResult>> xyz = new List<Person<TResult>>();
var list = xyz.Where(a => a.GetType() == typeof(Student).IsVerified);
I didn't check it in IDE but something like this would work

Categories