views:

739

answers:

2

I am trying to send an anonymous object over a web service. Is there anyway I can do this without manually creating a class and casting it to that class? Currently its throwing an exception saying Anonymous object could not be serialized.

// Some code has been removed here to simplify the example.
[WebMethod(EnableSession = true)]
public Response GetPatientList() {
    var patientList = from patient in ((User)Session["user"]).Practice.Patients
                      select new {
                          patientID = patient.PatientID,
                          status = patient.Active ? "Active" : "Inactive",
                          patientIdentifier = patient.PatientIdentifier,
                          physician = (patient.Physician.FirstName + " " + patient.Physician.LastName).Trim(),
                          lastModified = patient.Visits.Max(v => v.VisitDate)
                      };
    return patientList;
}

Thanks in advance.

Edit: Here is an example of what I mean by manually creating a class to return and fill it with the anonymous object...

public class Result {
    public bool success;
    public bool loggedIn;
    public string message;
}

public class PracticeInfoResult : Result {
    public string practiceName;
    public string address;
    public string city;
    public string state;
    public string zipCode;
    public string phone;
    public string fax;
}
+4  A: 

Anonymous type are meant to be used for simple projections of very loosely coupled data, used only within a method. If it makes sense for a web method to return data of a type, it really should be decently encapsulated. In other words, even if you can find a way to return an instance of an anonymous type from a web method, I strongly suggest you don't do it.

I would personally not create the classes with public fields either - use automatically implemented properties instead, so you can safely add more behaviour later if you need to.

Note that after you've created the "proper" type, your query expression only needs to change very, very slightly - just add the name of the type between new and { to use an object initializer.

Jon Skeet
Just curious, why do you prefer automatically implemented properties over public fields?
Kevin
See http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx
Jon Skeet
Thanks.  
Kevin
+1  A: 

Here is the code I wound up using.

[WebMethod(EnableSession = true)]
public PatientsResult GetPatientList(bool returnInactivePatients) {
    if (!IsLoggedIn()) {
        return new PatientsResult() {
            Success = false,
            LoggedIn = false,
            Message = "Not logged in"
        };
    }
    Func<IEnumerable<PatientResult>, IEnumerable<PatientResult>> filterActive = 
        patientList => returnInactivePatients ? patientList : patientList.Where(p => p.Status == "Active");
    User u = (User)Session["user"];
    return new PatientsResult() {
        Success = true,
        LoggedIn = true,
        Message = "",
        Patients = filterActive((from p in u.Practice.Patients
                      select new PatientResult() {
                          PhysicianID = p.PhysicianID,
                          Status = p.Active ? "Active" : "Inactive",
                          PatientIdentifier = p.PatientIdentifier,
                          PatientID = p.PatientID,
                          LastVisit = p.Visits.Count > 0 ? p.Visits.Max(v => v.VisitDate).ToShortDateString() : "",
                          Physician = (p.Physician == null ? "" : p.Physician.FirstName + " " + p.Physician == null ? "" : p.Physician.LastName).Trim(),
                      })).ToList<PatientResult>()
    };
}
public class Result {
    public bool Success { get; set; }
    public bool LoggedIn { get; set; }
    public string Message { get; set; }
}
public class PatientsResult : Result {
    public List<PatientResult> Patients { get; set; }
}
public class PatientResult  {
    public int PatientID { get; set; }
    public string Status { get; set; }
    public string PatientIdentifier { get; set; }
    public string Physician { get; set; }
    public int? PhysicianID {get;set;}
    public string LastVisit { get; set; }
}

}

Shawn Simon