10

I've got a LINQ 2 SQL generated class I'd like to expose through a webservice. There are some internal properties I don't want to be available.

Normally I'd throw [XmlIgnore] in there but because the properties are in the generated half I can't do that.

I've been looking at using MetadataType following this post which looks like it should allow me to define the property attributes in another class.

My code looks something like this:

[MetadataType(typeof(ProspectMetaData))]
public partial class Prospect : ApplicationBaseObject
{
}

public class ProspectMetaData
{
     [XmlIgnore]
     public object CreatedDateTime { get; set; }

     [XmlIgnore]
     public object AmendedDateTime { get; set; }

     [XmlIgnore]
     public object Timestamp { get; set; }
}

I'm referencing this through an ASP.NET Web Service from a Silverlight Project.

The issue is that the [XmlIgnore] attributes are being ignored, those properties are being sent through.

Does anyone have any insight into what might be going wrong here? and what might be the best way to do this?

Community
  • 1
  • 1
Tristan Warner-Smith
  • 9,631
  • 6
  • 46
  • 75

3 Answers3

12

You can do this by passing your own XmlAttributeOverrides to the XmlSerializer, in the XmlAttributeOverrides you can change the XmlIgnore to true for the fields/properties you wish without touching the DBML generated code and it works like a charm, use the same overrides to deserialize as well...

Refer this link for more information

    // Create the XmlAttributeOverrides and XmlAttributes objects.
    XmlAttributeOverrides xOver = new XmlAttributeOverrides();

    XmlAttributes attrs = new XmlAttributes();
    attrs.XmlIgnore = true;

    /* Setting XmlIgnore to true overrides the XmlIgnoreAttribute
        applied to the following fields. Thus it will be serialized.*/
    xOver.Add(typeof(Prospect), "CreatedDateTime", attrs);
    xOver.Add(typeof(Prospect), "AmendedDateTime", attrs);
    xOver.Add(typeof(Prospect), "Timestamp", attrs);

    XmlSerializer xSer = new XmlSerializer(typeof(Prospect), xOver);
    TextWriter writer = new StreamWriter(outputFilePath);
    xSer.Serialize(writer, object);
Ash
  • 657
  • 9
  • 16
  • Is there a way to do this for the Newtonsoft.Json JSON serializer? – Dave Feb 03 '15 at 21:21
  • @Dave, I am not familiar with Newtonsoft.Json to comment, if it is derived from XmlSerializer then you may be able to... The main reason I use XmlIgnore is to avoid circular reference, it seems that Newtonsoft.Json has some [settings](http://www.newtonsoft.com/json/help/html/SerializationSettings.htm) to avoid that. – Ash May 03 '15 at 01:42
4

AFAIK, MetadataTypeAttribute is not supported by XmlSerializer (although it would be nice - I've simply never checked). And as you say, you can't add member attributes in a partial class.

One option may be to make the generated properties non-public (private, protected or internal) - and name it something like TimestampStorage (etc) - then re-expose them (in the partial class) on the public API:

 [XmlIgnore]
 public object Timestamp {
     get {return TimestampStorage; }
     set {TimestampStorage = value; }
 }
 // and other properties

(since XmlSerializer only looks at the public API). The biggest problem here is that LINQ-to-SQL queries (Where etc) will only work against the generated columns (TimestampStorage etc). I've used this approach before with the member as internal, allowing my DAL class to use the internal property... but it is a bit of a fudge.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • It certainly seems that way and it's a real shame. I have no control over the accessors on the generated properties so it doesn't really solve it for me. I guess I'll just have to go with a proxy class rather than sending my business objects. – Tristan Warner-Smith Jun 10 '09 at 14:23
  • You must reset the access levels upon regeneration. :( –  Jan 19 '11 at 22:38
  • Thanks for the clue. 12 years later and `XmlSerializer` *still* does not support `MetadataTypeAttribute`. – Mike Finch May 24 '21 at 20:28
1

I agree with Marc. The easiest thing to do is mark them internal. Optionally, you can then re-expose them in the partial class with [XmlIgnore]. BTW, You can control the accessibility of the properties in the linq2sql designer. Get at the properties dialog and you'll see a place to set them

Erik Mork
  • 1,443
  • 9
  • 10
  • We're actually using our own code generation tools to output the generated halves, when I said LINQ2SQL, it's the closest parallel. This might be handy for others though. +1 – Tristan Warner-Smith Jun 11 '09 at 12:15