problems with storing a custom type in application settings

M

michael sorens

I have worked with application settings in VS2005 and C# for awhile, but
usually with standard types. I have been trying to store a custom
container/class/type in an application setting and I have seen erratic
results. I am aware of one known defect where user classes do not show up in
the list of types on the Property/Settings page in the visual designer and I
am wondering if I am encountering some other peculiar issue, or if there are
just tricks to using it properly.

I defined my setting on the Property/Settings page by selecting "browse"
then typing in my class name myNamespace.InfoContainerList, which is
basically just this:

public class InfoContainerList : List<InfoContainer>
{ // empty--just needed to give a name to the List.
}
public class InfoContainer : ICloneable
{
private string configName;
private string configSetting;
private bool typeA;
private bool rememberPassword;
. . .
}

I first let the program generate a value for this setting into the
user.config, then I copied that setting value into app.config in VS, assuming
it would propagate it to where it needed to go. When I re-opened the
Property/Settings page however, it complained that the value in app.settings
had changed to '' (the empty string) and did I want to propage that to the
Settings file. The value on the Property/Settings page was, in fact, an empty
string.
For my second attempt, I went to the value field, clicked the ellipsis, and
got a value wizard/builder that let me add instances of InfoContainer on the
left, and give values to each field on the right. I saved/closed the Property
pages and re-opened... and got the same complaint, and the value field was
again empty.

So what is the proper way to provide a default value to a custom type so
that it propagates where it needs to and it "sticks" ?
 
S

Steven Cheng[MSFT]

Hi Michael,

As for the .NET 2.0 application settings properties, if you want to use
custom class/type, you need to implement either of the following persistent
means for the c ustom type:

** provide a TypeConverter(implement FromSTring and ToString ) for it

** or you can make it XmlSerialiable

Here are some web FAQ and threads discussing on this, you may have a look
to get some further ideas:

#Client Settings FAQ
http://blogs.msdn.com/rprabhu/articles/433979.aspx

#How to save custom collections using ApplicationSettingsBase?
http://www.thescripts.com/forum/thread477600.html


Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================


This posting is provided "AS IS" with no warranties, and confers no rights.



--------------------
 
M

michael sorens

I understand what you are saying, but what I observed does not quite agree
with that. Without doing either a TypeConverter or XmlSerializable, I was
able to make it work: Once I compile with a value in app.config, the
application works just fine. It was only when I reopened the Property/Setting
page in VS that I had some "flaky" behavior. Comments?
 
M

michael sorens

Additional comments:
On the chance that you will tell me that the flakiness I have observed is
caused by the lack of TypeConverter/XmlSerializable, I tried to read up on
those topics. Frankly, the documentation on both of these topics is not at
all conducive to the simple task I am trying to accomplish. That includes
both the links you provided plus my own searches through MSDN. What I need is
an example or straightforward explanation of how to put a custom type into an
application setting and I have yet to find it.
 
S

Steven Cheng[MSFT]

Hi Michael,

As mentioned in the FAQ article, one means is implementing a TypeConverter
for the custom type. Here is a simple example:

=========================
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.ComponentModel;



namespace TypeLib
{
[TypeConverter(typeof(MySettingTypeConverter))]
[SettingsSerializeAs( SettingsSerializeAs.String)]
public class MySettingType
{
private string _name;
private string _path;
private bool _enabled;

public string Name
{
get { return _name; }
set { _name = value; }
}

public string Path
{
get { return _path; }
set { _path = value; }
}

public bool Enabled
{
get { return _enabled; }
set { _enabled = value; }
}

public MySettingType()
{ }

public MySettingType(string n, string p, bool e)
{
_name = n; _path = p; _enabled = e;
}

}

public class MySettingTypeConverter :TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context,
Type sourceType)
{
if(sourceType == typeof(string)) return true;

return base.CanConvertFrom(context, sourceType);
}



public override object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value)
{
if (value.GetType() == typeof(string))
{
MySettingType mst = new MySettingType();

string str = value as string;
if (str != null)
{
str = str.Trim();

string[] props = str.Split(new char[] { ',' },
StringSplitOptions.None);
mst.Name = props[0];
mst.Path = props[1];
mst.Enabled = bool.Parse(props[2]);
}

return mst;
}
else return base.ConvertFrom(context, culture, value);
}

