Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / MaterializeFromAtom.cs / 1305376 / MaterializeFromAtom.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// materialize objects from an xml stream // //--------------------------------------------------------------------- namespace System.Data.Services.Client { #region Namespaces. using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Xml; using System.Xml.Linq; using System.Text; using System.Linq.Expressions; #endregion Namespaces. ////// Use this class to materialize objects from an application/atom+xml stream. /// internal class MaterializeAtom : IDisposable, IEnumerable, IEnumerator { ///MergeOption captured from context so its static for the entire materialization internal readonly MergeOption MergeOptionValue; #region Private fields. ///Row count value representing the initial state (-1) private const long CountStateInitial = -1; ///Row count value representing the failure state (-2) private const long CountStateFailure = -2; ///Options when deserializing properties to the target type. private readonly bool ignoreMissingProperties; ///Backreference to the context to allow type resolution. private readonly DataServiceContext context; ///base type of the object to create from the stream. private readonly Type elementType; ///when materializing a known type (like string) ///<property> text-value </property> private readonly bool expectingSingleValue; ///Materializer from which instances are read. ////// The log for the materializer stores all changes for the /// associated data context. /// private readonly AtomMaterializer materializer; ///Parser used by materializer. ///Odd thing to have, only here to force a lookahead for inline elements. private readonly AtomParser parser; ///source reader (may be running on top of a buffer or be the real reader) private XmlReader reader; ///untyped current object private object current; ///has GetEnumerator been called? private bool calledGetEnumerator; ///The count tag's value, if requested private long countValue; ///Whether anything has been read. private bool moved; ////// output writer, set using reflection /// #if DEBUG && !ASTORIA_LIGHT private System.IO.TextWriter writer = new System.IO.StringWriter(System.Globalization.CultureInfo.InvariantCulture); #else #pragma warning disable 649 private System.IO.TextWriter writer; #pragma warning restore 649 #endif #endregion Private fields. ////// constructor /// /// originating context /// reader /// Query components (projection, expected type) /// Projection plan (if compiled in an earlier query). /// merge option to use for this materialization pass internal MaterializeAtom(DataServiceContext context, XmlReader reader, QueryComponents queryComponents, ProjectionPlan plan, MergeOption mergeOption) { Debug.Assert(queryComponents != null, "queryComponents != null"); this.context = context; this.elementType = queryComponents.LastSegmentType; this.MergeOptionValue = mergeOption; this.ignoreMissingProperties = context.IgnoreMissingProperties; this.reader = (reader == null) ? null : new System.Data.Services.Client.Xml.XmlAtomErrorReader(reader); this.countValue = CountStateInitial; this.expectingSingleValue = ClientConvert.IsKnownNullableType(elementType); Debug.Assert(reader != null, "Materializer reader is null! Did you mean to use Materializer.ResultsWrapper/EmptyResults?"); // NOTE: dataNamespace is used for reference equality, and while it looks like // a variable, it appears that it will only get set to XmlConstants.DataWebNamespace // at runtime. Therefore we remove string dataNamespace as a field here. // this.dataNamespace = reader != null ? reader.Settings.NameTable.Add(context.DataNamespace) : null; reader.Settings.NameTable.Add(context.DataNamespace); string typeScheme = this.context.TypeScheme.OriginalString; this.parser = new AtomParser(this.reader, AtomParser.XElementBuilderCallback, typeScheme, context.DataNamespace); AtomMaterializerLog log = new AtomMaterializerLog(this.context, mergeOption); Type implementationType; Type materializerType = GetTypeForMaterializer(this.expectingSingleValue, this.elementType, out implementationType); this.materializer = new AtomMaterializer(parser, context, materializerType, this.ignoreMissingProperties, mergeOption, log, this.MaterializedObjectCallback, queryComponents, plan); } private void MaterializedObjectCallback(object tag, object entity) { Debug.Assert(tag != null, "tag != null"); Debug.Assert(entity != null, "entity != null"); XElement data = (XElement)tag; if (this.context.HasReadingEntityHandlers) { XmlUtil.RemoveDuplicateNamespaceAttributes(data); this.context.FireReadingEntityEvent(entity, data); } } ////// Private internal constructor used for creating empty wrapper. /// private MaterializeAtom() { } ////// DO NOT USE - this is a private hook for client unit tests to construct materializers /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] private MaterializeAtom(DataServiceContext context, XmlReader reader, Type type, MergeOption mergeOption) : this(context, reader, new QueryComponents(null, Util.DataServiceVersionEmpty, type, null, null), null, mergeOption) { } #region Current ///Loosely typed current object property. ////// The value should be of the right type, as the materializer takes the /// expected type into account. /// public object Current { get { object currentValue = this.current; return currentValue; } } #endregion ////// A materializer for empty results /// internal static MaterializeAtom EmptyResults { get { return new ResultsWrapper(null, null); } } ////// Returns true, if the materialize atom has empty results, because of /// IgnoreResourceNotFoundException flag set in context /// internal bool IsEmptyResults { get { return this.reader == null; } } ////// The context object this materializer belongs to /// internal DataServiceContext Context { get { return this.context; } } #region IDisposable ////// dispose /// public void Dispose() { this.current = null; if (null != this.reader) { ((IDisposable)this.reader).Dispose(); } if (null != this.writer) { this.writer.Dispose(); } GC.SuppressFinalize(this); } #endregion #region IEnumerable ////// as IEnumerable /// ///this public virtual IEnumerator GetEnumerator() { this.CheckGetEnumerator(); return this; } #endregion private static Type GetTypeForMaterializer(bool expectingSingleValue, Type elementType, out Type implementationType) { if (!expectingSingleValue && typeof(IEnumerable).IsAssignableFrom(elementType)) { implementationType = ClientType.GetImplementationType(elementType, typeof(ICollection<>)); if (implementationType != null) { Type expectedType = implementationType.GetGenericArguments()[0]; // already know its IList<> return expectedType; } } implementationType = null; return elementType; } ////// Creates the next object from the stream. /// ///false if stream is finished public bool MoveNext() { bool applying = this.context.ApplyingChanges; try { this.context.ApplyingChanges = true; return this.MoveNextInternal(); } finally { this.context.ApplyingChanges = applying; } } ////// Creates the next object from the stream. /// ///false if stream is finished private bool MoveNextInternal() { // For empty results, just return false. if (this.reader == null) { Debug.Assert(this.current == null, "this.current == null -- otherwise this.reader should have some value."); return false; } this.current = null; this.materializer.Log.Clear(); bool result = false; Type implementationType; GetTypeForMaterializer(this.expectingSingleValue, this.elementType, out implementationType); if (implementationType != null) { if (this.moved) { return false; } Type expectedType = implementationType.GetGenericArguments()[0]; // already know its IList<> implementationType = this.elementType; if (implementationType.IsInterface) { implementationType = typeof(System.Collections.ObjectModel.Collection<>).MakeGenericType(expectedType); } IList list = (IList)Activator.CreateInstance(implementationType); while (this.materializer.Read()) { this.moved = true; list.Add(this.materializer.CurrentValue); } this.current = list; result = true; } if (null == this.current) { if (this.expectingSingleValue && this.moved) { result = false; } else { result = this.materializer.Read(); if (result) { this.current = this.materializer.CurrentValue; } this.moved = true; } } this.materializer.Log.ApplyToContext(); return result; } ////// Not supported. /// ///Always thrown void System.Collections.IEnumerator.Reset() { throw Error.NotSupported(); } ////// Creates materializer for results /// /// the results to wrap ///a new materializer internal static MaterializeAtom CreateWrapper(IEnumerable results) { return new ResultsWrapper(results, null); } ///Creates a materializer for partial result sets. /// The current page of results /// The continuation for the results. ///A new materializer. internal static MaterializeAtom CreateWrapper(IEnumerable results, DataServiceQueryContinuation continuation) { return new ResultsWrapper(results, continuation); } ///set the inserted object expected in the response /// object being inserted that the response is looking for internal void SetInsertingObject(object addedObject) { this.materializer.TargetInstance = addedObject; } internal static void SkipToEnd(XmlReader reader) { Debug.Assert(reader != null, "reader != null"); Debug.Assert(reader.NodeType == XmlNodeType.Element, "reader.NodeType == XmlNodeType.Element"); if (reader.IsEmptyElement) { return; } int readerDepth = reader.Depth; while (reader.Read()) { if (reader.NodeType == XmlNodeType.EndElement && reader.Depth == readerDepth) { return; } } } ////// The count tag's value, if requested /// ///The count value returned from the server internal long CountValue() { if (this.countValue == CountStateInitial) { this.ReadCountValue(); } else if (this.countValue == CountStateFailure) { throw new InvalidOperationException(Strings.MaterializeFromAtom_CountNotPresent); } return this.countValue; } ////// Returns the next link URI for the collection key /// /// The collection for which the Uri is returned, or null, if the top level link is to be returned ///An Uri pointing to the next page for the collection internal virtual DataServiceQueryContinuation GetContinuation(IEnumerable key) { Debug.Assert(this.materializer != null, "Materializer is null!"); DataServiceQueryContinuation result; if (key == null) { if ((this.expectingSingleValue && !this.moved) || (!this.expectingSingleValue && !this.materializer.IsEndOfStream)) { // expectingSingleValue && !moved : haven't started parsing single value (single value should not have next link anyway) // !expectingSingleValue && !IsEndOfStream : collection type feed did not finish parsing yet throw new InvalidOperationException(Strings.MaterializeFromAtom_TopLevelLinkNotAvailable); } // we have already moved to the end of stream // are we singleton or just an entry? if (this.expectingSingleValue || this.materializer.CurrentFeed == null) { result = null; } else { // DEVNOTE([....]): The next link uri should never be edited by the client, and therefore it must be absolute result = DataServiceQueryContinuation.Create( this.materializer.CurrentFeed.NextLink, this.materializer.MaterializeEntryPlan); } } else { if (!this.materializer.NextLinkTable.TryGetValue(key, out result)) { // someone has asked for a collection that's "out of scope" or doesn't exist throw new ArgumentException(Strings.MaterializeFromAtom_CollectionKeyNotPresentInLinkTable); } } return result; } ///verify the GetEnumerator can only be called once private void CheckGetEnumerator() { if (this.calledGetEnumerator) { throw Error.NotSupported(Strings.Deserialize_GetEnumerator); } this.calledGetEnumerator = true; } ////// read the m2:count tag in the feed /// private void ReadCountValue() { Debug.Assert(this.countValue == CountStateInitial, "Count value is not in the initial state"); if (this.materializer.CurrentFeed != null && this.materializer.CurrentFeed.Count.HasValue) { this.countValue = this.materializer.CurrentFeed.Count.Value; return; } // find the first element tag while (this.reader.NodeType != XmlNodeType.Element && this.reader.Read()) { } if (this.reader.EOF) { throw new InvalidOperationException(Strings.MaterializeFromAtom_CountNotPresent); } // the tag Should only beor tag: Debug.Assert( (Util.AreSame(XmlConstants.AtomNamespace, this.reader.NamespaceURI) && Util.AreSame(XmlConstants.AtomFeedElementName, this.reader.LocalName)) || (Util.AreSame(XmlConstants.DataWebNamespace, this.reader.NamespaceURI) && Util.AreSame(XmlConstants.LinkCollectionElementName, this.reader.LocalName)), " or tag expected"); // Create the XElement for look-ahead // DEVNOTE([....]): // This is not streaming friendly! XElement element = XElement.Load(this.reader); this.reader.Close(); // Read the count value from the xelement XElement countNode = element.Descendants(XNamespace.Get(XmlConstants.DataWebMetadataNamespace) + XmlConstants.RowCountElement).FirstOrDefault(); if (countNode == null) { throw new InvalidOperationException(Strings.MaterializeFromAtom_CountNotPresent); } else { if (!long.TryParse(countNode.Value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out this.countValue)) { throw new FormatException(Strings.MaterializeFromAtom_CountFormatError); } if (this.countValue < 0) { throw new FormatException(Strings.MaterializeFromAtom_CountFormatError); } } this.reader = new System.Data.Services.Client.Xml.XmlAtomErrorReader(element.CreateReader()); this.parser.ReplaceReader(this.reader); } /// /// Gets the /// String with type name to check. /// Context in which type is being resolved. /// Expected type for the name. /// /// Whether to check that a user-overriden type is assignable to a /// variable of typefor the (potentially /// user-callback-resolved) type name. /// . /// /// The internal static ClientType GetEntryClientType(string typeName, DataServiceContext context, Type expectedType, bool checkAssignable) { Debug.Assert(context != null, "context != null"); Type resolvedType = context.ResolveTypeFromName(typeName, expectedType, checkAssignable); ClientType result = ClientType.Create(resolvedType); Debug.Assert(result != null, "result != null -- otherwise ClientType.Create returned null"); return result; } internal static string ReadElementString(XmlReader reader, bool checkNullAttribute) { Debug.Assert(reader != null, "reader != null"); Debug.Assert( reader.NodeType == XmlNodeType.Element, "reader.NodeType == XmlNodeType.Element -- otherwise caller is confused as to where the reader is"); string result = null; bool empty = checkNullAttribute && !Util.DoesNullAttributeSayTrue(reader); if (reader.IsEmptyElement) { return (empty ? String.Empty : null); } while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.EndElement: return result ?? (empty ? String.Empty : null); case XmlNodeType.CDATA: case XmlNodeType.Text: case XmlNodeType.SignificantWhitespace: if (null != result) { throw Error.InvalidOperation(Strings.Deserialize_MixedTextWithComment); } result = reader.Value; break; case XmlNodeType.Comment: case XmlNodeType.Whitespace: break; #region XmlNodeType error case XmlNodeType.Element: goto default; default: throw Error.InvalidOperation(Strings.Deserialize_ExpectingSimpleValue); #endregion } } // xml ended before EndElement? throw Error.InvalidOperation(Strings.Deserialize_ExpectingSimpleValue); } ///for the given type name. /// Private type to wrap partial (paged) results and make it look like standard materialized results. /// private class ResultsWrapper : MaterializeAtom { #region Private fields. ///The results to wrap private readonly IEnumerable results; ///A continuation to the next page of results. private readonly DataServiceQueryContinuation continuation; #endregion Private fields. ////// Creates a wrapper for raw results /// /// the results to wrap /// The continuation for this query. internal ResultsWrapper(IEnumerable results, DataServiceQueryContinuation continuation) { this.results = results ?? new object[0]; this.continuation = continuation; } ////// Get the next link to the result set /// /// When equals to null, returns the next link associated with this collection. Otherwise throws InvalidOperationException. ///The continuation for this query. internal override DataServiceQueryContinuation GetContinuation(IEnumerable key) { if (key == null) { return this.continuation; } else { throw new InvalidOperationException(Strings.MaterializeFromAtom_GetNestLinkForFlatCollection); } } ////// Gets Enumerator for wrapped results. /// ///IEnumerator for results public override IEnumerator GetEnumerator() { return this.results.GetEnumerator(); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TextTrailingCharacterEllipsis.cs
- Bits.cs
- NamedObject.cs
- DataGrid.cs
- ZipIOCentralDirectoryFileHeader.cs
- DataBinding.cs
- CompilerWrapper.cs
- _HeaderInfoTable.cs
- SizeConverter.cs
- CapabilitiesPattern.cs
- SystemIPGlobalProperties.cs
- SqlUdtInfo.cs
- TcpAppDomainProtocolHandler.cs
- DataControlCommands.cs
- NamespaceQuery.cs
- _ConnectOverlappedAsyncResult.cs
- PtsPage.cs
- Container.cs
- JsonCollectionDataContract.cs
- RadioButton.cs
- InfiniteTimeSpanConverter.cs
- CornerRadiusConverter.cs
- FastEncoderStatics.cs
- ISAPIRuntime.cs
- SqlDataSourceCommandEventArgs.cs
- Grid.cs
- SuppressIldasmAttribute.cs
- PeerNameRecord.cs
- DataGridViewRowsRemovedEventArgs.cs
- basecomparevalidator.cs
- Deflater.cs
- SchemaSetCompiler.cs
- BamlLocalizer.cs
- TransactionFormatter.cs
- CacheSection.cs
- OleDbDataReader.cs
- SerializationFieldInfo.cs
- RbTree.cs
- TrackingStringDictionary.cs
- _SSPISessionCache.cs
- FrameDimension.cs
- WindowsToolbar.cs
- WebEncodingValidator.cs
- CheckableControlBaseAdapter.cs
- WriteableBitmap.cs
- MapPathBasedVirtualPathProvider.cs
- Helpers.cs
- ToolZone.cs
- DBCommand.cs
- PerfCounterSection.cs
- GcHandle.cs
- EventItfInfo.cs
- StringResourceManager.cs
- DbSetClause.cs
- NonVisualControlAttribute.cs
- SessionParameter.cs
- TraceSection.cs
- ImageBrush.cs
- indexingfiltermarshaler.cs
- ResourcePermissionBase.cs
- Drawing.cs
- XmlMtomWriter.cs
- ErrorStyle.cs
- ProtectedConfiguration.cs
- GcHandle.cs
- PartManifestEntry.cs
- DiscoveryInnerClientAdhocCD1.cs
- ResourceDictionaryCollection.cs
- ObjectSpanRewriter.cs
- BindValidationContext.cs
- Int64Storage.cs
- ExtensionQuery.cs
- CompilerCollection.cs
- MemberMemberBinding.cs
- ConversionContext.cs
- XMLUtil.cs
- PrintDialog.cs
- Camera.cs
- ConfigurationManagerInternal.cs
- PersistenceTypeAttribute.cs
- TreeView.cs
- SharedConnectionInfo.cs
- MetricEntry.cs
- UnknownWrapper.cs
- AssertFilter.cs
- HtmlImage.cs
- GridItem.cs
- XhtmlBasicLiteralTextAdapter.cs
- ConfigViewGenerator.cs
- VerificationAttribute.cs
- XmlImplementation.cs
- DtdParser.cs
- xmlformatgeneratorstatics.cs
- TimeSpanSecondsConverter.cs
- RtfToXamlReader.cs
- SizeIndependentAnimationStorage.cs
- DebugHandleTracker.cs
- _ConnectionGroup.cs
- ListBase.cs
- HotSpot.cs