Initial commit
[mono.git] / mcs / class / referencesource / System / sys / system / configuration / SettingsPropertyValue.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SettingsPropertyValue.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Configuration {
8     using  System.Collections;
9     using  System.Collections.Specialized;
10     using  System.Runtime.Serialization;
11     using  System.Configuration.Provider;
12     using  System.Globalization;
13     using  System.IO;
14     using System.Runtime.Serialization.Formatters.Binary;
15     using System.Xml.Serialization;
16     using System.ComponentModel;
17     using System.Security.Permissions;
18     using System.Reflection;
19     using System.Runtime.Versioning;
20
21     //////////////////////////////////////////////////////////////////////////////////
22     //////////////////////////////////////////////////////////////////////////////////
23     public class SettingsPropertyValue
24     {
25         public string Name                  { get { return _Property.Name; } }
26         public bool   IsDirty               { get { return _IsDirty; } set { _IsDirty = value; }}
27         public SettingsProperty Property    { get { return _Property; } }
28
29         public bool UsingDefaultValue { get { return _UsingDefaultValue; } }
30
31         public SettingsPropertyValue(SettingsProperty property)
32         {
33             _Property = property;
34         }
35
36         public object PropertyValue
37         {
38             get
39             {
40                 if (!_Deserialized)
41                 {
42                     _Value = Deserialize();
43                     _Deserialized = true;
44                 }
45
46                 if (_Value != null && !Property.PropertyType.IsPrimitive && !(_Value is string) && !(_Value is DateTime))
47                 {
48                     _UsingDefaultValue = false;
49                     _ChangedSinceLastSerialized = true;
50                     _IsDirty = true;
51                 }
52
53                 return _Value;
54             }
55             set
56             {
57                 _Value = value;
58                 _IsDirty = true;
59                 _ChangedSinceLastSerialized = true;
60                 _Deserialized = true;
61                 _UsingDefaultValue = false;
62             }
63         }
64
65         public object SerializedValue
66         {
67             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
68             get {
69                 if (_ChangedSinceLastSerialized) {
70                     _ChangedSinceLastSerialized = false;
71                     _SerializedValue = SerializePropertyValue();
72                 }
73                 return _SerializedValue;
74             }
75             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
76             set {
77                 _UsingDefaultValue = false;
78                 _SerializedValue = value;
79             }
80         }
81
82         public bool Deserialized
83         {
84             get { return _Deserialized; }
85             set { _Deserialized = value; }
86         }
87
88         [ResourceExposure(ResourceScope.None)]
89         [ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
90         private bool IsHostedInAspnet() {
91             // See System.Web.Hosting.ApplicationManager::PopulateDomainBindings
92             return AppDomain.CurrentDomain.GetData(".appDomain") != null;
93         }
94
95         private object Deserialize()
96         {
97             object val = null;
98             //////////////////////////////////////////////
99             /// Step 1: Try creating from Serailized value
100             if (SerializedValue != null)
101             {
102                 try {
103                     if (SerializedValue is string) {
104                         val = GetObjectFromString(Property.PropertyType, Property.SerializeAs, (string)SerializedValue);
105                     } else {
106                         MemoryStream ms = new System.IO.MemoryStream((byte[])SerializedValue);
107                         try {
108                             val = (new BinaryFormatter()).Deserialize(ms);
109                         } finally {
110                             ms.Close();
111                         }
112                     }
113                 } 
114                 catch (Exception exception) { 
115                     try {
116                         if (IsHostedInAspnet()) {
117                             object[]    args = new object[] { Property, this, exception};
118
119                             const string webBaseEventTypeName = "System.Web.Management.WebBaseEvent, " +  AssemblyRef.SystemWeb;
120                             
121                             Type type = Type.GetType(webBaseEventTypeName, true);
122                             
123                             type.InvokeMember("RaisePropertyDeserializationWebErrorEvent",
124                                 BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.InvokeMethod, 
125                                 null, null, args, CultureInfo.InvariantCulture);
126                         }
127                     }
128                     catch {
129                     }
130                 }
131
132                if (val != null && !Property.PropertyType.IsAssignableFrom(val.GetType())) // is it the correct type
133                     val = null;
134             }
135
136             //////////////////////////////////////////////
137             /// Step 2: Try creating from default value
138             if (val == null)
139             {
140                 _UsingDefaultValue = true;
141                 if (Property.DefaultValue == null || Property.DefaultValue.ToString() == "[null]") {
142                     if (Property.PropertyType.IsValueType)
143                         return SecurityUtils.SecureCreateInstance(Property.PropertyType);
144                     else
145                         return null;
146                 }
147                 if (!(Property.DefaultValue is string)) {
148                     val = Property.DefaultValue;
149                 } else {
150                     try {
151                         val = GetObjectFromString(Property.PropertyType, Property.SerializeAs, (string)Property.DefaultValue);
152                     } catch(Exception e) {
153                         throw new ArgumentException(SR.GetString(SR.Could_not_create_from_default_value, Property.Name, e.Message));
154                     }
155                 }
156                 if (val != null && !Property.PropertyType.IsAssignableFrom(val.GetType())) // is it the correct type
157                     throw new ArgumentException(SR.GetString(SR.Could_not_create_from_default_value_2, Property.Name));
158             }
159
160             //////////////////////////////////////////////
161             /// Step 3: Create a new one by calling the parameterless constructor
162             if (val == null)
163             {
164                 if (Property.PropertyType == typeof(string)) {
165                     val = "";
166                 } else {
167                     try {
168                         val = SecurityUtils.SecureCreateInstance(Property.PropertyType);
169                     } catch {}
170                 }
171             }
172
173             return val;
174         }
175
176         private static object GetObjectFromString(Type type, SettingsSerializeAs serializeAs, string attValue)
177         {
178             // Deal with string types
179             if (type == typeof(string) && (attValue == null || attValue.Length < 1 || serializeAs == SettingsSerializeAs.String))
180                 return attValue;
181
182             // Return null if there is nothing to convert
183             if (attValue == null || attValue.Length < 1)
184                 return null;
185
186             // Convert based on the serialized type
187             switch (serializeAs)
188             {
189                 case SettingsSerializeAs.Binary:
190                     byte[]          buf = Convert.FromBase64String(attValue);
191                     MemoryStream    ms  = null;
192                     try {
193                         ms = new System.IO.MemoryStream(buf);
194                         return (new BinaryFormatter()).Deserialize(ms);
195                     } finally {
196                         if (ms != null)
197                             ms.Close();
198                     }
199
200                 case SettingsSerializeAs.Xml:
201                     StringReader    sr = new StringReader(attValue);
202                     XmlSerializer   xs = new XmlSerializer(type);
203                     return xs.Deserialize(sr);
204
205                 case SettingsSerializeAs.String:
206                     TypeConverter converter = TypeDescriptor.GetConverter(type);
207                     if (converter != null && converter.CanConvertTo(typeof(String)) && converter.CanConvertFrom(typeof(String)))
208                         return converter.ConvertFromInvariantString(attValue);
209                     throw new ArgumentException(SR.GetString(SR.Unable_to_convert_type_from_string, type.ToString()), "type");
210
211                 default:
212                     return null;
213             }
214         }
215
216         private object SerializePropertyValue()
217         {
218             if (_Value == null)
219                 return null;
220
221             if (Property.SerializeAs != SettingsSerializeAs.Binary)
222                 return ConvertObjectToString(_Value, Property.PropertyType, Property.SerializeAs, Property.ThrowOnErrorSerializing);
223
224             MemoryStream ms = new System.IO.MemoryStream();
225             try {
226                 BinaryFormatter bf = new BinaryFormatter();
227                 bf.Serialize(ms, _Value);
228                 return ms.ToArray();
229             } finally {
230                 ms.Close();
231             }
232         }
233
234
235         private static string ConvertObjectToString(object propValue, Type type, SettingsSerializeAs serializeAs, bool throwOnError)
236         {
237             if (serializeAs == SettingsSerializeAs.ProviderSpecific) {
238                 if (type == typeof(string) || type.IsPrimitive)
239                     serializeAs = SettingsSerializeAs.String;
240                 else
241                     serializeAs = SettingsSerializeAs.Xml;
242             }
243
244             try {
245                 switch (serializeAs) {
246                 case SettingsSerializeAs.String:
247                     TypeConverter converter = TypeDescriptor.GetConverter(type);
248                     if (converter != null && converter.CanConvertTo(typeof(String)) && converter.CanConvertFrom(typeof(String)))
249                         return converter.ConvertToInvariantString(propValue);
250                     throw new ArgumentException(SR.GetString(SR.Unable_to_convert_type_to_string, type.ToString()), "type");
251                 case SettingsSerializeAs.Binary :
252                     MemoryStream ms = new System.IO.MemoryStream();
253                     try {
254                         BinaryFormatter bf = new BinaryFormatter();
255                         bf.Serialize(ms, propValue);
256                         byte[] buffer = ms.ToArray();
257                         return Convert.ToBase64String(buffer);
258                     } finally {
259                         ms.Close();
260                     }
261
262                 case SettingsSerializeAs.Xml :
263                     XmlSerializer xs = new XmlSerializer(type);
264                     StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
265
266                     xs.Serialize(sw, propValue);
267                     return sw.ToString();
268                 }
269             } catch (Exception) {
270                 if (throwOnError)
271                     throw;
272             }
273             return null;
274         }
275
276         private object  _Value              = null;
277         private object  _SerializedValue    = null;
278         private bool    _Deserialized       = false;
279         private bool    _IsDirty            = false;
280         private SettingsProperty _Property  = null;
281         private bool    _ChangedSinceLastSerialized = false;
282         private bool _UsingDefaultValue = true;
283     }
284 }