public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type
destinationType)
{
if (destinationType == typeof(string))
{
string str = string.Empty;

MySettingType mst = value as MySettingType;
if (mst != null)
{
str = string.Format("{0},{1},{2}", mst.Name, mst.Path,
mst.Enabled.ToString());
}
return str;
}
else return base.ConvertTo(context, culture, value,
destinationType);

}
}
}

===========================

the ConvertTo ,From method make you able to edit the type in designer.
Also, for complex type, you can consider using xml serialization in the
typeconverter.


Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
 
M

michael sorens

Let me back up to my earlier question that you skipped:
Wdoing either a TypeConverter or XmlSerializable, my app.config and
user.config files are working *fine* during program execution. That is, my
simple InfoListContainer class...

public class InfoContainerList : List<InfoContainer>
{ // empty--just needed to give a name to the List.
}
public class InfoContainer : ICloneable
{
private string configName;
private string configSetting;
private bool typeA;
private bool rememberPassword;
. . .
}

persists as a nicely organized XML structure in user.config thusly:

<setting name="ConfigList" serializeAs="Xml">
<value>
<ArrayOfInfoContainer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<InfoContainer>
<ConnectionString>User ID=foo;Data Source=asb</ConnectionString>
<ConfigName>Default</ConfigName>
<DbType>SqlServer</DbType>
<RememberPassword>false</RememberPassword>
</InfoContainer>
<InfoContainer>
<ConnectionString>User ID=;Dsn=informaticaSource</ConnectionString>
<ConfigName>myodbc</ConfigName>
<DbType>Odbc</DbType>
<RememberPassword>false</RememberPassword>
</InfoContainer>
<InfoContainer>
<ConnectionString>User ID=a;Data Source=asb</ConnectionString>
<ConfigName>new-ora</ConfigName>
<DbType>Oracle</DbType>
<RememberPassword>false</RememberPassword>
</InfoContainer>
</ArrayOfInfoContainer>
</value>
</setting>

My only issue is that I cannot seem to set a default value in the Settings
Page of the Property Designer. Why is it working at runtime if you say it
should not be? And why am I having design-time issues?

BTW, I still do not follow the use of the TypeConverter from your
uncommented code sample. What do I need to change except the string
"MySettingType" ? If that is the only thing, that sure seems like a very
klunky technique, to have to repeat the identical code for every class I want
to persist.
 
S

Steven Cheng[MSFT]

Hi Michael,

Yes, for runtime accessing and writing, XML serialization is good. However,
the design-time editing in designer is depend on the "TypeConverter". This
is just like you provide a custom type that need to be editable in winform
project's "Property window". You need to implement the ToString and
FromString method of the TypeConverter. For complex case, you may also
need to implement a type editor which will require more work. Such topic is
more related to winform design-time developing.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.


--------------------
 
M

michael sorens

I looked back at my previous post and found that one vital word was somehow
lost: The first word of the second sentence was "without", i.e.:
"Without doing either a TypeConverter or XmlSerializable, my app.config and
user.config files are working *fine* during program execution."

So if I may beg your indulgence to answer the question in the now context
that it was supposed to be (sorry about that:). Again, here's my summary:

Runtime: I am *not* doing any XML serialization but it is working fine just
the same.

Designtime: I am *not* doing any type converter, but when I click the
ellipsis in the value field of the property designer page, I *do* get a
correct wizard/dialog that lets me add my objects, defining each of their
fields. The only problem is that this is not carried back to the value field
when I close the dialog. Will this be fixed if I use the type converter? But
one more issue with it: if I just paste in a complete XML into the same value
field for the property, it immediately disappears if I click on a different
setting. Will this be fixed if I use the type converter?

Finally, as to implementing a typeconverter we are still not communicating.
You provided a link to a FAQ that states what you have, i.e. use to/from
string. You gave an example piece of code, for which I stated I do not follow
what I am supposed to customize or not--and by the way it does *not*
implement the to/from string. The MSDN page on the TypeConverter class is
also of little help to me. Do you have any other information on how to use a
TypeConverter in this context?
 
M

michael sorens

