.NET Forum / Languages / C# / January 2008
problems with storing a custom type in application settings
|
|
Thread rating:  |
michael sorens - 30 Dec 2007 22:27 GMT 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" ?
Steven Cheng[MSFT] - 31 Dec 2007 04:06 GMT 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.
--------------------
>From: =?Utf-8?B?bWljaGFlbCBzb3JlbnM=?= <m_j_sorens@newsgroup.nospam> >Subject: problems with storing a custom type in application settings [quoted text clipped - 39 lines] >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" ? michael sorens - 31 Dec 2007 23:52 GMT 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?
michael sorens - 02 Jan 2008 23:15 GMT 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.
Steven Cheng[MSFT] - 03 Jan 2008 05:22 GMT 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.
--------------------
>From: =?Utf-8?B?bWljaGFlbCBzb3JlbnM=?= <m_j_sorens@newsgroup.nospam> >References: <03DCCB07-E2BD-46E1-9661-108F2A0B6534@microsoft.com> <zGOnaK2SIHA.6904@TK2MSFTNGHUB02.phx.gbl>
>Subject: RE: problems with storing a custom type in application settings >Date: Wed, 2 Jan 2008 15:15:02 -0800 [quoted text clipped - 7 lines] >an example or straightforward explanation of how to put a custom type into an >application setting and I have yet to find it. michael sorens - 03 Jan 2008 16:41 GMT 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.
Steven Cheng[MSFT] - 08 Jan 2008 02:35 GMT 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.
--------------------
>Subject: RE: problems with storing a custom type in application settings >Date: Thu, 3 Jan 2008 08:41:06 -0800 >Newsgroups: microsoft.public.dotnet.languages.csharp >X-Tomcat-NG: microsoft.public.dotnet.languages.csharp
>Let me back up to my earlier question that you skipped: >Wdoing either a TypeConverter or XmlSerializable, my app.config and [quoted text clipped - 50 lines] >klunky technique, to have to repeat the identical code for every class I want >to persist. michael sorens - 08 Jan 2008 15:50 GMT 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?
Kevin Spencer - 09 Jan 2008 12:22 GMT Hi Michael,
Your class instance needs to be serialized. See the following (and related) article:
http://msdn2.microsoft.com/en-us/library/ms171834.aspx
 Signature HTH,
Kevin Spencer Chicken Salad Surgeon Microsoft MVP
>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.: [quoted text clipped - 32 lines] > a > TypeConverter in this context? michael sorens - 09 Jan 2008 18:57 GMT 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>.) ====================================================
Steven Cheng[MSFT] - 10 Jan 2008 08:12 GMT 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.
-------------------- <eeVsdprUIHA.3940@TK2MSFTNGP05.phx.gbl>
>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 [quoted text clipped - 61 lines] ><ArrayOfX>.) >==================================================== Kevin Spencer - 10 Jan 2008 15:50 GMT 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.
 Signature HTH,
Kevin Spencer Chicken Salad Surgeon Microsoft MVP
> Hi Michael, > [quoted text clipped - 95 lines] >><ArrayOfX>.) >>==================================================== michael sorens - 11 Jan 2008 01:33 GMT (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.
Steven Cheng[MSFT] - 15 Jan 2008 03:17 GMT 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=?= <m_j_sorens@newsgroup.nospam> >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 [quoted text clipped - 9 lines] >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. michael sorens - 15 Jan 2008 22:00 GMT 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.
Steven Cheng[MSFT] - 16 Jan 2008 02:44 GMT 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.
--------------------
>Subject: Re: problems with storing a custom type in application settings >Date: Tue, 15 Jan 2008 14:00:03 -0800
>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.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|