hello I have WCF service with webHttpEndpointBehavior under Sitecore 6 and I use Glass Mapper to read items, Glass mapper has depends on Castle library.
It is working well, but i have some methods with Contract like:
[OperationContract]
[WebInvoke(Method = "POST",BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
List<Shade> GetAllShades(int columns, int rows);
where I try return list of my class in JSON format,
during debug my service with SvcTraceViewer.exe I find out next error:
There was an error while trying to serialize parameter
:GetFamilyShadesResult. The InnerException message was 'Type
'Castle.Proxies.ShadeProxy' with data contract name
'ShadeProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies' 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.
How to resole this issue? Castle.Proxies.ShadeProxy is a dynamic class under Castle and I can't use KnownTypeAttribute.
Actually if I JSON.net library and return results as string everything works fine.
I assume you have a class that links to other classes loaded via Glass, e.g.
[SitecoreClass]
public class Shade{
[SitecoreField]
public virtual IEnumerable<AnotherClass> SomeField{get;set;}
[SitecoreChildren]
public virtual IEnumerable<AnotherClass> Children{get;set;}
}
[SitecoreClass]
public class AnotherClass{}
To allow lazy loading of classes Glass uses proxies generated by Castle, so at runtime when the classes are loaded into the SomeField property you actually get a sub-class of the AnotherClass class.
To resolve this you have to explicitly tell class to load the other classes as concrete types, updating the SitecoreField attribute should fix this problem:
[SitecoreClass]
public class Shade{
[SitecoreField(Setting=SitecoreFieldSettings.DontLazyLoad)]
public virtual IEnumerable<AnotherClass> SomeField{get;set;}
[SitecoreChildren(IsLazy=false)]
public virtual IEnumerable<AnotherClass> Children{get;set;}
}
[SitecoreClass]
public class AnotherClass{}
Related
This is my ABC on the server side:
<endpoint address="msmq.formatname:DIRECT=OS:.\private$\imhmsgs"
binding="msmqIntegrationBinding"
bindingConfiguration="IncomingMessageHandlerBinding"
contract="TMC.Services.Contracts.Messages.IInboundMessageHandlerService">
As soon as I do an .Open() to host the service, I get the exception:
Cannot serialize interface
XYZ.Services.Contracts.Messages.Interfaces.IMyMessage.
My IMyMessage interface:
[ServiceContract]
[ServiceKnownType(typeof(IMyMessage))]
[ServiceKnownType(typeof(ConcreteMessage))]
public interface IInboundMessageHandlerService
{
[OperationContract(IsOneWay = true, Action = "*")]
void ProcessIncomingMessage(MsmqMessage<IMyMessage> incomingMessage);
}
The implementor for that interface:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple,
ReleaseServiceInstanceOnTransactionComplete = false)]
public class InboundMessageHandlerService : IInboundMessageHandlerService
{
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void ProcessIncomingMessage(MsmqMessage<IMyMessage> incomingMessage)
{
}
}
The type that is being created by the client basically is a concrete class, which derives from a base class and also an interface (IMyMessage) and then places this on the MSMQ.
After some testing, if I remove the service known type attributes and just instead use say "string" instead, then it seems to open the host but faults (because the message type is not what it was expecting).
where am I going wrong?
On further testing I see that if I only specify the concrete type, it works.
This is not quite what I was expecting.
how am I able to create it so that the service can take a known interface and classes which that interface has? The idea is for the client (using the same contract and classes) to send the message as "IMyMessage" and for the WCF service to pick that up as "IMyMessage" and go ahead and find out the type of message/object it is.
How?
Your contract is an interface, but the definition within the contract must be concrete classes.
In your case it looks like you want to send over a list of things, those things could be different but they all support the same interface.
The problem is that when WCF deserialises what has been sent over the wire, it needs to deserialise it the a concrete type. If it just has an interface in the definition and 20 different types that implement that definition, it does not know what to do with it.
What you can do is have a base type that implements the interface, all your classes inherit from the base type and you use the base type in your contact.
Fairly new to WCF and need help with understanding why serialisation is not working correctly.
Service definition - I just want to post, serialise into a LogDeviceCommunication object and then just return the object as a simple test
[OperationContract]
[WebInvoke(UriTemplate = "AddDeviceCommunicationLog", RequestFormat =
WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare, Method = "POST")]
LogDeviceCommunication AddDeviceCommunicationLog(LogDeviceCommunication
deviceCommunicationEntry);
public LogDeviceCommunication AddDeviceCommunicationLog(LogDeviceCommunication
deviceCommunicationEntry)
{
return deviceCommunicationEntry;
}
At the moment I am just posting the following XML with Fiddler as a test.
<?xml version="1.0" encoding="UTF-8"?>
<LogDeviceCommunication>
<ID>1207a26e-ab59-4977-b7eb-b2776205cffe</ID>
<DeviceID>A42E8707-7C65-45AA-8E58-5D21F53DA101</DeviceID>
<Time>2012-03-14T15:38:28.379Z</Time>
<Line>0</Line>
<Tab>0</Tab>
<Info>Starting Synchronisation</Info>
</LogDeviceCommunication>
Results returned from Fiddler
<LogDeviceCommunication z:Id="i1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<ChangeTracker z:Id="i2"
xmlns:a="http://schemas.datacontract.org/2004/07/conxEntities">
<a:ExtendedProperties/>
<a:ObjectsAddedToCollectionProperties/>
<a:ObjectsRemovedFromCollectionProperties/>
<a:OriginalValues/>
<a:State>Added</a:State>
</ChangeTracker>
<DeviceID>00000000-0000-0000-0000-000000000000</DeviceID>
<ID>1207a26e-ab59-4977-b7eb-b2776205cffe</ID>
<Info i:nil="true"/>
<Line i:nil="true"/>
<Tab i:nil="true"/>
<Time>2012-03-14T15:38:28.379Z</Time>
</LogDeviceCommunication>
Why does the DeviceID contain the 0000's (I assume it's a null Guid) while the ID contains the correct Guid; also why do the Info, Line and Info elements contain nil values?
The LogDeviceCommunication is a POCO generated from EF4 using the ADO.NET Self Tracking Template
Condensed version is
[DataContract(IsReference = true, Namespace = "")]
public partial class LogDeviceCommunication: IObjectWithChangeTracker,
INotifyPropertyChanged
[DataMember]
public System.Guid DeviceID
[DataMember]
public System.DateTime Time
[DataMember]
public Nullable<int> Line
[DataMember]
public Nullable<int> Tab
[DataMember]
public string Info
[DataMember]
public System.Guid ID
I am sure I am doing something incorrectly so any help appreciated.
The problem lies in the required ordering of the XML.
WCF Datacontract, some fields do not deserialize
http://neimke.blogspot.co.nz/2012/03/serialization-ordering-causes-problems.html
When WCF receives your request, its deserialization machinery will create a new instance of the LogDeviceCommunication type to populate with the values it receives. It seems that the code from the EF partial class of your instance is being triggered and it results in what you post in your question.
Try setting a debugger break point on the return statement in your AddDeviceCommunicationLog method to see what EF & WCF deserialized for you. If it's just as what you posted then the issue is likely caused by the EF plumbing code. Also, you may want to enable WCF message tracing to see what WCF is actually receiving and sending back.
EDIT: Just ran across this blog post that shows some of the interaction between EF & WCF. You may want to review it to see if it's applicable to your issue.
I bet the other parts of the class, generated by that template, include the elements you're seeing.
In general, it's not a good idea to return EF entities (or any complex .NET type) from a web service - they drag along implementation dependencies. Return a purely POCO class as a DTO instead.
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.
I have a really simple customized collection type that inherits from List<> and uses a CollectionDataContract.
When I use DataContractSerializer.WriteObject to serialize it, it respects the CollectionDataContract attribute the way I'd expect; however, when I use it as a return type for a WCF method, I get the default ArrayOfFoo.
I'm wondering if there is some decoration I'm missing in the service contract.
Details:
[DataContract(Namespace = "")]
public class Foo
{
[DataMember]
public string BarString { get; set; }
}
[CollectionDataContract(Namespace = "")]
[Serializable]
public class FooList : List<Foo> {}
If I just instantiate a Foo and then use DataContractSerializer.WriteObject to serialize it, I get what you'd expect:
<FooList>
<Foo>
<BarString>myString1</BarString>
</Foo>
</FooList>
However, if I have a service with a method like this...
[ServiceContract Name = "MyService"]
public interface IMyService
{
[OperationContract, WebGet(UriTemplate = "foos/")]
FooList GetAllFoos();
}
and then do a GET for http://www.someEndpoint.com/foos/, I get this:
<ArrayOfFoo>
<Foo>
<BarString>myString1</BarString>
</Foo>
</ArrayOfFoo>
I've also tried specifying Name="MyFooListName" in the CollectionDataContract attribute. Same results: DataContractSerializer gets the memo; WCF doesn't.
Saeed sent me in the right direction: I inadvertently ended up with XmlSerializer, when I had been hoping for DataContractSerializer.
I had ended up with XmlSerializer... well... by asking for it.
In particular, I had decorated methods in my service with the XmlSerializerFormat like this:
[ServiceContract Name = "MyService"]
public interface IMyService
{
// ... other stuff ...
[OperationContract, WebInvoke(UriTemplate = "foos/", Method = "POST")]
[XmlSerializerFormat]
Foo PostAFoo(Foo yourNewFoo);
}
I had done this in the hopes of forgiving member order in hand-rolled Foo XML blobs. Of course, when one does this one ends up with XmlSerializer, not DataContractSerializer.
When I take away the XmlSerializerFormat attribute, problem solved: WCF is now serializing my FooList collection the way I want.
See MSDN for detail:
The DataContractSerializer does not
support the programming model used by
the XmlSerializer and ASP.NET Web
services. In particular, it does not
support attributes like
XmlElementAttribute and
XmlAttributeAttribute. To enable
support for this programming model,
WCF must be switched to use the
XmlSerializer instead of the
DataContractSerializer.
So the serialization going to be done by XMLSerializer, and you can't change it.
Have you selected Generic types while configuring your WCF service? if not then,
right click and go to configuration, then select Generic Type, by default it is arraylist type.
I have a WCF service and I'm sharing types with a client in a shared assembly.
If the client create a derived class will it be possible to pass back the derived type to the service so that I can read the added properties through reflection ?
I tried but having issues with KnownTypes since the service don't know how to deserialize the derived type.
[Serializable]
public abstract class Car : ICar
{........
//on the client :
[Serializable]
public class MyCar : Car
{......
when passing myCar to Service I get the exception complaining about knownType but I cant add this on the server since I wont know what the client will be sending through and I want to handle extra properties through reflection.
Possible to register client types as knowntypes at runtime ?
Is this maybe the solution ?
http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx
This is not possible. Both service and client has to know what types will be sent in messages. If you want to use known type you have to define that relation to parent type on the service.
Why do you need to know added properties on the server?
I think there is a way.
I vaguely remember that when I studied WCF, I met ExtensionData which should be a mechanism to get everything that does not match the serialization of the class. for example, if you enable ExtensionData and you are in this situation
//Server
public class GenericRQ
{
public string GenericProperty {get;set;}
}
public Service GenericService
{
Public void GenericMethod(GenericRQ RQ)
{
}
}
// client
Public class MoreSpecificRQ : GenericRQ
{
public string SpecificProperty {get;set;}
}
At
Public void GenericMethod(GenericRQ RQ)
{
// the serializer adds automatically in RQ.ExtensionData everything that has come and that does not match the class GenericRQ.
}
On how to enable ExtensionData you to easily search on the web