WCF handling objects - c#

I have a class which is placed in a class library:
public class UserProfile
{
public int UserId { get; set; }
public string UserName { get; set; }
}
Then I have a repository class:
public class Repository
{
public List<UserProfile> GetUsers()
{
using (var context = new DBContext())
{
List<UserProfile> list = context.UserProfiles.ToList();
return list;
}
}
}
business logic class:
public class BusinessLogic
{
public List<UserProfile> GetUserProfiles()
{
Repository repo = new Repository();
List<UserProfile> list = repo.GetUsers().ToList();
return list;
}
}
and finaly WCF:
public interface IService1
{
[OperationContract]
List<UserProfile> GetUserProfiles();
}
public class Service1 : IService1
{
public List<UserProfile> GetUserProfiles()
{
BusinessLogic.BusinessLogic bl = new BusinessLogic.BusinessLogic();
List<UserProfile> list = bl.GetUserProfiles().ToList();
return list;
}
}
Whenever I try to get user profiles from wcf, it returns empty list.
However, if I skip wcf and get List<UserProfile> straight from businesslogic, it works perfectly fine.
I tried to debug. Results: when inside wcf it gets list from businesslogic, it's already empty. But as I said earlier, business logic works perfectly fine (returns necessary information).
There were similar posts but none of them did help me.
How can I make my WCF return a list filled with necessary information?
P.S. I do not want to add a copy of my class UserProfile into wcf with [DataContract] flag

Your object must either be serializable or decorated with that DataContract attribute. Your return type from WCF must also be decorated with the DataContract attribute, and the member containing your List must be marked with the DataMember attribute. This is required by WCF's DataContractSerializer in order to properly serialize the data and return it to the consumer. Converting a class for transmission over the wire requires serialization. There isn't a practical way to get around this with WCF.
Your list is empty because your UserProfile class cannot be serialized.
EDIT:
I just saw you are simply returning a list, which is already serializable, so if you just make your UserProfile class serializable or decorate it with the appropriate DataContract/DataMember classes, it will start working fine.

Related

Why is my response being serialized without navigation properties?

Today I ran into a small problem with my code. I have an HttpGet method similar to the following:
[HttpGet]
public IEnumerable<SomeEntity> Get()
{
return db.SomeEntity.ToList();
}
where SomeEntity could be represented as
public class SomeEntity
{
#region DatabaseColumns
[Key]
public int SomeEntityID { get; set; }
public string SomeEntityName { get; set; }
#endregion
#region Navigation Properties
public virtual ICollection<SomeChildEntity> SomeChildEntity { get; set; }
#endregion
}
I noticed that return db.SomeEntity.ToList(); only returned the top level members of the object (not the navigation properties).
This made sense to me considering I was not calling Include. Out of curiosity, I attempted the following:
[HttpGet]
public IEnumerable<SomeEntity> Get()
{
var enumeratedEntity = db.SomeEntity.ToList();
return enumeratedEntity;
}
To my surprise, it returned the entire entity along with its navigation properties.
I also noticed that an HttpGet along these lines also returned the entire object
[HttpGet]
public SomeEntity Get(int id)
{
return db.SomeEntity.Find(id);
}
Can someone please explain, or point me to resources that will explain, why these methods return the entire object without using the Includes method while the first one doesn't?
I'm not 100% on this, so feel free to test and then up or downvote me. When you return an IEnumerable<SomeEntity> you don't define a concrete type. You're returning some generic IEnumerable which the HTTP pipeline then strips the virtual properties out of.
When you call var enumeratedEntity = db.SomeEntity.ToList(); you create a List. That concrete object then gets the virtual properties immediately instantiated. The whole concrete object is then sent down the pipeline including the virtual properties.
You could test this by changing var enumeratedEntity = db.SomeEntity.ToList(); to IEnumerable<SomeEntity> enumeratedEntity = db.SomeEntity.ToList(); and List<SomeEntity> enumeratedEntity = db.SomeEntity.ToList();. You'd then expect to see the 2 behaviors you currently see based on which generic container you use.

WCF ensure that the necessary enum values are present

