/// <summary>
        /// Writes the &lt;saml:Advice> element.
        /// </summary>
        /// <param name="writer">A <see cref="XmlWriter"/> to serialize the <see cref="Saml2Advice"/>.</param>
        /// <param name="data">The <see cref="Saml2Advice"/> to serialize.</param>
        protected virtual void WriteAdvice(XmlWriter writer, Saml2Advice data)
        {
            if (null == writer)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("writer");
            }

            if (null == data)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("data");
            }

            // <Advice>
            writer.WriteStartElement(Saml2Constants.Elements.Advice, Saml2Constants.Namespace);

            // <AssertionIDRef> 0-OO
            foreach (Saml2Id id in data.AssertionIdReferences)
            {
                writer.WriteElementString(Saml2Constants.Elements.AssertionIDRef, Saml2Constants.Namespace, id.Value);
            }

            // <AssertionURIRef> 0-OO
            foreach (Uri uri in data.AssertionUriReferences)
            {
                writer.WriteElementString(Saml2Constants.Elements.AssertionURIRef, Saml2Constants.Namespace, uri.AbsoluteUri);
            }

            // <Assertion> 0-OO
            foreach (Saml2Assertion assertion in data.Assertions)
            {
                this.WriteAssertion(writer, assertion);
            }

            // </Advice>
            writer.WriteEndElement();
        }
        /// <summary>
        /// Reads the &lt;saml:Advice> element.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The Advice element has an extensibility point to allow XML elements
        /// from non-SAML2 namespaces to be included. By default, because the 
        /// Advice may be ignored without affecting the semantics of the 
        /// assertion, any such elements are ignored. To handle the processing
        /// of those elements, override this method.
        /// </para>
        /// </remarks>
        /// <param name="reader">A <see cref="XmlReader"/> positioned at a <see cref="Saml2Advice"/> element.</param>
        /// <returns>A <see cref="Saml2Advice"/> instance.</returns>
        protected virtual Saml2Advice ReadAdvice(XmlReader reader)
        {
            if (null == reader)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("reader");
            }

            // throw if wrong element
            if (!reader.IsStartElement(Saml2Constants.Elements.Advice, Saml2Constants.Namespace))
            {
                reader.ReadStartElement(Saml2Constants.Elements.Advice, Saml2Constants.Namespace);
            }

            try
            {
                Saml2Advice advice = new Saml2Advice();
                bool isEmpty = reader.IsEmptyElement;

                // @attributes

                // @xsi:type
                XmlUtil.ValidateXsiType(reader, Saml2Constants.Types.AdviceType, Saml2Constants.Namespace);

                reader.Read();
                if (!isEmpty)
                {
                    // <AssertionIDRef|AssertionURIRef|Assertion|EncryptedAssertion|other:any> 0-OO
                    while (reader.IsStartElement())
                    {
                        // <AssertionIDRef>, <AssertionURIRef>, <Assertion>, <EncryptedAssertion>
                        if (reader.IsStartElement(Saml2Constants.Elements.AssertionIDRef, Saml2Constants.Namespace))
                        {
                            advice.AssertionIdReferences.Add(ReadSimpleNCNameElement(reader));
                        }
                        else if (reader.IsStartElement(Saml2Constants.Elements.AssertionURIRef, Saml2Constants.Namespace))
                        {
                            advice.AssertionUriReferences.Add(ReadSimpleUriElement(reader));
                        }
                        else if (reader.IsStartElement(Saml2Constants.Elements.Assertion, Saml2Constants.Namespace))
                        {
                            advice.Assertions.Add(this.ReadAssertion(reader));
                        }
                        else if (reader.IsStartElement(Saml2Constants.Elements.EncryptedAssertion, Saml2Constants.Namespace))
                        {
                            advice.Assertions.Add(this.ReadAssertion(reader));
                        }
                        else
                        {
                            TraceUtility.TraceString(TraceEventType.Warning, SR.GetString(SR.ID8006, reader.LocalName, reader.NamespaceURI));
                            reader.Skip();
                        }
                    }

                    reader.ReadEndElement();
                }

                return advice;
            }
            catch (Exception e)
            {
                if (System.Runtime.Fx.IsFatal(e))
                    throw;
                
                Exception wrapped = TryWrapReadException(reader, e);
                if (null == wrapped)
                {
                    throw;
                }
                else
                {
                    throw wrapped;
                }
            }
        }