Cannot return a CollectionContext from a WCF RESTful service

Posted by Community Admin on 04-Aug-2018 19:42

Cannot return a CollectionContext from a WCF RESTful service

All Replies

Posted by Community Admin on 14-Dec-2010 00:00

In your Sitefinity Convention Assurance documentation regrading creation of WCF RESTful services (Sitefinity 4.0), you state:

For every OperationContract (web service method) that retrieves a collection of items, return an object of type CollectionContext<T>, where you pass the type of the resource as a generic argument.

When I try to return a CollectionContext I get the following error:

Telerik.Sitefinity.Web.Services.CollectionContext`1[InstaOrderOpenAccess.EsfManufacturer] cannot be serialized because it does not have a parameterless constructor.

This error makes sense as the CollectionContext object does not have a parameterless constructor.

How do I return a CollectionContext object in my WCF service?

Thanks

- Courtney

P.S. Your online SiteFinity 4.0 RC Developer's Guide that talks about each of the Client Binder Controls (where I thought i might find an answer to this in an example) has links to sample code that do not work:

http://www.sitefinity.com/40/help/developer-manual/a3c3e363-2b58-4ac6-8c6b-d3c05171cb87.html

Article sample code: (broken link)
http://sitefinity.com/4.0/help/CodeExamples/RadGridBinderRead.zip

Posted by Community Admin on 15-Dec-2010 00:00

Hello Courtney,

 I am sorry that the documentation has been misleading.

The collection context does not need to have a constructor without parameters, as the family of DataContractSerialzier-s use FormatterServices.GetUninitializedObject when Type.GetConstructor( Type.EmptyTypes ) returns null/Nothing.

This exception could be caused when you are not using a WCF service or for some reason it does not use XmlObjectSerializer.

Here are some instructions on how to find out what's wrong:

  • Make sure that your .svc looks like this:
    1.<%@ ServiceHost
    2.    Language="C#"
    3.    Debug="true"
    4.    Service="Telerik.Sitefinity.Modules.News.Web.Services.NewsItemService"
    5.    Factory="Telerik.Sitefinity.Web.Services.WcfHostFactory"
    6. %>
  • Make sure that your interface looks something like this: (notice the attributes
    [ServiceContract(Namespace = "ContentService")]
    [AllowDynamicFields]
    public interface IContentService<TContent, TContentViewModel>
         where TContent : SfModel.Content
         where TContentViewModel : ContentViewModelBase
         [OperationContract]
         [WebGet(UriTemplate = "/?sortExpression=sortExpression&skip=skip&take=take&filter=filter&provider=providerName&workflowOperation=workflowOperation", ResponseFormat = WebMessageFormat.Json)]
         CollectionContext<TContentViewModel> GetContentItems(string sortExpression, int skip, int take, string filter, string providerName, string workflowOperation);
            
  • Make sure that your service class has these attributes:
    /// <summary>
    /// The WCF web service that is used to work with all types that inherit from base <see cref="Content"/>
    /// class.
    /// </summary>
    [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public abstract class ContentServiceBase<TContent, TParentContent, TContentViewModel, TParentContentViewModel, TContentManager> : IContentService<TContent, TContentViewModel>
        where TContent : Content
        where TParentContent : Content
        where TContentViewModel : ContentViewModelBase
        where TParentContentViewModel : ContentViewModelBase
        where TContentManager : class, IManager, IContentLifecycleManager<TContent>
  • Make sure that your collection item has an empty constructor:
    /// <summary>
    /// View model class for the <see cref="NewsItem"/> model.
    /// </summary>
    public class NewsItemViewModel : ContentViewModelBase
        /// <summary>
        /// Initializes a new instance of the <see cref="NewsItemViewModel"/> class.
        /// </summary>
        public NewsItemViewModel()
            : base()
        
        
  • Make sure that you use DataMember and DataContract attributes in you collection item - see how and see the difference of using and not using them

If you haven't found the problem after completing those steps, here is what we will need to troubleshoot this for you:

  • The full stack trace of the exception
  • Version of Telerik.Sitefinity.Model.dll
  • The contents of your .svc file
  • The code for your service class and/or interface
  • The code for your model class (obviously EsfManufacturer) - and any classes part of its definition, recursively
  • The way to reproduce this error (e.g. call service with that url, query string, http verb, and optionally that JSON)

Kind regards,
Dido
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 15-Dec-2010 00:00

Dido, thanks for your reply.  I tried all of your suggestions but I still got the same error message:

Telerik.Sitefinity.Web.Services.CollectionContext`1[InstaOrderOpenAccess.TestManufacturer] cannot be serialized because it does not have a parameterless constructor.


After a lot of trial and error, we have discovered the source of the problem.

(Sorry I cannot seem to highlight my text like you were somehow able to!)

[ServiceContract]
public interface IManufacturerService
 
    [OperationContract]
    [WebHelp(Comment =
"Get all test manufacturers")] 
    [WebGet(UriTemplate =  "/test/?sort=sort&skip=skip&take=take&filter=filter"
ResponseFormat = WebMessageFormat.Json)] 
    CollectionContext<TestManufacturer> GetTestManufacturers(string sort,  int skip, int take, string filter);     

    [OperationContract] 
    [XmlSerializerFormat()]
    [WebHelp(Comment = "Get all test 
manufacturers")]
    [WebGet(UriTemplate = 
"/test/xml/?sort=sort&skip=skip&take=take&filter=filter"ResponseFormat = WebMessageFormat.Xml)]  
    
CollectionContext<TestManufacturer> GetTestManufacturersInXml(string sort, int skip, int take, string filter);
    
    [OperationContract] 
    [WebGet(UriTemplate = "/id", BodyStyle = WebMessageBodyStyle.Bare,  ResponseFormat =WebMessageFormat.Json)]    
    TestManufacturer 
GetManufacturer(string id);

    [OperationContract]
    [XmlSerializerFormat()]
    [WebGet(UriTemplate =
"/xml/id", BodyStyle = 
WebMessageBodyStyle.Bare, ResponseFormat= WebMessageFormat.Xml)] 
    TestManufacturer GetManufacturerInXml(string id);

The problem is with the second defined method, GetTestManufacturersInXml.

As suggested in the documentation, I have been creating two methods for each resource to be returned.  One method,  returns Json and the other method returns Xml (with the URITemplate having the extra piece of the path "/xml").

Naturally, I had created two methods to return all manufacturers: The first method, GetTestManufacturers, returned a List<TestManufacturer> in Json and the second method, GetTestManufacturersInXml, returned a List<TestManufacturer> in Xml format.  These are the first two methods in the code sample above.

I then wanted to bind the results of the GetTestManufacturers method to a RadGridBinder control, so I changed the original return type of GetTestManufacturers and  GetTestManufacturersInXml from List<TestManufacturer> to CollectionContext<TestManufacturer>.

This is where the error was introduced.  Apparently you cannot have a method that returns its data in Xml format to return a class of type CollectionContext<>.  The mere existence of such a method causes all methods to fail. 

When I commented out the GetTestManufacturersInXml method, everything started working.

- Courtney

Posted by Community Admin on 16-Dec-2010 00:00

Hi Courtney,

 Without having the code to "play with", I can only suggest that you do remove the XmlSerializerFormat attribute.

Also, I would like to emphasize that we support DataContract serialization only, and XmlSerializer is not exactly tested. They are slightly different and obviously use different serializers:


That does not mean, however, that you cannot use XML as an output of your services. That's what's the purpose of the WebGet and WebInvoke attributes' ResponseFormat property is.

All the best,
Dido
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

This thread is closed