I'm trying to serialize enum values which potentially do not exist yet.
I have an existing project which has several enums in our datacontract for simplicity reason I display one like so:
public partial class TestDTO : ITestDTO
{
public DeleteMe DeleteMeEnum { get; set; }
}
[DataContract]
public enum DeleteMe
{
[EnumMember]
Deleted = 0,
}
Our application has a hidden internal wcf layer which our public web api accesses. A sample Service contract looks like so:
[ServiceContract]
public interface ITestService
{
[OperationContract]
TestDTO GetTestDTO();
}
public class TestService : ITestService
{
public TestDTO GetTestDTO()
{
return new TestDTO() { DeleteMeEnum = (DeleteMe)2 };
}
}
When I call this method from WebApi obviously I get the classic error:
Enum value '2' is invalid for type 'DeleteMe' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.
I can't go and change all of the enums now because we have a massive project, and replacing them would be too much, Also replacing all of our Service Contracts with a new Attibute would be too much.
Does anyone know of a way I can fix this globally, such as replacing the default XMLSerializer with a custom XMLSerializer?
There isn't a nice way to handle this once your application is released. However if you plan for the situation ahead of time, it can be handled.
So for the example above, you can do this:
public partial class TestDTO : ITestDTO
{
[DataMember(Name = "DeleteMeEnum")]
private string DeleteMeEnumString
{
get { return DeleteMeEnum.ToString(); }
set {
DeleteMe _enum;
if (!Enum.TryParse(value, out _enum))
{
_enum = <default value>;
}
DeleteMeEnum = _enum;
}
}
[IgnoreDataMember]
public DeleteMe DeleteMeEnum { get; set; }
}

Returning List<T> with WCF service

I got an Employee class and each employee has a list of applied leaves. Is it possible to have the list AppliedLeave as a [DataMember] in WCF?
[DataContract]
public class Employee
{
[DataMember]
public string UserID { get; set; }
[DataMember]
public int EmployeeNumber { get; set; }
[ForeignKey("EmployeeUserID")]
[DataMember]
public List<Leave> AppliedLeave
{
get { return _appliedLeaves; }
set { _appliedLeaves = value; }
}
private List<Leave> _appliedLeaves = new List<Leave>();
...
}
Is there any other way to do this?
thank you for your consideration of this matter
I extend my Question
This is my Leave Class:
[DataContract]
public class Leave
{
[Key()]
[DataMember]
public Guid LeaveId { get; set; }
[DataMember]
public string LeaveType { get; set; }
[DataMember]
public DateTime StartDate { get; set; }
[DataMember]
public string EmployeeUserID { get; set; }
}
this shows ServiceContract ---->
[ServiceContract]
public interface IEmployeeService
{
[OperationContract]
Employee GetEmployeeByUserId(string userId);
[OperationContract]
void AssignSupervisor(string userId, string supervisorUserId);
[OperationContract]
void DeleteEmployeeByUserId(string userId);
....
}
In Client application,
EmployeeServiceClient employeeService = new EmployeeServiceClient();
Employee employee = employeeService.GetEmployeeByUserId(id);
But when Employee gathered from the service its shows Null for leaves,
Can somebody help me? what have I done wrong here?
Yes, it is possible to return generics from WCF service operations.
But by default they are casted to Array on client side. This can be customized while proxy generation.
WCF: Serialization and Generics
Also you have to decorate the service with all the types to which generics can be resolved, using KnownTypeAttribute.
Known Types and the Generic Resolver
I also found my server side list would always arrive at the client as a null pointer. After browsing around a lot for this problem it strikes me it is nearly always denied at first ("your code should work")
Found the issue.. I had configured my solution using one "WCF Service" project and one "Winforms app" project with a generated service reference. Both interface and implementation of Service1 were in the WCF service project, as expected. But any list member returned null.
When I put my IService1.cs = the interface only = in a separate class library instead, reference the class library on both sides (using) and generate the service reference again, my list does work ! The generated code on the client side looks much simpler.
I did not need any special attributes, change service reference configuration, or interface references for this.
You could use IList<T> instead of List<T>.

Accessing custom objects in DomainService from client

