none
Deserialization suddenly requires public setters - error not even in google

    Question

  • I've been happily sending objects back and forth between a Silverlight 2 test harness (so, hosted in IE) and a WCF service for weeks but after some refactoring on the server I now get an exception in the proxy generated classes imploring me to change one of my properties so its setter is public.

    But this is not how I understand WCF to work, it has always previously worked, I've made no changes to the data contract or its classes and when I reverse my changes, it doesn't fix it. I'm also skeptical as to why the error message is not in google/live.com - this forum post is an error message world first!

    The message and stack-trace are below. I'm 99% sure that setters do not need to be public because they are used via reflection in the data contract deseralizer. So what is going on?


    [DataMember(Order = 1)]

    public string IdFieldName { get; protected set; } // proof it has a setter




    {System.Security.SecurityException: The data contract type 'CompanyName.ProductName.Core.User.CustomerAccount' cannot be deserialized because the property 'IdFieldName' does not have a public setter. Adding a public setter will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. ---> System.Security.SecurityException: Security error.
       at System.Runtime.Serialization.CodeGenerator.DisallowMemberAccess(Boolean memberAccess)
       at System.Runtime.Serialization.CodeGenerator.BeginMethod(Type returnType, String methodName, Type[] argTypes, Boolean allowPrivateMemberAccess)
       at System.Runtime.Serialization.CodeGenerator.BeginMethod(String methodName, Type delegateType, Boolean allowPrivateMemberAccess)
       at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.GenerateClassReader(ClassDataContract classContract)
       --- End of inner exception stack trace ---
       at System.Runtime.Serialization.ClassDataContract.RequiresMemberAccessForRead(SecurityException securityException)
       at System.Runtime.Serialization.XmlFormatReaderGenerator.CriticalHelper.GenerateClassReader(ClassDataContract classContract)
       at System.Runtime.Serialization.XmlFormatReaderGenerator.GenerateClassReader(ClassDataContract classContract)
       at System.Runtime.Serialization.ClassDataContract.get_XmlFormatReaderDelegate()
       at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)
       at System.Runtime.Serialization.XmlObjectSerializerReadContext.ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader)
       at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, DataContract& dataContract)
       at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)
       at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName)
       at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName)
       at System.Runtime.Serialization.DataContractSerializer.ReadObject(XmlDictionaryReader reader, Boolean verifyObjectName)
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameter(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
       at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeBody(XmlDictionaryReader reader, MessageVersion version, String action, MessageDescription messageDescription, Object[] parameters, Boolean isRequest)
       at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeBodyContents(Message message, Object[] parameters, Boolean isRequest)
       at System.ServiceModel.Dispatcher.OperationFormatter.DeserializeReply(Message message, Object[] parameters)
       at System.ServiceModel.Dispatcher.ProxyOperationRuntime.AfterReply(ProxyRpc& rpc)
       at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
       at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
       at System.ServiceModel.ClientBase`1.ChannelBase`1.EndInvoke(String methodName, Object[] args, IAsyncResult result)
       at CompanyName.ProductName.Web.Silverlight.Gui.LocalUserService.UserServiceClient.UserServiceClientChannel.EndGetAccount(IAsyncResult result)
       at CompanyName.ProductName.Web.Silverlight.Gui.LocalUserService.UserServiceClient.CompanyName.ProductName.Web.Silverlight.Gui.LocalUserService.IUserService.EndGetAccount(IAsyncResult result)
       at CompanyName.ProductName.Web.Silverlight.Gui.LocalUserService.UserServiceClient.OnEndGetAccount(IAsyncResult result)
       at System.ServiceModel.ClientBase`1.OnAsyncCallCompleted(IAsyncResult result)}

    Tuesday, February 10, 2009 12:23 PM

Answers

  •  whole SilverLight code is partially trusted and so you are seeing this exception in SL and not in WPF.
    you can make your property internal and mark your dll (which contains your DC)  with the following attribute:
    [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization")]

    hopefully this should resolve the issue that you are seeing.
    Amit
    • Marked as answer by LukePuplett Wednesday, February 11, 2009 1:15 PM
    Wednesday, February 11, 2009 6:12 AM
    Moderator

All replies

  •  Hi,

    Any chance one of the refactoring was adding a DataContract attribute to your data class? where it didn't exist before, if so, this can change the way your classes are serialized.

    I assume the DataMember attribute didn't exist previously on this property?

    Currently, as long as your property has a protected set and it's marked as a DataMember, the class cannot be serialized.

    I don't see why this declaration worked before, if you add the class code that you had before, I might notice something you didn't.

    Ido.
    Tuesday, February 10, 2009 10:50 PM
  • Hi Ido

    I've actually rolled back my changes and the problem is still there. So it's really just 'decided' to behave differently.

    My WPF fat client still works fine, as I the documentation says it should, i.e. the deserialization engine will use internal or private setters because the magic is done via reflection.

    The Silverlight GUI assembly references a Core assembly that contains the entities and I tick the option to use types in referenced libraries. This Core library is also used on the server, so a CustomerAccount is deserialized back into the type it came from. Again, this setup worked before and still works in WPF.

    Using the .NET Reflector, I've opened up the MS function that seems to be raising the exception. In it, it makes reference to partially trusted checks.

    Of course, I'm stumped as to why this ever worked before, and indeed what it should act like. Does the Silverlight deserializer need public setters or not??

    One difference to note is that my WPF fat client test rig works, but it is also fully trusted because its local. I could run this rig from a non-trusted network location and see if this changes things.

    Also, I've trusted my own local site (just adding to Trusted Sites) but I'm not sure this is properly trusting. Either way, I'm surprised that no one else has ever raised this issue. Could MS have released a new SL client and fixed a security problem which allowed me to work before??

    Its a pain because I don't want these properties to be settable from outside their assembly, database IDs should not be overwritable, so I'm loath to make them all public.

    Luke

    P.S. thanks for being my soul response, I was feeling a bit neglected ;)
    • Edited by LukePuplett Tuesday, February 10, 2009 11:23 PM clarity
    Tuesday, February 10, 2009 11:08 PM
  •  whole SilverLight code is partially trusted and so you are seeing this exception in SL and not in WPF.
    you can make your property internal and mark your dll (which contains your DC)  with the following attribute:
    [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization")]

    hopefully this should resolve the issue that you are seeing.
    Amit
    • Marked as answer by LukePuplett Wednesday, February 11, 2009 1:15 PM
    Wednesday, February 11, 2009 6:12 AM
    Moderator


  • STOP PRESS (edit): I just restart VS and its all kicked in. I will now add the InternalsVisibleTo as you suggested and post back.


    Hi Amit

    I setup a new test service, a new SL2 app, etc. etc. and the problem still exists. So it seems that the previously working behaviour shouldn't have worked. I rolled back and tested the old XAP file on a different PC and get an exception stemming from Reflection.

    If I dissassemble the dll in my old XAP file I can see my old working code which used to display a value from the returned Account obj, and thinking about it, I reckon MS patch-Tuesday'd me and broke/fixed my application!! Anyway...


    Using my new test setup, I experimented with InternalsVisibleTo and it doesn't work. It seems the IDE and the compiler aren't in agreement: trying to set an internal setter results in a build error but my internal types do appear in intellisense; actually coding against them is erroneous.

    Before I apply the attribute and point it to the MS assembly, as you suggest, I would like to see it working between my two SL assemblies.


    'Entity.InternalType.InternalType()' is inaccessible due to its protection level 

    +

    The property or indexer 'Entity.SharedType.SomeData' cannot be used in this context because the set accessor is inaccessible

    And the line which is in my Silverlight "Entity.dll" assembly:

    [assembly: InternalsVisibleTo("SilverlightDeserializerNonPublicProps")]



    Thanks for your help,


    Luke
    • Edited by LukePuplett Wednesday, February 11, 2009 1:08 PM New information
    Wednesday, February 11, 2009 12:59 PM
  •  It's working!

            Thank you so much, Amit.



    Hey everyone: have you heard about Amit Sharma R? Really clever guy. Really clever.

    Wednesday, February 11, 2009 1:38 PM
  • one additional piece of information (though this not apply to your current scenario) -

    If you are using Json serializer then you will have to add the following 2 attributes to your assembly so that the internal members get serialized in partial trust

        [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.ServiceModel.Web")]
        [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization")]

    Amit
    Thursday, February 12, 2009 1:44 AM
    Moderator
  •  
    I am in exactly the same position. I was overjoyed to read this thread but unfortunately my problem did not, entirely, go away using the line:

    [assembly: InternalsVisibleTo("System.Runtime.Serialization")] 

    So let me outline the context.

    I have a silverlight class library that contains a simple class that looks, in part, like this:

     
    [DataContract]  
    public class Quote  
    {  
        [DataMember]   
        public string Symbol{ getprivate set; }  


        ... other code
    }  
     

    I then have a web app that references the silverlight class library and defines a a WCF service.  The service has the following method.

     
    public Quote GetQuote(string symbol)  
    {  
        var url = "http://someurl.com" 
        var quoteString = new WebClient().DownloadString(new Uri(url));  
        return Quote.Parse(quoteString);  
    }  
     


    Finally I have a silverlight app that also references the silverlight classlibrary and the WCF service (it is hosted by the web app). the silverlight application has the following event handlers:

     
    private void btnCreate_Click(object sender, RoutedEventArgs e)  
    {  
        this.WebAPI.GetQuoteAsync(this.txtSymbol.Text);  
    }  
     
    private void WebAPI_GetQuoteCompleted(object sender, GetQuoteCompletedEventArgs e)  
    {  
        this.txtQuote.Text = e.Result.ToString();  

    The e.Result.ToString() line is the same as saying Quote.ToString() because the return type of the service method is Quote. Anyway, when I run this code I get the dreaded error:

    'Quote' cannot be deserialized because the property 'Symbol' does not have a public setter. Adding a public setter will fix this error. 

    So following the instructions on this thread I have updated my silverlight class library so that the Quote class now looks like this

        
    [DataContract]     
    public class Quote     
    {     
        [DataMember]      
        public string Symbol{ getinternal set; }    
     
     
        ... other code   
    }     
     

    Note the property setter has been upgraded from private to internal. I don't want to do this because the setter really should be private, but needs must :-)

    I also add the InternalVisibleTo attribute to the AssemblyInfo.cs of the silverlight class library

     
    [assembly: InternalsVisibleTo("System.Runtime.Serialization")]   
     

    Now when I run the code I don't get the error, that is a good thing. However the Quote.Symbol property value just does not get set. Instead the Quote object is instantiated but the Symbol property value is string.Empty. If the property setter is made public then it works just fine.

    I have been tearing what is left of my hair out over this issue for ages. I really want to create immutable value objects (with readonly properties) but I fear that because of Silverlight deserialization I may be forced to keep the setters public.

    Any thoughts gratefully received. Thanks.

    biofractal


    Wednesday, March 25, 2009 2:27 PM
  • biofractal,

    I know that this post is over a year old, but did you happen to find a solution to your problem?

    Thanks.

    Tuesday, July 27, 2010 3:55 PM
  • In some cases it might be useful to check if the data is actually crossing the wire using Fiddler. It's easy to install and then look at the raw HTTP data being sent from the server. You can inspect the formatted XML version of the object very simply and see if the field value actually contains the data you expect.

    Tuesday, July 27, 2010 8:32 PM
  • I'm not sure how you guys made it work but it doesn't work for me.

    Here is what I've tried:
    I have
    [assembly: InternalsVisibleTo("System.Runtime.Serialization")]

    the class definition
    public class SampleData
    {
      public string Name
      {
       
    get; internal set;
      }
    }

    and I've tested it with:
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(SampleData));
    object data = xmlSerializer.Deserialize(new StringReader("<SampleData><Name>TestName</Name></SampleData>"));

    If I leave the setter public the property is set properly.
    Any help is appreciated.

    Thanks.

    Sunday, November 07, 2010 1:46 PM
  • You're using the wrong serializer. System.Runtime.Serialization is the DataContractSerializer type and you are using XmlSerializer.

    Switch to DataContractSerializer and it should work.


    Please mark posts as answers/helpful if it answers your question
    Sunday, November 07, 2010 2:33 PM