//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Syndication { using System.Collections.ObjectModel; using System.Runtime.Serialization; using System.Xml.Serialization; using System.Collections.Generic; using System.Xml; using System.Xml.Schema; using System.ServiceModel.Channels; using System.Diagnostics; using System.ServiceModel.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; internal delegate InlineCategoriesDocument CreateInlineCategoriesDelegate(); internal delegate ReferencedCategoriesDocument CreateReferencedCategoriesDelegate(); [TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")] [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)] public class AtomPub10ServiceDocumentFormatter : ServiceDocumentFormatter, IXmlSerializable { Type documentType; int maxExtensionSize; bool preserveAttributeExtensions; bool preserveElementExtensions; public AtomPub10ServiceDocumentFormatter() : this(typeof(ServiceDocument)) { } public AtomPub10ServiceDocumentFormatter(Type documentTypeToCreate) : base() { if (documentTypeToCreate == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("documentTypeToCreate"); } if (!typeof(ServiceDocument).IsAssignableFrom(documentTypeToCreate)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("documentTypeToCreate", SR.GetString(SR.InvalidObjectTypePassed, "documentTypeToCreate", "ServiceDocument")); } this.maxExtensionSize = int.MaxValue; this.preserveAttributeExtensions = true; this.preserveElementExtensions = true; this.documentType = documentTypeToCreate; } public AtomPub10ServiceDocumentFormatter(ServiceDocument documentToWrite) : base(documentToWrite) { // No need to check that the parameter passed is valid - it is checked by the c'tor of the base class this.maxExtensionSize = int.MaxValue; preserveAttributeExtensions = true; preserveElementExtensions = true; this.documentType = documentToWrite.GetType(); } public override string Version { get { return App10Constants.Namespace; } } public override bool CanRead(XmlReader reader) { if (reader == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } return reader.IsStartElement(App10Constants.Service, App10Constants.Namespace); } [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")] XmlSchema IXmlSerializable.GetSchema() { return null; } [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")] void IXmlSerializable.ReadXml(XmlReader reader) { if (reader == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } TraceServiceDocumentReadBegin(); ReadDocument(reader); TraceServiceDocumentReadEnd(); } [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Justification = "The IXmlSerializable implementation is only for exposing under WCF DataContractSerializer. The funcionality is exposed to derived class through the ReadFrom\\WriteTo methods")] void IXmlSerializable.WriteXml(XmlWriter writer) { if (writer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); } if (this.Document == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DocumentFormatterDoesNotHaveDocument))); } TraceServiceDocumentWriteBegin(); WriteDocument(writer); TraceServiceDocumentWriteEnd(); } public override void ReadFrom(XmlReader reader) { if (reader == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader"); } reader.MoveToContent(); if (!CanRead(reader)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.UnknownDocumentXml, reader.LocalName, reader.NamespaceURI))); } TraceServiceDocumentReadBegin(); ReadDocument(reader); TraceServiceDocumentReadEnd(); } public override void WriteTo(XmlWriter writer) { if (writer == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer"); } if (this.Document == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.DocumentFormatterDoesNotHaveDocument))); } TraceServiceDocumentWriteBegin(); writer.WriteStartElement(App10Constants.Prefix, App10Constants.Service, App10Constants.Namespace); WriteDocument(writer); writer.WriteEndElement(); TraceServiceDocumentWriteEnd(); } internal static CategoriesDocument ReadCategories(XmlReader reader, Uri baseUri, CreateInlineCategoriesDelegate inlineCategoriesFactory, CreateReferencedCategoriesDelegate referencedCategoriesFactory, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize) { string link = reader.GetAttribute(App10Constants.Href, string.Empty); if (string.IsNullOrEmpty(link)) { InlineCategoriesDocument inlineCategories = inlineCategoriesFactory(); ReadInlineCategories(reader, inlineCategories, baseUri, version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize); return inlineCategories; } else { ReferencedCategoriesDocument referencedCategories = referencedCategoriesFactory(); ReadReferencedCategories(reader, referencedCategories, baseUri, new Uri(link, UriKind.RelativeOrAbsolute), version, preserveElementExtensions, preserveAttributeExtensions, maxExtensionSize); return referencedCategories; } } internal static void TraceServiceDocumentReadBegin() { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationReadServiceDocumentBegin, SR.GetString(SR.TraceCodeSyndicationReadServiceDocumentBegin)); } } internal static void TraceServiceDocumentReadEnd() { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationReadServiceDocumentEnd, SR.GetString(SR.TraceCodeSyndicationReadServiceDocumentEnd)); } } internal static void TraceServiceDocumentWriteBegin() { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationWriteServiceDocumentBegin, SR.GetString(SR.TraceCodeSyndicationWriteServiceDocumentBegin)); } } internal static void TraceServiceDocumentWriteEnd() { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.SyndicationWriteServiceDocumentEnd, SR.GetString(SR.TraceCodeSyndicationWriteServiceDocumentEnd)); } } internal static void WriteCategoriesInnerXml(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version) { Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, categories.BaseUri); if (baseUriToWrite != null) { WriteXmlBase(writer, baseUriToWrite); } if (!string.IsNullOrEmpty(categories.Language)) { WriteXmlLang(writer, categories.Language); } if (categories.IsInline) { WriteInlineCategoriesContent(writer, (InlineCategoriesDocument)categories, version); } else { WriteReferencedCategoriesContent(writer, (ReferencedCategoriesDocument)categories, version); } } protected override ServiceDocument CreateDocumentInstance() { if (this.documentType == typeof(ServiceDocument)) { return new ServiceDocument(); } else { return (ServiceDocument)Activator.CreateInstance(this.documentType); } } static void ReadInlineCategories(XmlReader reader, InlineCategoriesDocument inlineCategories, Uri baseUri, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize) { inlineCategories.BaseUri = baseUri; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { inlineCategories.BaseUri = FeedUtils.CombineXmlBase(inlineCategories.BaseUri, reader.Value); } else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { inlineCategories.Language = reader.Value; } else if (reader.LocalName == App10Constants.Fixed && reader.NamespaceURI == string.Empty) { inlineCategories.IsFixed = (reader.Value == "yes"); } else if (reader.LocalName == Atom10Constants.SchemeTag && reader.NamespaceURI == string.Empty) { inlineCategories.Scheme = reader.Value; } else { string ns = reader.NamespaceURI; string name = reader.LocalName; if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) { continue; } string val = reader.Value; if (!TryParseAttribute(name, ns, val, inlineCategories, version)) { if (preserveAttributeExtensions) { inlineCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); } } } } } SyndicationFeedFormatter.MoveToStartElement(reader); bool isEmptyElement = reader.IsEmptyElement; reader.ReadStartElement(); if (!isEmptyElement) { XmlBuffer buffer = null; XmlDictionaryWriter extWriter = null; try { while (reader.IsStartElement()) { if (reader.IsStartElement(Atom10Constants.CategoryTag, Atom10Constants.Atom10Namespace)) { SyndicationCategory category = CreateCategory(inlineCategories); Atom10FeedFormatter.ReadCategory(reader, category, version, preserveAttributeExtensions, preserveElementExtensions, maxExtensionSize); if (category.Scheme == null) { category.Scheme = inlineCategories.Scheme; } inlineCategories.Categories.Add(category); } else if (!TryParseElement(reader, inlineCategories, version)) { if (preserveElementExtensions) { SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); reader.Skip(); } } } LoadElementExtensions(buffer, extWriter, inlineCategories); } finally { if (extWriter != null) { extWriter.Close(); } } reader.ReadEndElement(); } } static void ReadReferencedCategories(XmlReader reader, ReferencedCategoriesDocument referencedCategories, Uri baseUri, Uri link, string version, bool preserveElementExtensions, bool preserveAttributeExtensions, int maxExtensionSize) { referencedCategories.BaseUri = baseUri; referencedCategories.Link = link; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { referencedCategories.BaseUri = FeedUtils.CombineXmlBase(referencedCategories.BaseUri, reader.Value); } else if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { referencedCategories.Language = reader.Value; } else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty) { continue; } else { string ns = reader.NamespaceURI; string name = reader.LocalName; if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) { continue; } string val = reader.Value; if (!TryParseAttribute(name, ns, val, referencedCategories, version)) { if (preserveAttributeExtensions) { referencedCategories.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); } } } } } reader.MoveToElement(); bool isEmptyElement = reader.IsEmptyElement; reader.ReadStartElement(); if (!isEmptyElement) { XmlBuffer buffer = null; XmlDictionaryWriter extWriter = null; try { while (reader.IsStartElement()) { if (!TryParseElement(reader, referencedCategories, version)) { if (preserveElementExtensions) { SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, maxExtensionSize); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); reader.Skip(); } } } LoadElementExtensions(buffer, extWriter, referencedCategories); } finally { if (extWriter != null) { extWriter.Close(); } } reader.ReadEndElement(); } } static void WriteCategories(XmlWriter writer, CategoriesDocument categories, Uri baseUri, string version) { writer.WriteStartElement(App10Constants.Prefix, App10Constants.Categories, App10Constants.Namespace); WriteCategoriesInnerXml(writer, categories, baseUri, version); writer.WriteEndElement(); } static void WriteInlineCategoriesContent(XmlWriter writer, InlineCategoriesDocument categories, string version) { if (!string.IsNullOrEmpty(categories.Scheme)) { writer.WriteAttributeString(Atom10Constants.SchemeTag, categories.Scheme); } // by default, categories are not fixed if (categories.IsFixed) { writer.WriteAttributeString(App10Constants.Fixed, "yes"); } WriteAttributeExtensions(writer, categories, version); for (int i = 0; i < categories.Categories.Count; ++i) { Atom10FeedFormatter.WriteCategory(writer, categories.Categories[i], version); } WriteElementExtensions(writer, categories, version); } static void WriteReferencedCategoriesContent(XmlWriter writer, ReferencedCategoriesDocument categories, string version) { if (categories.Link != null) { writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(categories.Link)); } WriteAttributeExtensions(writer, categories, version); WriteElementExtensions(writer, categories, version); } static void WriteXmlBase(XmlWriter writer, Uri baseUri) { writer.WriteAttributeString("xml", "base", Atom10FeedFormatter.XmlNs, FeedUtils.GetUriString(baseUri)); } static void WriteXmlLang(XmlWriter writer, string lang) { writer.WriteAttributeString("xml", "lang", Atom10FeedFormatter.XmlNs, lang); } ResourceCollectionInfo ReadCollection(XmlReader reader, Workspace workspace) { ResourceCollectionInfo result = CreateCollection(workspace); result.BaseUri = workspace.BaseUri; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value); } else if (reader.LocalName == App10Constants.Href && reader.NamespaceURI == string.Empty) { result.Link = new Uri(reader.Value, UriKind.RelativeOrAbsolute); } else { string ns = reader.NamespaceURI; string name = reader.LocalName; if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) { continue; } string val = reader.Value; if (!TryParseAttribute(name, ns, val, result, this.Version)) { if (this.preserveAttributeExtensions) { result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); } } } } } XmlBuffer buffer = null; XmlDictionaryWriter extWriter = null; reader.ReadStartElement(); try { while (reader.IsStartElement()) { if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace)) { result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/app:collection/atom:title[@type]", this.preserveAttributeExtensions); } else if (reader.IsStartElement(App10Constants.Categories, App10Constants.Namespace)) { result.Categories.Add(ReadCategories(reader, result.BaseUri, delegate() { return CreateInlineCategories(result); }, delegate() { return CreateReferencedCategories(result); }, this.Version, this.preserveElementExtensions, this.preserveAttributeExtensions, this.maxExtensionSize)); } else if (reader.IsStartElement(App10Constants.Accept, App10Constants.Namespace)) { result.Accepts.Add(reader.ReadElementString()); } else if (!TryParseElement(reader, result, this.Version)) { if (this.preserveElementExtensions) { SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); reader.Skip(); } } } LoadElementExtensions(buffer, extWriter, result); } finally { if (extWriter != null) { extWriter.Close(); } } reader.ReadEndElement(); return result; } void ReadDocument(XmlReader reader) { ServiceDocument result = CreateDocumentInstance(); try { SyndicationFeedFormatter.MoveToStartElement(reader); bool elementIsEmpty = reader.IsEmptyElement; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.LocalName == "lang" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { result.Language = reader.Value; } else if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { result.BaseUri = new Uri(reader.Value, UriKind.RelativeOrAbsolute); } else { string ns = reader.NamespaceURI; string name = reader.LocalName; if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) { continue; } string val = reader.Value; if (!TryParseAttribute(name, ns, val, result, this.Version)) { if (this.preserveAttributeExtensions) { result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); } } } } } XmlBuffer buffer = null; XmlDictionaryWriter extWriter = null; reader.ReadStartElement(); if (!elementIsEmpty) { try { while (reader.IsStartElement()) { if (reader.IsStartElement(App10Constants.Workspace, App10Constants.Namespace)) { result.Workspaces.Add(ReadWorkspace(reader, result)); } else if (!TryParseElement(reader, result, this.Version)) { if (this.preserveElementExtensions) { SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); reader.Skip(); } } } LoadElementExtensions(buffer, extWriter, result); } finally { if (extWriter != null) { extWriter.Close(); } } } reader.ReadEndElement(); } catch (FormatException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e)); } catch (ArgumentException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(FeedUtils.AddLineInfo(reader, SR.ErrorParsingDocument), e)); } SetDocument(result); } Workspace ReadWorkspace(XmlReader reader, ServiceDocument document) { Workspace result = CreateWorkspace(document); result.BaseUri = document.BaseUri; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if (reader.LocalName == "base" && reader.NamespaceURI == Atom10FeedFormatter.XmlNs) { result.BaseUri = FeedUtils.CombineXmlBase(result.BaseUri, reader.Value); } else { string ns = reader.NamespaceURI; string name = reader.LocalName; if (FeedUtils.IsXmlns(name, ns) || FeedUtils.IsXmlSchemaType(name, ns)) { continue; } string val = reader.Value; if (!TryParseAttribute(name, ns, val, result, this.Version)) { if (this.preserveAttributeExtensions) { result.AttributeExtensions.Add(new XmlQualifiedName(reader.LocalName, reader.NamespaceURI), reader.Value); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); } } } } } XmlBuffer buffer = null; XmlDictionaryWriter extWriter = null; reader.ReadStartElement(); try { while (reader.IsStartElement()) { if (reader.IsStartElement(Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace)) { result.Title = Atom10FeedFormatter.ReadTextContentFrom(reader, "//app:service/app:workspace/atom:title[@type]", this.preserveAttributeExtensions); } else if (reader.IsStartElement(App10Constants.Collection, App10Constants.Namespace)) { result.Collections.Add(ReadCollection(reader, result)); } else if (!TryParseElement(reader, result, this.Version)) { if (this.preserveElementExtensions) { SyndicationFeedFormatter.CreateBufferIfRequiredAndWriteNode(ref buffer, ref extWriter, reader, this.maxExtensionSize); } else { SyndicationFeedFormatter.TraceSyndicationElementIgnoredOnRead(reader); reader.Skip(); } } } LoadElementExtensions(buffer, extWriter, result); } finally { if (extWriter != null) { extWriter.Close(); } } reader.ReadEndElement(); return result; } void WriteCollection(XmlWriter writer, ResourceCollectionInfo collection, Uri baseUri) { writer.WriteStartElement(App10Constants.Prefix, App10Constants.Collection, App10Constants.Namespace); Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, collection.BaseUri); if (baseUriToWrite != null) { baseUri = collection.BaseUri; WriteXmlBase(writer, baseUriToWrite); } if (collection.Link != null) { writer.WriteAttributeString(App10Constants.Href, FeedUtils.GetUriString(collection.Link)); } WriteAttributeExtensions(writer, collection, this.Version); if (collection.Title != null) { collection.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace); } for (int i = 0; i < collection.Accepts.Count; ++i) { writer.WriteElementString(App10Constants.Prefix, App10Constants.Accept, App10Constants.Namespace, collection.Accepts[i]); } for (int i = 0; i < collection.Categories.Count; ++i) { WriteCategories(writer, collection.Categories[i], baseUri, this.Version); } WriteElementExtensions(writer, collection, this.Version); writer.WriteEndElement(); } void WriteDocument(XmlWriter writer) { // declare the atom10 namespace upfront for compactness writer.WriteAttributeString(Atom10Constants.Atom10Prefix, Atom10FeedFormatter.XmlNsNs, Atom10Constants.Atom10Namespace); if (!string.IsNullOrEmpty(this.Document.Language)) { WriteXmlLang(writer, this.Document.Language); } Uri baseUri = this.Document.BaseUri; if (baseUri != null) { WriteXmlBase(writer, baseUri); } WriteAttributeExtensions(writer, this.Document, this.Version); for (int i = 0; i < this.Document.Workspaces.Count; ++i) { WriteWorkspace(writer, this.Document.Workspaces[i], baseUri); } WriteElementExtensions(writer, this.Document, this.Version); } void WriteWorkspace(XmlWriter writer, Workspace workspace, Uri baseUri) { writer.WriteStartElement(App10Constants.Prefix, App10Constants.Workspace, App10Constants.Namespace); Uri baseUriToWrite = FeedUtils.GetBaseUriToWrite(baseUri, workspace.BaseUri); if (baseUriToWrite != null) { baseUri = workspace.BaseUri; WriteXmlBase(writer, baseUriToWrite); } WriteAttributeExtensions(writer, workspace, this.Version); if (workspace.Title != null) { workspace.Title.WriteTo(writer, Atom10Constants.TitleTag, Atom10Constants.Atom10Namespace); } for (int i = 0; i < workspace.Collections.Count; ++i) { WriteCollection(writer, workspace.Collections[i], baseUri); } WriteElementExtensions(writer, workspace, this.Version); writer.WriteEndElement(); } } [TypeForwardedFrom("System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")] [XmlRoot(ElementName = App10Constants.Service, Namespace = App10Constants.Namespace)] public class AtomPub10ServiceDocumentFormatter : AtomPub10ServiceDocumentFormatter where TServiceDocument : ServiceDocument, new() { public AtomPub10ServiceDocumentFormatter() : base(typeof(TServiceDocument)) { } public AtomPub10ServiceDocumentFormatter(TServiceDocument documentToWrite) : base(documentToWrite) { } protected override ServiceDocument CreateDocumentInstance() { return new TServiceDocument(); } } }