I have built a WCF service library, I have added reference to few 3rd party dll's. This is my interface
[ServiceContract]
public interface IService1
{
[OperationContract]
3rdpartyreturntype GetObj(System.Windows.Controls.Control txtcontrol);
}
// Use a data contract as illustrated in the sample below to add composite types to service operations
[DataContract]
public class nclass
{
[DataMember]
public System.Windows.Controls.Control txtcontrol
{
get { return txtcontrol; }
set { txtcontrol = value; }
}
[DataMember]
public 3rdpartyreturntype nobj
{
get { return vuiobj; }
set { vuiobj = value; }
}
[DataMember]
public System.Windows.Input.TouchDevice tchdev
{
get { return tchdev; }
set { tchdev = value; }
}
}
and I have implemented the above interface. When I run the service I get the below error, can anyone help me out?
type 'System.Windows.Input.TouchDevice' cannot be serialized. Consider
marking it with the DataContractAttribute attribute, and marking all
of its members you want serialized with the DataMemberAttribute
attribute.
if you want a complex type like a class to be serialized you have to declare each of its members as data member and class as datacontract.
In this case touch device is the complex type(class) so you need to mark all of its members as datamembers and class as datacontract.
but as i can see from type that it belongs to system.windows.input the class may not be serialized. hence you cannot use this as a data member.
If you are using only a set of members belonging to touchDevice class, you can create your own class which will map only the set of touchdevice members which can be serialized. and decorate this new class with datacontract and datamember attributes.
It would appear that the type "System.Windows.Input.TouchDevice" is itself not marked as serializable or a DataContract.
Instead of trying to pass the TouchDevice and the Control directly like that, maybe you can just pass the properties you care about. I'm guessing in the case of the TextControl you just care about the Text value. And for the TouchDevice, maybe the source and target control name?
Related
I am using Stream object inside my wcf Contracts so forced to use MessageContract instead of DataContract.
[MessageContract]
public class Document
{
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileData;
}
[MessageContract]
public class A : Document
{
[MessageBodyMember]
public string input;
}
[MessageContract]
public class B : Document
{
[MessageBodyMember]
public string someProp;
}
[ServiceContract]
public interface ISomeService
{
[OperationContract]
Document SomeMethod(Document file);
}
I want the consumer of this service to create object of either A or B and call the service with it. On the service side, I can type cast it to proper object then perform some action.
Problem is I cannot specified KnownType with MessageContract and inherited contracts cannot be exposed to client until they are used in service or declared with KnownType.
I tried google it but couldn't find anything related to KnownType with MessageContract.
As suggested in comment... i updated my message contract with KnownType but they are still not exposed to client through service reference...
[MessageContract]
[KnownType(typeof(FileSystemStoredDocument))]
[KnownType(typeof(FileBoundStoredDocument))]
[KnownType(typeof(SharepointStoredDocument))]
public class Document : DocumentInfo, IDisposable
{
}
Can any one help me what's wrong here?
Note: ALL KnownType are inherited from Document
Message contracts describe exactly how the message should look like. They do support inheritance, but you must specify the exact message contract you're using in a specific operation.
If you check the body parts of the message:
ContractDescription.GetContract(typeof(ISomeService)).Operations[0].Messages[0].Body.Parts
You'll see exactly one part - a Stream object. That's in contrast to data contracts, where the body contains a part of the type Object. So you see why KnownType wouldn't work here.
(The ContractDescription class is used, among other things, to generate WSDL. See the WsdlExporter class.)
What you can do is create a hierarchy of data contracts that would be contained in the message contract, e.g.
[MessageContract]
public class Document
{
[MessageHeader]
public DocumentProperties Properties;
[MessageBodyMember(Order = 1)]
public System.IO.Stream FileData;
}
[DataContract]
[KnownType(typeof(A))]
[KnownType(typeof(B))]
public abstract class DocumentProperties { }
[DataContract]
public class A : DocumentProperties
{
[DataMember]
public string input;
}
[DataContract]
public class B : DocumentProperties
{
[DataMember]
public string someProp;
}
Note that you you cannot have more than one body member if you want to pass a Stream, so the rest of the properties must be in headers.
So, I have created a couple of WCF services. Each return lists of a certain type of data contract. However, these data contracts have list properties of other data contracts. I am trying to implement lazy-loading of data contract collections.
What I've thought of is to implement a class at the client that inherits from the data contract with collection properties overriden so the setter and getter methods call the service and get the actual collection items.
My question is: How can I make the base channel to return the class that implements the data contract instead of the actual data contract? how can I control what the base channel returns?
My service client looks like this:
public class ServiceClient : BaseClient<IServiceClient>
{
public IList<DataObject> FindAll()
{
// how to control what base.Channel.FindAll return during deserialization.
return base.Channel.FindAll();
}
}
Note that I don't want to do something like this:
public class ServiceClient : BaseClient<IServiceClient>
{
public IList<DataObject> FindAll()
{
var dtos = base.Channel.FindAll();
var dtoProxies = Mapper.Map<DataObject, DataObjectProxy>();
return dtoProxies;
}
}
I want a way so WCF automatically returns a List<DataObject> which elements are actually of type DataObjectProxy.
Any suggestions on how to do this?
Thanks!
EDIT: Sample DataObject class:
[DataContract]
public class DataObject
{
public virtual List<OtherDomainObject> SubItems { get; set; }
}
public class DataObjectProxy : DataObject
{
public override List<OtherDomainObject> SubItems
{
get { // Custom way to retrieve collection... }
set { // Etc.. }
}
}
First, decorate the DataObjectProxy with the [DataContract] attribute, WCF requires explicit contract identifications for all the types - no matter what you gonna do with them later. Then, set [DataMember] on each and every field (property in your case) of the data contract types that you want to expose to the client.
Finally, add [KnownType(typeof(DataObjectProxy))] attribute on the DataObject class. KnownType defines all sub-types of the given base for polymorphic substitutions on the client.
This should work.
[DataContract]
[KnownType(typeof(DataObjectProxy))]
public class DataObject
{
[DataMember]
public virtual List<OtherDomainObject> SubItems { get; set; }
}
[DataContract]
public class DataObjectProxy : DataObject
{
[DataMember]
public override List<OtherDomainObject> SubItems
{
get { // Custom way to retrieve collection... }
set { // Etc.. }
}
}
I am programming a Azure WCF application.
A datacontract defined as below:
[DataContract]
public class UserInfo
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public int UserID { get; set; }
[DataMember]
public bool IsOnline { get; set; }
}
then I define a datacontract in my WCF service:
[DataContract(Name="UserInfo")]
public class ServiceUserInfo : UserInfo
{
[IgnoreDataMember]
public ICallback Callback { get; set; }
}
Then in the service contract, it will callback to client, the method as below
private void NoticeUsers(UserInfo currentuser)
{
var users = UserManager.GetAllActiveUsers();
foreach (var user in users)
{
if (user.UserName == currentuser.UserName)
continue;
user.Callback.UpdateUserList(currentuser);
}
}
Actually I pass a ServiceUserInfo object as parameter to the NoticeUsers method. Then an error will occurs as below:
There was an error while trying to serialize parameter http://tempuri.org/:user. The InnerException message was 'Type 'WCFServiceWebRole.ServiceUserInfo' with data contract name 'UserInfo:http://schemas.datacontract.org/2004/07/WCFServiceWebRole' is not expected. Consider using a DataContractResolver 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 DataContractSerializer.'. Please see InnerException for more details.
I am not able to find solution for this issue.Please help.
I think I have found the root cause of the issue, however I do not know why.
The problem is caused by the Namespace attribute of the Service contract.
I didn't set the namespace of my service contract interface and data contract interface. I thought it would be set by default and it won't cause any problem. But actually the issue of this thread is caused by the Namespace attribute. I set a Namespace attribute for both service contract and data contract, of course the same namespace, then it worked. The problem never happens again.
However, I do not know why it caused this issue. If I do not set Namespace, it will be a default value of "http://tempuri.org", isn't it?
Ok so I have two objects that look like this in my WCF service. When my MyProfile property in my User class comes back to the client all of its properties are null; however, nothing else is.
[DataContract]
[Serializable]
public class User {
private WebProfile.UserTable _MyProfile;
public WebProfile.UserTable MyProfile {
get { return _MyProfile; }
set { _MyProfile = value; }
}
}
[DataContract]
[Serializable]
public class WebProfile {
[DataContract]
[Serializable]
public class UserTable {
}
}
On the WCF service it looks like this.
#region User Contract...
[ServiceContract]
public interface IUser {
List<User> GetAllUsers();
}
#endregion
public List<User> GetAllUsers() {
return _users;
}
I have only listed the property in question because I believe its specific to that property being in a subclass.
Here is what I have done. I have verified that the data is actually being obtained from the database on the service end from the database. Also, that MyProfile has values for its properties via Event Log.
When the client requests a list of Users I write to the event log on the server hosting the service to make sure MyProfile's properties have values. So the issue is either when the client deserializes the information or when the server serializes it to send to the client. Is it possible that my WebProfile class needs to be decorated with some type of attribute?
Again, I have verified that the User is coming back with values for all of its extra properties and that before the object leaves the server that the values are populated.
Any suggestions?
None of the class's properties for said object were decorated with the [DataMember] attribute.
This is one of the classes in Interface file.
[DataContract]
public class ClassX
{
public ClassX()
{
ClassXParameters = new List<ClassXParameter>();
}
public void Add(string name, string value)
{
ClassXParameters.Add(new ClassXParameter() { Name = name, Value = value });
}
[DataMember]
public List<ClassXParameter> ClassXParameters { get; set; }
}
[DataContract]
public class ClassXParameter
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Value { get; set; }
}
on the client I'm trying to do something like this
ClassX classx = new ClassX();
classx.Add("testname", "testvalue");
But this .Add method is not even visible.
currently I'm doing
ClassX classx = new ClassX();
List<ClassXParameter> params = new List<ClassXParameter()>;
params.add(new ClassXParameter() {Name="testname", Value="testvalue"});
classx.ClassXParameters = params;
Is there anyway I can do what I'm trying to do?
Note: I am not sure why some of the text above are in bold.
If you autogenerate the client code from scratch, it will generate a new class, which contains those members and properties that are marked with DataContract.
If you have methods that you want available on the client, you can accomplish this by putting the DataContract types in an own assembly, which you reference from both the server and the client. When you generate the service reference you have to choose the option to reuse existing classes instead of generating new ones.
Often it is suitable to put data validation rules in the data contract classes property setters. Reusing the data contract assembly in the client will cause the data validation to occur directly on the client, without the need for a roundtrip. It also causes the error in a place where it is much easier to spot than if it is reported as deserialization error.
Data Contracts are for data only. Any methods will not be visible on the client.
The bold was because of the "-----".