views:

32

answers:

1

I have to serialize several objects inheriting from WebControl for database storage. These include several unecessary (to me) properties that I would prefer to omit from serialization. For example BackColor, BorderColor, etc.

Here is an example of an XML serialization of one of my controls inheriting from WebControl.

<Control xsi:type="SerializePanel">
        <ID>grCont</ID>
        <Controls />
        <BackColor />
        <BorderColor />
        <BorderWidth />
        <CssClass>grActVid bwText</CssClass>
        <ForeColor />
        <Height />
        <Width />
        ...
      </Control>

I have been trying to create a common base class for my controls that inherits from WebControl and uses the "xxxSpecified" trick to selectively choose not to serialize certain properties.

For example to ignore an empty BorderColor property, I'd expect

[XmlIgnore]    
public bool BorderColorSpecified()
{
    return !base.BorderColor.IsEmpty;
}

to work, but it's never called during serialization.

I've also tried it in the class to be serialized as well as the base class.

Since the classes themselves might change, I'd prefer not to have to create a custom serializer. Any ideas?

Edit:

I was already using XmlAttributeOverrides though apparently incorrectly. I didn't realize you couldn't specify a base class. I tweaked my routine, but it is still not working. Here are some more details of the things I've tried.

I have WebControl named Activity, that has a ContainerPanel (inherits Panel) which contains several controls of type SerializePanel (also inherits Panel).

Attempt 1 I added the [XmlIgnore] attributes to new properties of SerializePanel has no effect. The property is still included in serialization.

//This is ignored
[XmlIgnore]
public new System.Drawing.Color  BackColor{
get {  return base.BackColor;   }
set { }}

Attempt 2 I also tried the *Specified in the declaration of SerializePanel, but it was ignored

public bool BackColorSpecified
    {
        get { return !base.BackColor.IsEmpty; }
    }

Attempt 3 Then in the serializer I passed the overrides created here:

XmlAttributeOverrides overrides = new XmlAttributeOverrides();

string[] serPAnelProps = { "BackColor", "BorderColor", "ForeColor", "Site", "Page", "Parent", "TemplateControl", "AppRelativeTemplateSourceDirectory" };
foreach (string strAttr in serPAnelProps)
{
    XmlAttributes ignoreAtrs = new XmlAttributes();
    ignoreAtrs.XmlIgnore = true;
    overrides.Add(typeof(SerializePanel), strAttr, ignoreAtrs);
}

string[] ignoreProps = { "Site", "Page", "Parent", "TemplateControl", "AppRelativeTemplateSourceDirectory" };
foreach (string strAttr in ignoreProps)
{
    XmlAttributes ignoreAtrs = new XmlAttributes();
    ignoreAtrs.XmlIgnore = true;
    overrides.Add(typeof(System.Web.UI.Control), strAttr, ignoreAtrs);
}

Note: The attribute additions to the System.Web.UI.Control type are necessary in order to be able to serialize a Control.

The resulting XML snippet is for each attempt was

<Activity....>
...
<ContainerPanel>
      <ID>actPnl_grAct207_0</ID> 
    - <Controls>
    - <Control xsi:type="SerializePanel">
      <ID>grCont</ID> 
      <Controls /> 
      <BackColor /> 
      <BorderColor /> 
      <BorderWidth /> 
      <CssClass>grActVid</CssClass> 
      <ForeColor /> 
      <Height /> 
      <Width /> 
      <WidthUnitType>Pixel</WidthUnitType> 
      <HeightUnitType>Pixel</HeightUnitType> 
      <WidthUnit>0</WidthUnit> 
      <HeightUnit>0</HeightUnit> 
      </Control>
...
A: 

XXXSpecified has to be a property, not a method :

public bool BorderColorSpecified
{
    get { return !base.BorderColor.IsEmpty; }
}

Also, the XmlIgnore attribute is unnecessary, since read-only property are not serialized (and anyway it was a method in your code)

Alternatively, you can use a ShouldSerializeXXX method instead of a XXXSpecified property


EDIT:

According to Marc's answer, the XXXSpecified trick won't work here...

However, there's another option available to you : the XmlAttributeOverrides class. This allows you to customize the serialization without changing the code of the class :

XmlAttributeOverrides overrides = new XmlAttributeOverrides();

// Ignore the BackColor property
XmlAttributes attributesBackColor = new XmlAttributes();
attributesBackColor.XmlIgnore = true;
overrides.Add(typeof(WebControl), "BackColor", attributesBackColor);

// do the same for other properties to ignore...

XmlSerializer xs = new XmlSerializer(typeof(YourControl), overrides);

This approach is probably better, because you don't need to create a common base class for your controls. Also, you don't need to pollute your classes with new public members that serve no purpose except serialization

Thomas Levesque
@Thomas. I really appreciate your insights. Unfortunately I'm still having issues that I suspect are related to the fact that I have nested controls, though it's just a hunch at this point. I wonder if you might lend an eye to what's still wrong. Please see question edit.
Laramie
@Laramie, you need to specify the attribute for the type on which the property is defined. For instance, BackColor is defined in WebControl, not in Control. So you must write `overrides.Add(typeof(WebControl), strAttr, ignoreAtrs)`
Thomas Levesque
@Thomas. That makes perfect sense. Works great for all objects inheriting WebControl, but I still don't see a way of selectively choosing which types that inherit WebControl should have their properties serialized. If I create a **public new System.Drawing.Color BackColor** property on an inheriting type like SerializePanel and set **overrides.Add(typeof(SerializePanel), "BackColor", ignoreAtrs)** BackColor is still serialized.
Laramie