I am using Domain Service to fetch data from database from Silverlight Client.
In DomainService1.cs, I have added the following:
[EnableClientAccess()]
public class Product
{
public int productID;
public string productName;
public List<Part> Parts = new List<Part>(); //Part is already present in Model designer
}
In DomainService1 class I added a new method to retrive a collection of the custom class object:
[EnableClientAccess()]
public class DomainService1 : LinqToEntitiesDomainService<HELPERDBNEWEntities1>
{
...
public List<Product> GetProductsList(...)
{
List<Product> resultProducts = new List<Product>();
...
return resultProducts;
}
}
From the silverlight client I am trying to access that method:
DomainService1 ds1 = new DomainService1();
var allproductList = ds1.GetProductsList(...);
ds1.Load<SLProduct>(allproductList).Completed += new EventHandler(Load_Completed); //Not correct usage
However it is not the correct way to call the new method. The reason I added a new class Product in DomainServices.cs is to have an efficient grouping. I cannot achieve the same using the model classes auto-generated by the entity framework.
How call I call the new method from the client?
I believe there is a similar question with an answer here:
Can a DomainService return a single custom type?
Also, here is some discussion about the overall problem of adding custom methods in a Domain Service:
http://forums.silverlight.net/t/159292.aspx/1
While I don't know what you mean by "it is not the correct way to call the new method", or if you're getting any errors, I thought maybe posting some working code might help.
My POCO
public class GraphPointWithMeta
{
[Key]
public Guid PK { get; set; }
public string SeriesName { get; set; }
public string EntityName { get; set; }
public double Amount { get; set; }
public GraphPointWithMeta(string seriesName, string entityName, double amount)
{
PK = Guid.NewGuid();
SeriesName = seriesName;
EntityName = entityName;
Amount = amount;
}
// Default ctor required.
public GraphPointWithMeta()
{
PK = Guid.NewGuid();
}
}
A method in the domain service (EnableClientAccess decorates the class)
public IEnumerable<GraphPointWithMeta> CallingActivityByCommercial()
{
List<GraphPointWithMeta> gps = new List<GraphPointWithMeta>();
// ...
return gps;
}
Called from the Silverlight client like
ctx1.Load(ctx1.CallingActivityByCommercialQuery(), CallingActivityCompleted, null);
client call back method
private void CallingActivityCompleted(LoadOperation<GraphPointWithMeta> lo)
{
// lo.Entities is an IEnumerable<GraphPointWithMeta>
}
I am not sure if your Product class is an actual entity or not. From the way it is defined, it does not appear to be an entity. My answer is assuming it is not an entity. You will need to apply the DataMemberAttribute for your Product properties, and you wouldn't load the product list - load is for Entity Queries (IQueryable on the service side). You would just invoke it like this (client side):
void GetProductList( Action<InvokeOperation<List<Product>>> callback)
{
DomainService ds1 = new DomainService();
ds1.GetProductsList(callback, null);//invoke operation call
}
And the domain service's (server side) method needs the InvokeAttribute and would look like this:
[EnableClientAccess]
public class MyDomainService
{
[Invoke]
public List<Product> GetProductList()
{
var list = new List<Product>();
...
return list;
}
}
And here is how your Product class might be defined (if it is not an entity):
public class Product
{
[DataMember]
public int productID;
[DataMember]
public string productName;
[DataMember]
public List<Part> Parts = new List<Part>(); // you might have some trouble here.
//not sure if any other attributes are needed for Parts,
//since you said this is an entity; also not sure if you
//can even have a list of entities or it needs to be an
//entity collection or what it needs to be. You might
//have to make two separate calls - one to get the products
//and then one to get the parts.
}
Like I said, i am not sure what Product inherits from... Hope this helps.

WCF: How do i return a .NET Framework class via Datacontract?

As a beginner to WCF i want to implement a call to the Active Directory Service which gets all Users, the method looks like this:
[OperationContract]
SearchResultCollection GetAllUsers();
SearchResultCollection is not serializable so i have to make something like this:
[DataContract]
SearchResultCollection
So i have to make my own wrapper class which inherits the SearchResultCollection or use IDataContractSerializer. Both solutions seems not easy.
The question: How is the "standard" approach to use .NET Classes as a return type in a WCF service?
(Writing a own DataContract for my own class seems easy. ;))
The DataContract route will suffice here. The standard way is to decorate your class with the relevant attributes and it will be consumable by WCF in methods:
[DataContract]
public sealed class CustomerResponse
{
[DataMember]
public Guid CustomerReference { get; set; }
}
[ServiceContract]
public interface IWcfMessagingService
{
[OperationContract]
CustomerResponse GetCustomer();
}
If the class is not serializable, I don't think even wrapping it will work.
However, the SearchResultCollection is itself returned from a WCF method, so you could just pass that straight through your own service, or at the very least, wrap it successfully.
I think your best bet is create your own simple POCO class to represent SearchResult, and return a list of these objects. Really you want to be able to control exactly the information you need to send back from the service. For example:
[Serializable]
public class MySearchResult
{
public string Name { get; set; }
public string Email { get; set; }
}
And simply iterate the searech results and pull out the properties you need like so:
var results = new List<MySearchResult>();
foreach (SearchResult r in searchResultCollection)
{
results.Add(new MySearchResult
{
Name = searchResult.Properties["Name"],
Email = searchResult.Properties["Email"]
});
}
That way the xml being sent back isn't bloated with all the properties you don't need AND you can serialize your own List<MySearchResult> return results. And by the way I have no idea if the Name and Email properties exist I am just showing an example.
I think I would just return a List of User where User is a custom User class flagged as Serializable. The method that gets the data from active directory can populate the User class by looping through the result.

Categories

Resources