locked
Passing objects from/to WCF Service with "ExtensionData" field RRS feed

  • Question

  • User1514553073 posted

    I have been working with a WCF service that has implemented IExtensibleDataObject, and when I pass objects into my client-side script, the object has an "ExtensionData" field in it.  That's fine for passing the data in, but then when I try to pass that object back from the JS to a method in the service, it dies there.  The error I get is "No parameterless constructor defined for type of 'System.Runtime.Serialization.ExtensionDataObject'."

    We tried the class without implementing IExtensionDataObject but that we want to implement it for versioning reasons, and we tried decorating the ExtensionData property with [DataMember], but that just caused the service to fail altogether.

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p>Other than defining a new class that I can copy the object into and translate between client-side and service manually, is there something that can be done to the WCF service to enable the use of that object in outbound calls using AJAX?</o:p>

    The code for the type that's being passed is:

    public interface IWorkflow<o:p></o:p>
        {<o:p></o:p>
            int WorkflowId { get; set; }<o:p></o:p>
            int ObjectTypeId { get; set; }<o:p></o:p>
            string Name { get; set; }<o:p></o:p>
            string Description { get; set; }<o:p></o:p>
            List<Model.State> States { get; set; }<o:p></o:p>
            Model.ObjectType ObjectType { get; set; }<o:p></o:p>
            int PredecessorWorkflowId { get; set; }<o:p></o:p>
        }<o:p></o:p>
    <o:p> </o:p>
        [DataContract(Name = "Workflow",<o:p></o:p>
            Namespace = "http://www.[yaddaYadda].com/ model")]<o:p></o:p>
        public class Workflow : IWorkflow, IExtensibleDataObject<o:p></o:p>
        {<o:p></o:p>
            private int _workflowId;<o:p></o:p>
            private int _objectTypeId;<o:p></o:p>
            private string _name;<o:p></o:p>
            private string _description;<o:p></o:p>
            private int _predecessorWorkflowId;<o:p></o:p>
            private List<Model.State> _states;<o:p></o:p>
            private Model.ObjectType _objectType;<o:p></o:p>
    <o:p> </o:p>
            #region Properties<o:p></o:p>
            [DataMember]<o:p></o:p>
            public int WorkflowId<o:p></o:p>
            {<o:p></o:p>
                get { return _workflowId; }<o:p></o:p>
                set { _workflowId = value; }<o:p></o:p>
            }<o:p></o:p>
            [DataMember]<o:p></o:p>
            public int ObjectTypeId<o:p></o:p>
            {<o:p></o:p>
                get { return _objectTypeId; }<o:p></o:p>
                set { _objectTypeId = value; }<o:p></o:p>
            }<o:p></o:p>
            [DataMember]<o:p></o:p>
            public string Name<o:p></o:p>
            {<o:p></o:p>
                get { return _name; }<o:p></o:p>
                set { _name = value; }<o:p></o:p>
            }<o:p></o:p>
            [DataMember]<o:p></o:p>
            public string Description<o:p></o:p>
            {<o:p></o:p>
                get { return _description; }<o:p></o:p>
                set { _description = value; }<o:p></o:p>
            }<o:p></o:p>
            [DataMember]<o:p></o:p>
            public List<Model.State> States<o:p></o:p>
            {<o:p></o:p>
                get { return _states; }<o:p></o:p>
                set { _states = value; }<o:p></o:p>
            }<o:p></o:p>
            [DataMember]<o:p></o:p>
            public Model.ObjectType ObjectType<o:p></o:p>
            {<o:p></o:p>
                get { return _objectType; }<o:p></o:p>
                set { _objectType = value; }<o:p></o:p>
            }<o:p></o:p>
            [DataMember]<o:p></o:p>
            public int PredecessorWorkflowId<o:p></o:p>
            {<o:p></o:p>
                get { return _predecessorWorkflowId; }<o:p></o:p>
                set { _predecessorWorkflowId = value; }<o:p></o:p>
            }<o:p></o:p>
            #endregion<o:p></o:p>
    <o:p> </o:p>
            private ExtensionDataObject _extensionData;<o:p></o:p>
    <o:p> </o:p>
            public ExtensionDataObject ExtensionData<o:p></o:p>
            {<o:p></o:p>
                get { return _extensionData; }<o:p></o:p>
                set { _extensionData = value; }<o:p></o:p>
            }<o:p></o:p>
        }
     
    <o:p>Thanks!</o:p>
    Thursday, May 10, 2007 11:21 AM

All replies

  • User1514553073 posted

    Is there anyone here who can offer any assistance with this?  It would be greatly appreciated!

    Thanks!

    Friday, May 11, 2007 9:14 AM
  • User-332046507 posted
    I'm having the same issue. Help!?!
    Monday, May 14, 2007 2:33 PM
  • User336673788 posted
    Hmm you guys are ahead of me. I'm only half way through my WCF book. =) Sorry can't help at this moment.
    Monday, May 14, 2007 8:03 PM
  • User-332046507 posted

    The reason the error is occurring is because the serializer tries to call the default constructor of IExtensibleDataObject, which is internal to the class. It is also a sealed class, so you cannot override this behavior.



    The answer is to create a custom javascript serializer like below. This will ignore the ExtensionData object when it is serialized to the client, effectively removing it from the object. The downfall is that you cannot use the ExtensionData once the object has been re-serialized from the client.


    public class ExtensionDataObjectConverter : JavaScriptConverter
    {
            public override IEnumerable<Type> SupportedTypes
            {
                get
                {
                    return new ReadOnlyCollection<Type>(new Type[] {typeof (ExtensionDataObject)});
                }
            }
    
            public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
            {
                return null;
            }
    
            public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
            {
                throw new Exception("The method or operation is not implemented.");
            }
    }
    </Type></Type>


    <system.web.extensions><o:p></o:p>

        <scripting><o:p></o:p>

          <webServices><o:p></o:p>

            <jsonSerialization><o:p></o:p>

              <converters><o:p></o:p>

                <add name="ExtensionDataObjectConverter"<o:p></o:p>

                   type="Utilities.Serialization.ExtensionDataObjectConverter"/><o:p></o:p>

              </converters><o:p></o:p>

            </jsonSerialization><o:p></o:p>

          </webServices><o:p></o:p>

        </scripting><o:p></o:p>

      </system.web.extensions><o:p></o:p>

    Friday, November 9, 2007 5:46 PM
  • User1736562914 posted
     I just used this on the client side:
    1    		function DeleteExtensionData(obj) {
    2    			var keys = Object.keys(obj);
    3    
    4    			keys.each(function(key) {
    5    				if(!Object.isFunction(obj[key])) {
    6    					if(obj[key] instanceof Object) {
    7    						DeleteExtensionData(obj[key]);
    8    					}
    9    
    10   					if(key == "ExtensionData") {
    11   						delete obj[key];
    12   					}
    13   				}
    14   			});
    15   		}
    

     (it requires prototype (only because I'm already using it in my app))

     

    Tuesday, July 15, 2008 12:01 PM
  • User-1209230303 posted

    The below worked for me without using prototype. It was not a complex object though.

    delete obj['ExtensionData'];

    Monday, December 20, 2010 12:49 AM