I am sure that the link to the Designer Serialization Overview would be
helpful to someone who is more familiar with serialization; regrettably it
was not helpful to me. However, based on your confirming comment that
serialization is what I want, I did yet another web search for how to use
serialization with property settings and came up with one reference
(http://www.15seconds.com/issue/020903.htm) that gave me some concrete clues.
Based on that, I present my final solution here for two reasons: (1) to help
others who might find it useful; (2) to have it vetted by the experts in case
I missed something that might trip me up down the road.
====================================================
Goal: To store a collection of a custom type X into app.config and
user.config that may be created and manipulated in the property designer of
Visual Studio 2005.

My solution:
(1) Define a wrapping type for the collection that is completely empty; it
serves only to give a name to the collection.

public XCollection: Collection<X> { }

(2) Define the type X as a serializable type with appropriate properties:

[Serializable]
public class X : ISerializable
{
private string myProperty1;
private bool myProperty2;
private int myProperty3;
. . .
}

(3) Implement the ISerializable interface by adding a GetObjectData method.
This method should include AddValue calls for each property. So the
definition of X is now:

[Serializable]
public class X : ISerializable
{
private string myProperty1;
private bool myProperty2;
private int myProperty3;
. . .

public void GetObjectData(SerializationInfo info, StreamingContext
context)
{
info.AddValue("MyProperty1", myProperty1);
info.AddValue("MyProperty2", myProperty2);
info.AddValue("MyProperty3", myProperty3);
. . .
}
}

(4) Build the project.

(5) Open the Settings page of the Property Designer and create a new
setting. Select the type XCollection by opening the browse dialog then just
typing in the fully qualified name (e.g. myNamespace.x.y.XCollection). Click
on the Value field which will then display an ellipsis button. Clicking the
ellipsis opens a collection editor allowing one to add or remove X objects
from this XCollection. Upon closing the collection editor, an XML-serialized
version of the XCollection is now present in the Value field and the
app.config. (Curiously, the app.config file shows the root element as
<ArrayOfX>.)
====================================================
 
S

Steven Cheng[MSFT]

Hi Michael,

The reason it works at runtime if you do not do anything particular is
because your custom type is serializable(without explicit implementing
serialization stuffs).

However, for design-time IDE editing(in property window or in application
setting designer), you need to implement TypeConverter. Just like you need
to make the "PropertyWindow" be able to let you edit a custom type in
property window (assign new value and save it).

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.


--------------------
Subject: Re: problems with storing a custom type in application settings
Date: Wed, 9 Jan 2008 10:57:04 -0800
I am sure that the link to the Designer Serialization Overview would be
helpful to someone who is more familiar with serialization; regrettably it
was not helpful to me. However, based on your confirming comment that
serialization is what I want, I did yet another web search for how to use
serialization with property settings and came up with one reference
(http://www.15seconds.com/issue/020903.htm) that gave me some concrete clues.
Based on that, I present my final solution here for two reasons: (1) to help
others who might find it useful; (2) to have it vetted by the experts in case
I missed something that might trip me up down the road.
====================================================
Goal: To store a collection of a custom type X into app.config and
user.config that may be created and manipulated in the property designer of
Visual Studio 2005.

My solution:
(1) Define a wrapping type for the collection that is completely empty; it
serves only to give a name to the collection.

public XCollection: Collection<X> { }

(2) Define the type X as a serializable type with appropriate properties:

[Serializable]
public class X : ISerializable
{
private string myProperty1;
private bool myProperty2;
private int myProperty3;
. . .
}

(3) Implement the ISerializable interface by adding a GetObjectData method.
This method should include AddValue calls for each property. So the
definition of X is now:

[Serializable]
public class X : ISerializable
{
private string myProperty1;
private bool myProperty2;
private int myProperty3;
. . .

public void GetObjectData(SerializationInfo info, StreamingContext
context)
{
info.AddValue("MyProperty1", myProperty1);
info.AddValue("MyProperty2", myProperty2);
info.AddValue("MyProperty3", myProperty3);
. . .
}
}

(4) Build the project.

(5) Open the Settings page of the Property Designer and create a new
setting. Select the type XCollection by opening the browse dialog then just
typing in the fully qualified name (e.g. myNamespace.x.y.XCollection). Click
on the Value field which will then display an ellipsis button. Clicking the
ellipsis opens a collection editor allowing one to add or remove X objects
from this XCollection. Upon closing the collection editor, an XML-serialized
version of the XCollection is now present in the Value field and the
app.config. (Curiously, the app.config file shows the root element as
<ArrayOfX>.)
====================================================
 
K

Kevin Spencer

I have been working on a similar problem, and following this thread fairly
closely. In my case, I want to keep a typed Collection of objects which have
several other custom types nested in them, and some of these are structures.

One of the things I found most difficult in solving my problem was a bug I
finally discovered in Visual Studio 2008, with regards to the Settings
Designer. Apparently due to some caching mechanism, it doesn't always
identify changes to custom classes when you rebuild and attempt to add an
instance to the Settings Designer. Once I figured this out, solving the rest
of the issues was fairly trivial. My solution to dealing with the bug was to
close and re-open Visual Studio any time I made a change to any of the
classes I wanted to serialize into the Settings. This worked well, as it
cleared whatever cache was being used. I believe it was a caching issue, but
it may have been a result of some error state in the Designer which was not
resolved when the Solution was rebuilt.

I found that the parent class in the Collection only needed to be marked as
Serializable, as it was readily serializable as XML. An oddity of the
Settings Designer is that it will not serialize a custom class that is not
marked as Serializable, even though XmlSerializer will. After marking this
class, and the several other classes and structures in it as Serializable, I
found that I did have to implement a TypeConverter for each nested class or
structure (nested as a property or field of the parent class) in order for
the Settings Designer to serialize it. This was also odd, as my experience
has shown that the XmlSerializer will serialize the class types without
TypeConverters. To rephrase, the top-level class did not need a
TypeConverter, nor did any of them need to implement ISerializable. But any
class nested as a property of the top-level class DID need a TypeConverter
to be serialized in the Settings Designer.

In addition, I wish that XML Serialization of structures was documented in
the .Net Framework SDK. Although it mentions structs in passing is several
articles, it never explicitly explains how to serialize them as XML, which
was troublesome to me, as a structure cannot have a parameterless
constructor defined (it is implied), and the Framework requires a
parameterless constructor for a class to serialize it. So, in essence, the
documentation is totally ambiguous regarding this issue.

--
HTH,

Kevin Spencer
Chicken Salad Surgeon
Microsoft MVP

Steven Cheng said:
Hi Michael,

The reason it works at runtime if you do not do anything particular is
because your custom type is serializable(without explicit implementing
serialization stuffs).

However, for design-time IDE editing(in property window or in application
setting designer), you need to implement TypeConverter. Just like you need
to make the "PropertyWindow" be able to let you edit a custom type in
property window (assign new value and save it).

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no
rights.


--------------------
Subject: Re: problems with storing a custom type in application settings
Date: Wed, 9 Jan 2008 10:57:04 -0800
I am sure that the link to the Designer Serialization Overview would be
helpful to someone who is more familiar with serialization; regrettably it
was not helpful to me. However, based on your confirming comment that
serialization is what I want, I did yet another web search for how to use
serialization with property settings and came up with one reference
(http://www.15seconds.com/issue/020903.htm) that gave me some concrete clues.
Based on that, I present my final solution here for two reasons: (1) to help
others who might find it useful; (2) to have it vetted by the experts in case
I missed something that might trip me up down the road.
====================================================
Goal: To store a collection of a custom type X into app.config and
user.config that may be created and manipulated in the property designer of
Visual Studio 2005.

My solution:
(1) Define a wrapping type for the collection that is completely empty; it
serves only to give a name to the collection.

public XCollection: Collection<X> { }

(2) Define the type X as a serializable type with appropriate properties:

[Serializable]
public class X : ISerializable
{
private string myProperty1;
private bool myProperty2;
private int myProperty3;
. . .
}

(3) Implement the ISerializable interface by adding a GetObjectData method.
This method should include AddValue calls for each property. So the
definition of X is now:

[Serializable]
public class X : ISerializable
{
private string myProperty1;
private bool myProperty2;
private int myProperty3;
. . .

public void GetObjectData(SerializationInfo info, StreamingContext
context)
{
info.AddValue("MyProperty1", myProperty1);
info.AddValue("MyProperty2", myProperty2);
info.AddValue("MyProperty3", myProperty3);
. . .
}
}

(4) Build the project.

(5) Open the Settings page of the Property Designer and create a new
setting. Select the type XCollection by opening the browse dialog then just
typing in the fully qualified name (e.g. myNamespace.x.y.XCollection). Click
on the Value field which will then display an ellipsis button. Clicking the
ellipsis opens a collection editor allowing one to add or remove X objects
from this XCollection. Upon closing the collection editor, an XML-serialized
version of the XCollection is now present in the Value field and the
app.config. (Curiously, the app.config file shows the root element as
<ArrayOfX>.)
====================================================
 
M

michael sorens

(1) So if I understand you correctly, Kevin, then in my solution (posted Jan
9) for a custom type with only primitive types within, I need only keep the
[Serializable] attribute and I could remove the ISerializable implementation,
is that right?

(2) From my attempt at understanding TypeConverters, it looks like they
output just a string representation rather than XML. I suppose one could use
a TypeConverter to manually create an XML representation but that seems quite
kludgy; implementing ISerializable, on the other hand, does "automatically"
create XML which seems a much more elegant approach. So why would one ever
want to use a TypeConverter for outputting to the settings file (which is
XML) ? It sounds like both you and Steven are saying it is preferable, but
(in my current level of ignorance) I do not yet grok how or why.
 
S

Steven Cheng[MSFT]

Hi Michael,

For your two questions:

1) Yes, if you can make sure your classes can be binary serialized(by only
applying the [Serializable] attribute), you can certainly avoid
implementing the ISerializable interface. This is true not only for
application settings case, but also for any cases that need to use custom
classes require binary serialization.

2) I agree that Xml Serialization is good and make the representation
formal and the string representation of TypeConverter is not quite useful
for runtime. However, this is the requirement and restriction of dealing
with custom type in Visual Studio IDE, for any type you need to deal with
in IDE desiger(property window), you need to at least implement a
TypeConverter so that you can edit it via string based value.

I've found a web article provide some detailed information on design-time
support in Visual studio:

http://blogs.msdn.com/gurbir/archive/2007/03/16/vs-net-2005-design-time-inte
gration.aspx

it mentioned Designer, TypeConverter and UITypeEditor for custom types,
note the following comments in it:

===============
The VS.Net property grid allows the configuration of property values at
design-time. Since the property browser allows entering only the string
values, therefore there should be some mechanism to convert these string
values to the appropriate data type of the property. This mechanism is
provided by Type Converters.
================

that's why you have to implement the Typeconverter as VS property browser
only support string based editing (for complex or non-built-in type ....).

If you want to provide rich support of design-time editing for your custom
types, you may consider implementing a custom UITypeEditor which is also
mentioned in the above article.

The following link give you more ideas about custom Type Editor:

#User Interface Type Editors
http://msdn2.microsoft.com/en-us/library/ms171838.aspx

#Walkthrough: Implementing a UI Type Editor
http://msdn2.microsoft.com/en-us/library/ms171840.aspx

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.

--------------------
From: =?Utf-8?B?bWljaGFlbCBzb3JlbnM=?= <[email protected]>
Subject: Re: problems with storing a custom type in application settings
Date: Thu, 10 Jan 2008 17:33:03 -0800
(1) So if I understand you correctly, Kevin, then in my solution (posted Jan
9) for a custom type with only primitive types within, I need only keep the
[Serializable] attribute and I could remove the ISerializable implementation,
is that right?

(2) From my attempt at understanding TypeConverters, it looks like they
output just a string representation rather than XML. I suppose one could use
a TypeConverter to manually create an XML representation but that seems quite
kludgy; implementing ISerializable, on the other hand, does "automatically"
create XML which seems a much more elegant approach. So why would one ever
want to use a TypeConverter for outputting to the settings file (which is
XML) ? It sounds like both you and Steven are saying it is preferable, but
(in my current level of ignorance) I do not yet grok how or why.
 
M

michael sorens

I learned a few interesting things from your first link, including finally
getting straight that TypeConverters are really for the on-screen editing
portion while the XML serializer is for storing in the config file. Thanks
for the tips.
 
S

Steven Cheng[MSFT]

Thanks for the followup.

Yes, all we talk about here are specific to .NET/VS design-time support
which is really complex sometimes(since sometimes many interfaces are not
quite documented). Anyway, glad to be of assistance.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top