DataContractException in hosted WCF service - wcf

I am trying a host a service where there is a method that returns the following type:
[DataContract]
[Obfuscation(ApplyToMembers = true, Exclude = true)]
[Serializable]
public class Output
{
[DataMember]
public DataSet dsOutput{get;set;}
}
The method signature is as follows:
[OperationContract]
[WebGet]
function Output matchData(DataSet pDSSide1,DataSet pDSSide2)
{
return new Output();
}
On browsing the service I encounter the following exception:
System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension:System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://tempuri.org/:TesterTool ---->
System.Runtime.Serialization.InvalidDataContractException: Type 'System.Data.DataRow' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
`
Any suggestions.

It's not a good practice to send a DataTable over a service.
As stated by govindaraj here:
The best way is to use custom collection of custom object.
If you're using 2.0, then you can use generic collection instead of
custom collection to reduce code.
How?
Create a custom data object (containing only private fields and public properties for each field) that is similar to each row in the
datatable.
Create a layer that will do all database (in this case, dataset) access and translation to the custom object.
All client code will access that layer.

Related

SerializationException when returning custom classes from a WCF service

I have the following classes...
public abstract class Fallible<T> {
}
public class Success<T> : Fallible<T> {
public Success(T value) {
Value = value;
}
public T Value { get; private set; }
}
The background to this can be found in a previous question of mine, but you don't need to read that post as the classes above are all that's needed to see the problem.
If I have a simplified WCF service call like this...
[OperationContract]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
...then when I try to call the service from the WPF app that consumes it (or the WCF test client), I get a CommunicationException exception...
There was an error while trying to serialize parameter :GetPatientResult. The
InnerException message was 'Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by
adding them to the list of known types passed to the serializer.'. Please
see InnerException for more details.
...with an inner SerializationException exception of...
Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer or add any types not known statically to the list
of known types - for example, by using the KnownTypeAttribute attribute
or by adding them to the list of known types passed to the serializer.
I've tried adding [DataContract] to the class and [DataMember] to each property, as well as adding a [KnownType] attribute for all four classes involved, and adding a [ServiceKnownType] for each of them on the service contract, but nothing helps.
I've read countless answers to the same question, but have not found anything that works. My services return other custom classes, and they all get serialised without a problem.
Anyone able to explain what the problem is here? Please let me know if I've not supplied enough information.
Turns out all I needed to do was decorate the service method with [ServiceKnownType] attributes for the base type, and each derived type...
[OperationContract]
[ServiceKnownType(typeof(Fallible<Patient>)]
[ServiceKnownType(typeof(Success<Patient>)]
[ServiceKnownType(typeof(BadIdea<Patient>)]
[ServiceKnownType(typeof(Failure<Patient>)]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
Although it's a pain to have to add four attributes to every call, it works. I'd like to know if there is a way to combine them into one attribute, but at least I have a working service now.
Hope this helps someone.

WCF deserialization of type object Properties

I am having trouble achieving the following scenario.
We currently have a method which expects a list of 'context' key value pairs. The value however can be of any type.
the goal is to make this method available using WCF. So I created a
public List<Element> Transform(List<Element> elements)
{
... Transformation of elements takes place
}
[DataContract(Namespace = Constants.NAMESPACE)]
public struct Element
{
[DataMember(Order = 0, IsRequired = true)]
public string Key;
[DataMember(Order = 1, IsRequired = true)]
public object Value;
}
When I use a .Net test project everything works fine.
However, when I call this service using SOAP UI I get an error message:
The formatter threw an exception while trying to deserialize the
message: There was an error while trying to deserialize parameter
elements. The InnerException message was 'Element Value cannot have
child contents to be deserialized as an object. Please use XmlNode[]
to deserialize this pattern of XML.'.
I am having trouble figuring out what to do. any help appreciated.
the xml i use is this:
<ws:Transform>
<ws:elements>
<ws:Element>
<ws:Key>Key1</ws:Key>
<ws:Value>A</ws:Value>
</ws:Element>
<ws:Element>
<ws:Key>Key2</ws:Key>
<ws:Value>B</ws:Value>
</ws:Element>
<ws:ScriptName>SetVariable</ws:ScriptName>
</ws:elements>
</ws:Transform>
In this case, SoapUI uses .Net technology which does not understand target type for object.
sending object is not valid across all platforms. In fact you might get an error with a .Net client as well. Your best bet is create a generic xml representation of the Value and have all clients inflate the object from the xml

PetaPoco - Including Custom Partial Class Properties in WCF Response

I have been experimenting with using PetaPoco for a small project I am working, and it has been awesome so far.
I have created some additional, non auto-generated partial classes to hold various computed values, as shown in my example below. I can't get these additional properties to be serialized into a WCF response, but all of the properties in the auto-generated stuff serializes just fine. I tried using [Serializable] and [DataContract] on these custom properties, but they break the WCF service altogether.
Any ideas?
public partial class Session
{
[ResultColumn]
public int ConnectedUserCount
{
get
{
AssistedServiceDB db = new AssistedServiceDB();
return db.ExecuteScalar<int>("SELECT Count(*) FROM Session_AssistedServiceUser WHERE IsConnected = 1");
}
}
There are couple of things to look to get partial WCF DataContracts to work. First, if the other Session class is marked with the DataContract then this class would also need to be marked the same way. This is assuming the ResultSession class is also serializable and/or marked as DataContract. The other issue is WCF requires properties to, as a minimum, have private setters so the ConnectedUserCount property needs to be changed to have one.

Passing an Entity Framework Context object to WCF

I need to pass a Context object from EF into a WCF method.
Normally, I create the Context object in the WCF method and dispose of it right before the end of the method call which works just fine for most of my methods.
However, I need to pass the Context object (specifically the DBContext) over from the MVC controller to my specific WCF method because I have caching enabled for some lookup tables. I need this specific Context object passed over (the one I set in the Application_Start method of the Global.asax file) rather than what I do in the sentence above because I use this specific object for the SqlDependency. If I try and create the DBContext object brand new, I can't use the SqlDependency becuase I will get an error informing me that the SqlDependency needs to be enabled before the database call.
The problem is that I'm getting the following error (shortened for brevity) when I try and start my WCF Test Client tool which I know has something to do with not properly declaring a KnownType attribute (ie the DBContext object). Note that the WCF project compiles just fine. I need some help with this specific part since I have never used a KnownType in my WCF service. They have all been simple types (int, string, etc).
Error: Cannot obtain Metadata from http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex
If this is a Windows (R) Communication Foundation service to which you
have access, please check that you have enabled metadata publishing at
the specified address. For help enabling metadata publishing, please
refer to the MSDN documentation at
http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata Exchange
Error URI:
http://localhost:8732/Design_Time_Addresses/YeagerTechWcfService/YeagerTechWcfService/mex
Metadata contains a reference that cannot be resolved:
I have the following OperationContract code in my WCF service:
[OperationContract]
IEnumerable<Category> GetCategories(YeagerTechEntities DbContext);
I have the following DataContract code in my WCF service:
namespace YeagerTechModel
{
[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(YeagerTechEntities))]
public partial class Category
{
public Category()
{
this.Projects = new HashSet<Project>();
}
[DataMember]
public short CategoryID { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public virtual ICollection<Project> Projects { get; set; }
}
}
Finally, the following is my WCF method:
public IEnumerable<YeagerTechModel.Category> GetCategories(YeagerTechEntities DbContext)
{
//YeagerTechEntities DbContext = new YeagerTechEntities();
DbContext.Configuration.ProxyCreationEnabled = false;
IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0).AsCached("Categories").ToList();
//IEnumerable<YeagerTechModel.Category> category = DbContext.Categories.Where(p => p.CategoryID > 0);
CloseConnection(DbContext);
return category;
}
You need singleton object following registry / service locator pattern. This object will hold reference to your global objects. For example at application start you will fill this object with your context using SqlDependency and you will use the registry to access this context in your controller's actions and service's operations.
Anyway work with this very carefully. SqlDependency and EF doesn't play nice together because it will make your context long living. Long living context is in most cases anti-pattern. Never ever use that context for anything else then loading cached data. Don't use it for data modification or loading non cached relations! Load entities as non-tracked (AsNoTracking extension method on query) in the first query and turn off proxy creation and lazy loading for that context.
Also be aware that query in EF is always executed in the database. I'm not sure what your AsCached is supposed to do but I somehow doubt it will work. What you need is probably:
var category = DbContext.Categories.Local
.Where(p => p.CategoryID > 0)
.ToList();
I would not use SqlDependency with EF. I would use ADO.NET and SQL directly. For caching in EF I would check EF Caching provider to use second level cache which is in most cases enough.

using custom types in a WCF service

I'm new in WCF and now stuck in something about using custom types in WCF service.
I have two classes Class1 and Class2 in TestClass project
public Class1: ArrayList{
public string street;
}
public Class2{
public string name;
public string address;
}
My WCF service TestService include function DoSomething using two above classes
public string DoSomething(Class1 c1){
return c1.street;
}
And when try to call this function
Class1 c1 = new Class1();
Class2 c2 = new Class2();
c1.Add(c2);
ServiceClient1.Dosomething(c1);
I get the Exception
There was an error while trying to serialize parameter http://tempuri.org/:c1. The
InnerException message was 'Type 'WebApplication1.Class2' with data contract name
'Class2:http://schemas.datacontract.org/2004/07/WebApplication1' is not expected. Add
any types not known statically to the list of known types - for example, by using the
KnownTypeAttribute attribute or by adding them to the list of known types passed to
DataContractSerializer.'. Please see InnerException for more details.
Can anyone tell me how to add DataContract for a class defined outside the WCF service, and how to solve this problem.
Thanks a lot!
Add the lines below to your service interface declaration (add them just below the ServiceContract attribute):
[ServiceKnownType(typeof(Class1))]
[ServiceKnownType(typeof(Class2))]
alternatively, and this is the recommended approach, define your set of DTO objects exported by the service and decorate them with [DataContract] and [DataMember] attributes.