PageRenderTime 41ms CodeModel.GetById 17ms app.highlight 18ms RepoModel.GetById 2ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.Runtime.Serialization.Internal/Microsoft/Runtime/Serialization/DataContractSet.cs

#
C# | 485 lines | 430 code | 45 blank | 10 comment | 95 complexity | f94dfb67b7d9e44e757ae7f415e2641c MD5 | raw file
  1//------------------------------------------------------------
  2// Copyright (c) Microsoft Corporation.  All rights reserved.
  3//------------------------------------------------------------
  4
  5namespace Microsoft.Runtime.Serialization
  6{
  7    using System;
  8    using System.Collections;
  9    using System.Collections.Generic;
 10    using System.Diagnostics.CodeAnalysis;
 11    using System.Runtime.Serialization;
 12    using System.Text;
 13    using System.Xml;
 14    using Microsoft.Server.Common;
 15    using DataContractDictionary = System.Collections.Generic.Dictionary<System.Xml.XmlQualifiedName, DataContract>;
 16
 17    internal class DataContractSet
 18    {
 19        Dictionary<XmlQualifiedName, DataContract> contracts;
 20        Dictionary<DataContract, object> processedContracts;
 21        IDataContractSurrogate dataContractSurrogate;
 22        Hashtable surrogateDataTable;
 23        DataContractDictionary knownTypesForObject;
 24        ICollection<Type> referencedTypes;
 25        ICollection<Type> referencedCollectionTypes;
 26        Dictionary<XmlQualifiedName, object> referencedTypesDictionary;
 27        Dictionary<XmlQualifiedName, object> referencedCollectionTypesDictionary;
 28
 29
 30        internal DataContractSet(IDataContractSurrogate dataContractSurrogate) : this(dataContractSurrogate, null, null) { }
 31
 32        internal DataContractSet(IDataContractSurrogate dataContractSurrogate, ICollection<Type> referencedTypes, ICollection<Type> referencedCollectionTypes)
 33        {
 34            this.dataContractSurrogate = dataContractSurrogate;
 35            this.referencedTypes = referencedTypes;
 36            this.referencedCollectionTypes = referencedCollectionTypes;
 37        }
 38
 39        internal DataContractSet(DataContractSet dataContractSet)
 40        {
 41            if (dataContractSet == null)
 42                throw Fx.Exception.AsError(new ArgumentNullException("dataContractSet"));
 43
 44            this.dataContractSurrogate = dataContractSet.dataContractSurrogate;
 45            this.referencedTypes = dataContractSet.referencedTypes;
 46            this.referencedCollectionTypes = dataContractSet.referencedCollectionTypes;
 47
 48            foreach (KeyValuePair<XmlQualifiedName, DataContract> pair in dataContractSet)
 49            {
 50                Add(pair.Key, pair.Value);
 51            }
 52
 53            if (dataContractSet.processedContracts != null)
 54            {
 55                foreach (KeyValuePair<DataContract, object> pair in dataContractSet.processedContracts)
 56                {
 57                    ProcessedContracts.Add(pair.Key, pair.Value);
 58                }
 59            }
 60        }
 61
 62        Dictionary<XmlQualifiedName, DataContract> Contracts
 63        {
 64            get
 65            {
 66                if (contracts == null)
 67                {
 68                    contracts = new Dictionary<XmlQualifiedName, DataContract>();
 69                }
 70                return contracts;
 71            }
 72        }
 73
 74        Dictionary<DataContract, object> ProcessedContracts
 75        {
 76            get
 77            {
 78                if (processedContracts == null)
 79                {
 80                    processedContracts = new Dictionary<DataContract, object>();
 81                }
 82                return processedContracts;
 83            }
 84        }
 85
 86        Hashtable SurrogateDataTable
 87        {
 88            get
 89            {
 90                if (surrogateDataTable == null)
 91                    surrogateDataTable = new Hashtable();
 92                return surrogateDataTable;
 93            }
 94        }
 95
 96        internal DataContractDictionary KnownTypesForObject
 97        {
 98            get { return knownTypesForObject; }
 99            set { knownTypesForObject = value; }
100        }
101
102        internal void Add(Type type)
103        {
104            DataContract dataContract = GetDataContract(type);
105            EnsureTypeNotGeneric(dataContract.UnderlyingType);
106            Add(dataContract);
107        }
108
109        internal static void EnsureTypeNotGeneric(Type type)
110        {
111            if (type.ContainsGenericParameters)
112                throw Fx.Exception.AsError(new InvalidDataContractException(SR.GenericTypeNotExportable(type)));
113        }
114
115        void Add(DataContract dataContract)
116        {
117            Add(dataContract.StableName, dataContract);
118        }
119
120        public void Add(XmlQualifiedName name, DataContract dataContract)
121        {
122            if (dataContract.IsBuiltInDataContract)
123                return;
124            InternalAdd(name, dataContract);
125        }
126
127        [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "This is cloned code.")]
128        internal void InternalAdd(XmlQualifiedName name, DataContract dataContract)
129        {
130            DataContract dataContractInSet = null;
131            if (Contracts.TryGetValue(name, out dataContractInSet))
132            {
133                if (!dataContractInSet.Equals(dataContract))
134                {
135                    if (dataContract.UnderlyingType == null || dataContractInSet.UnderlyingType == null)
136                        throw Fx.Exception.AsError(new InvalidOperationException(SR.DupContractInDataContractSet(dataContract.StableName.Name, dataContract.StableName.Namespace)));
137                    else
138                    {
139                        bool typeNamesEqual = (DataContract.GetClrTypeFullName(dataContract.UnderlyingType) == DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType));
140                        throw Fx.Exception.AsError(new InvalidOperationException(SR.DupTypeContractInDataContractSet((typeNamesEqual ? dataContract.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContract.UnderlyingType)), (typeNamesEqual ? dataContractInSet.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)), dataContract.StableName.Name, dataContract.StableName.Namespace)));
141                    }
142                }
143            }
144            else
145            {
146                Contracts.Add(name, dataContract);
147
148                if (dataContract is ClassDataContract)
149                {
150                    AddClassDataContract((ClassDataContract)dataContract);
151                }
152                else if (dataContract is CollectionDataContract)
153                {
154                    AddCollectionDataContract((CollectionDataContract)dataContract);
155                }
156                else if (dataContract is XmlDataContract)
157                {
158                    AddXmlDataContract((XmlDataContract)dataContract);
159                }
160            }
161        }
162
163        void AddClassDataContract(ClassDataContract classDataContract)
164        {
165            if (classDataContract.BaseContract != null)
166            {
167                Add(classDataContract.BaseContract.StableName, classDataContract.BaseContract);
168            }
169            if (!classDataContract.IsISerializable)
170            {
171                if (classDataContract.Members != null)
172                {
173                    for (int i = 0; i < classDataContract.Members.Count; i++)
174                    {
175                        DataMember dataMember = classDataContract.Members[i];
176                        DataContract memberDataContract = GetMemberTypeDataContract(dataMember);
177                        if (dataContractSurrogate != null && dataMember.MemberInfo != null)
178                        {
179                            object customData = DataContractSurrogateCaller.GetCustomDataToExport(
180                                                   dataContractSurrogate,
181                                                   dataMember.MemberInfo,
182                                                   memberDataContract.UnderlyingType);
183                            if (customData != null)
184                                SurrogateDataTable.Add(dataMember, customData);
185                        }
186                        Add(memberDataContract.StableName, memberDataContract);
187                    }
188                }
189            }
190            AddKnownDataContracts(classDataContract.KnownDataContracts);
191        }
192
193        void AddCollectionDataContract(CollectionDataContract collectionDataContract)
194        {
195            if (collectionDataContract.IsDictionary)
196            {
197                ClassDataContract keyValueContract = collectionDataContract.ItemContract as ClassDataContract;
198                AddClassDataContract(keyValueContract);
199            }
200            else
201            {
202                DataContract itemContract = GetItemTypeDataContract(collectionDataContract);
203                if (itemContract != null)
204                    Add(itemContract.StableName, itemContract);
205            }
206            AddKnownDataContracts(collectionDataContract.KnownDataContracts);
207        }
208
209        void AddXmlDataContract(XmlDataContract xmlDataContract)
210        {
211            AddKnownDataContracts(xmlDataContract.KnownDataContracts);
212        }
213
214        void AddKnownDataContracts(DataContractDictionary knownDataContracts)
215        {
216            if (knownDataContracts != null)
217            {
218                foreach (DataContract knownDataContract in knownDataContracts.Values)
219                {
220                    Add(knownDataContract);
221                }
222            }
223        }
224
225        internal XmlQualifiedName GetStableName(Type clrType)
226        {
227            if (dataContractSurrogate != null)
228            {
229                Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, clrType);
230
231                //if (clrType.IsValueType != dcType.IsValueType)
232                //    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ValueTypeMismatchInSurrogatedType, dcType, clrType)));
233                return DataContract.GetStableName(dcType);
234            }
235            return DataContract.GetStableName(clrType);
236        }
237
238        internal DataContract GetDataContract(Type clrType)
239        {
240            if (dataContractSurrogate == null)
241                return DataContract.GetDataContract(clrType);
242            DataContract dataContract = DataContract.GetBuiltInDataContract(clrType);
243            if (dataContract != null)
244                return dataContract;
245            Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, clrType);
246            //if (clrType.IsValueType != dcType.IsValueType)
247            //    throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ValueTypeMismatchInSurrogatedType, dcType, clrType)));
248            dataContract = DataContract.GetDataContract(dcType);
249            if (!SurrogateDataTable.Contains(dataContract))
250            {
251                object customData = DataContractSurrogateCaller.GetCustomDataToExport(
252                                      dataContractSurrogate, clrType, dcType);
253                if (customData != null)
254                    SurrogateDataTable.Add(dataContract, customData);
255            }
256            return dataContract;
257        }
258
259        internal DataContract GetMemberTypeDataContract(DataMember dataMember)
260        {
261            if (dataMember.MemberInfo != null)
262            {
263                Type dataMemberType = dataMember.MemberType;
264                if (dataMember.IsGetOnlyCollection)
265                {
266                    if (dataContractSurrogate != null)
267                    {
268                        Type dcType = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, dataMemberType);
269                        if (dcType != dataMemberType)
270                        {
271                            throw Fx.Exception.AsError(new InvalidDataContractException(SR.SurrogatesWithGetOnlyCollectionsNotSupported(
272                                DataContract.GetClrTypeFullName(dataMemberType), DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType), dataMember.MemberInfo.Name)));
273                        }
274                    }
275                    return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType, SerializationMode.SharedContract);
276                }
277                else
278                {
279                    return GetDataContract(dataMemberType);
280                }
281            }
282            return dataMember.MemberTypeContract;
283        }
284
285        internal DataContract GetItemTypeDataContract(CollectionDataContract collectionContract)
286        {
287            if (collectionContract.ItemType != null)
288                return GetDataContract(collectionContract.ItemType);
289            return collectionContract.ItemContract;
290        }
291
292        internal object GetSurrogateData(object key)
293        {
294            return SurrogateDataTable[key];
295        }
296
297        internal void SetSurrogateData(object key, object surrogateData)
298        {
299            SurrogateDataTable[key] = surrogateData;
300        }
301
302        public DataContract this[XmlQualifiedName key]
303        {
304            get
305            {
306                DataContract dataContract = DataContract.GetBuiltInDataContract(key.Name, key.Namespace);
307                if (dataContract == null)
308                {
309                    Contracts.TryGetValue(key, out dataContract);
310                }
311                return dataContract;
312            }
313        }
314
315        public IDataContractSurrogate DataContractSurrogate
316        {
317            get { return dataContractSurrogate; }
318        }
319
320        public bool Remove(XmlQualifiedName key)
321        {
322            if (DataContract.GetBuiltInDataContract(key.Name, key.Namespace) != null)
323                return false;
324            return Contracts.Remove(key);
325        }
326
327        public IEnumerator<KeyValuePair<XmlQualifiedName, DataContract>> GetEnumerator()
328        {
329            return Contracts.GetEnumerator();
330        }
331
332        internal bool IsContractProcessed(DataContract dataContract)
333        {
334            return ProcessedContracts.ContainsKey(dataContract);
335        }
336
337        internal void SetContractProcessed(DataContract dataContract)
338        {
339            ProcessedContracts.Add(dataContract, dataContract);
340        }
341
342        Dictionary<XmlQualifiedName, object> GetReferencedTypes()
343        {
344            if (referencedTypesDictionary == null)
345            {
346                referencedTypesDictionary = new Dictionary<XmlQualifiedName, object>();
347                //Always include Nullable as referenced type
348                //Do not allow surrogating Nullable<T>
349                referencedTypesDictionary.Add(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable);
350                if (this.referencedTypes != null)
351                {
352                    foreach (Type type in this.referencedTypes)
353                    {
354                        if (type == null)
355                            throw Fx.Exception.AsError(new InvalidOperationException(SR.ReferencedTypesCannotContainNull));
356                        AddReferencedType(referencedTypesDictionary, type);
357                    }
358                }
359            }
360            return referencedTypesDictionary;
361        }
362
363        Dictionary<XmlQualifiedName, object> GetReferencedCollectionTypes()
364        {
365            if (referencedCollectionTypesDictionary == null)
366            {
367                referencedCollectionTypesDictionary = new Dictionary<XmlQualifiedName, object>();
368                if (this.referencedCollectionTypes != null)
369                {
370                    foreach (Type type in this.referencedCollectionTypes)
371                    {
372                        if (type == null)
373                            throw Fx.Exception.AsError(new InvalidOperationException(SR.ReferencedCollectionTypesCannotContainNull));
374                        AddReferencedType(referencedCollectionTypesDictionary, type);
375                    }
376                }
377                XmlQualifiedName genericDictionaryName = DataContract.GetStableName(Globals.TypeOfDictionaryGeneric);
378                if (!referencedCollectionTypesDictionary.ContainsKey(genericDictionaryName) && GetReferencedTypes().ContainsKey(genericDictionaryName))
379                    AddReferencedType(referencedCollectionTypesDictionary, Globals.TypeOfDictionaryGeneric);
380            }
381            return referencedCollectionTypesDictionary;
382        }
383
384        [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", Justification = "This is cloned code.")]
385        void AddReferencedType(Dictionary<XmlQualifiedName, object> referencedTypes, Type type)
386        {
387            if (IsTypeReferenceable(type))
388            {
389                XmlQualifiedName stableName = this.GetStableName(type);
390                object value;
391                if (referencedTypes.TryGetValue(stableName, out value))
392                {
393                    Type referencedType = value as Type;
394                    if (referencedType != null)
395                    {
396                        if (referencedType != type)
397                        {
398                            referencedTypes.Remove(stableName);
399                            List<Type> types = new List<Type>();
400                            types.Add(referencedType);
401                            types.Add(type);
402                            referencedTypes.Add(stableName, types);
403                        }
404                    }
405                    else
406                    {
407                        List<Type> types = (List<Type>)value;
408                        if (!types.Contains(type))
409                            types.Add(type);
410                    }
411                }
412                else
413                    referencedTypes.Add(stableName, type);
414            }
415        }
416        internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, out Type type)
417        {
418            return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type);
419        }
420
421        internal bool TryGetReferencedCollectionType(XmlQualifiedName stableName, DataContract dataContract, out Type type)
422        {
423            return TryGetReferencedType(stableName, dataContract, true/*useReferencedCollectionTypes*/, out type);
424        }
425
426        [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", Justification = "This is cloned code.")]
427        bool TryGetReferencedType(XmlQualifiedName stableName, DataContract dataContract, bool useReferencedCollectionTypes, out Type type)
428        {
429            object value;
430            Dictionary<XmlQualifiedName, object> referencedTypes = useReferencedCollectionTypes ? GetReferencedCollectionTypes() : GetReferencedTypes();
431            if (referencedTypes.TryGetValue(stableName, out value))
432            {
433                type = value as Type;
434                if (type != null)
435                    return true;
436                else
437                {
438                    // Throw ambiguous type match exception
439                    List<Type> types = (List<Type>)value;
440                    StringBuilder errorMessage = new StringBuilder();
441                    bool containsGenericType = false;
442                    for (int i = 0; i < types.Count; i++)
443                    {
444                        Type conflictingType = types[i];
445                        if (!containsGenericType)
446                            containsGenericType = conflictingType.IsGenericTypeDefinition;
447                        errorMessage.AppendFormat("{0}\"{1}\" ", Environment.NewLine, conflictingType.AssemblyQualifiedName);
448                        if (dataContract != null)
449                        {
450                            DataContract other = this.GetDataContract(conflictingType);
451                            errorMessage.Append(((other != null && other.Equals(dataContract)) ? SR.ReferencedTypeMatchingMessage : SR.ReferencedTypeNotMatchingMessage));
452                        }
453                    }
454                    if (containsGenericType)
455                    {
456                        throw Fx.Exception.AsError(new InvalidOperationException(useReferencedCollectionTypes ? 
457                            SR.AmbiguousReferencedCollectionTypes1(errorMessage.ToString()) :
458                            SR.AmbiguousReferencedTypes1(errorMessage.ToString())));
459                    }
460                    else
461                    {
462                        throw Fx.Exception.AsError(new InvalidOperationException(useReferencedCollectionTypes ? 
463                            SR.AmbiguousReferencedCollectionTypes3(XmlConvert.DecodeName(stableName.Name), stableName.Namespace, errorMessage.ToString()) :
464                            SR.AmbiguousReferencedTypes3(XmlConvert.DecodeName(stableName.Name), stableName.Namespace, errorMessage.ToString()))); 
465                    }
466                }
467            }
468            type = null;
469            return false;
470        }
471
472        static bool IsTypeReferenceable(Type type)
473        {
474            Type itemType;
475            return (type.IsSerializable ||
476                    type.IsDefined(Globals.TypeOfDataContractAttribute, false) ||
477                    (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) && !type.IsGenericTypeDefinition) ||
478                    CollectionDataContract.IsCollection(type, out itemType) ||
479                    ClassDataContract.IsNonAttributedTypeValidForSerialization(type));
480        }
481    }
482}
483
484
485