File: System\Web\Services\Protocols\SoapMessage.cs
Project: ndp\cdf\src\NetFx20\System.Web.Services\System.Web.Services.csproj (System.Web.Services)
//------------------------------------------------------------------------------
// <copyright file="SoapMessage.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Web.Services.Protocols {
    using System.Web.Services;
    using System.Xml.Serialization;
    using System;
    using System.Reflection;
    using System.Collections;
    using System.IO;
    using System.ComponentModel;
    using System.Security.Permissions;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System.Web.Services.Diagnostics;
 
    /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage"]/*' />
    /// <devdoc>
    ///    <para>[To be supplied.]</para>
    /// </devdoc>
    [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")]
    public abstract class SoapMessage {
        SoapMessageStage stage;
        SoapHeaderCollection headers = new SoapHeaderCollection();
        Stream stream;
        SoapExtensionStream extensionStream;
        string contentType;
        string contentEncoding;
        object[] parameterValues;
        SoapException exception;
 
        internal SoapMessage() { }
 
        internal void SetParameterValues(object[] parameterValues) {
            this.parameterValues = parameterValues;
        }
 
        internal object[] GetParameterValues() {
            return parameterValues;
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.OneWay"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public abstract bool OneWay {
            get;
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.GetInParameterValue"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public object GetInParameterValue(int index) {
            EnsureInStage();
            EnsureNoException();
            if (index < 0 || index >= parameterValues.Length) throw new IndexOutOfRangeException(Res.GetString(Res.indexMustBeBetweenAnd0Inclusive, parameterValues.Length));
            return parameterValues[index];
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.GetOutParameterValue"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public object GetOutParameterValue(int index) {
            EnsureOutStage();
            EnsureNoException();
            if (!MethodInfo.IsVoid) {
                if (index == int.MaxValue)
                    throw new IndexOutOfRangeException(Res.GetString(Res.indexMustBeBetweenAnd0Inclusive, parameterValues.Length));
                index++;
            }
            if (index < 0 || index >= parameterValues.Length) throw new IndexOutOfRangeException(Res.GetString(Res.indexMustBeBetweenAnd0Inclusive, parameterValues.Length));
            return parameterValues[index];
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.GetReturnValue"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public object GetReturnValue() {
            EnsureOutStage();
            EnsureNoException();
            if (MethodInfo.IsVoid) throw new InvalidOperationException(Res.GetString(Res.WebNoReturnValue));
            return parameterValues[0];
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.EnsureOutStage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected abstract void EnsureOutStage();
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.EnsureInStage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected abstract void EnsureInStage();
 
        void EnsureNoException() {
            if (exception != null) throw new InvalidOperationException(Res.GetString(Res.WebCannotAccessValue), exception);
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.Exception"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public SoapException Exception {
            get { return exception; }
            set { exception = value; }
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.MethodInfo"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public abstract LogicalMethodInfo MethodInfo {
            get;
        }
 
        /*
        internal abstract SoapReflectedExtension[] Extensions {
            get;
        }
 
        internal abstract object[] ExtensionInitializers {
            get;
        }
        */
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.EnsureStage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected void EnsureStage(SoapMessageStage stage) {
            if ((this.stage & stage) == 0) throw new InvalidOperationException(Res.GetString(Res.WebCannotAccessValueStage, this.stage.ToString()));
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.Headers"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public SoapHeaderCollection Headers {
            get { return headers; }
        }
 
        internal void SetStream(Stream stream) {
            if (extensionStream != null) {
                extensionStream.SetInnerStream(stream);
                extensionStream.SetStreamReady();
                // The extension stream should now be referenced by either this.stream
                // or an extension that has chained it to another stream.
                extensionStream = null;
            }
            else
                this.stream = stream;
        }
 
        internal void SetExtensionStream(SoapExtensionStream extensionStream) {
            this.extensionStream = extensionStream;
            this.stream = extensionStream;
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.Stream"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public Stream Stream {
            get { return stream; }
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.ContentType"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public string ContentType {
            get { EnsureStage(SoapMessageStage.BeforeSerialize | SoapMessageStage.BeforeDeserialize); return contentType; }
            set { EnsureStage(SoapMessageStage.BeforeSerialize | SoapMessageStage.BeforeDeserialize); contentType = value; }
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.ContentEncoding"]/*' />
        public string ContentEncoding {
            get { EnsureStage(SoapMessageStage.BeforeSerialize | SoapMessageStage.BeforeDeserialize); return contentEncoding; }
            set { EnsureStage(SoapMessageStage.BeforeSerialize | SoapMessageStage.BeforeDeserialize); contentEncoding = value; }
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.Stage"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public SoapMessageStage Stage {
            get { return stage; }
        }
 
        internal void SetStage(SoapMessageStage stage) {
            this.stage = stage;
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.Url"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public abstract string Url {
            get;
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.Action"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public abstract string Action {
            get;
        }
 
        /// <include file='doc\SoapMessage.uex' path='docs/doc[@for="SoapMessage.SoapVersion"]/*' />
        [ComVisible(false)]
        [DefaultValue(SoapProtocolVersion.Default)]
        public virtual SoapProtocolVersion SoapVersion {
            get { return SoapProtocolVersion.Default; }
        }
 
        internal static SoapExtension[] InitializeExtensions(SoapReflectedExtension[] reflectedExtensions, object[] extensionInitializers) {
            if (reflectedExtensions == null)
                return null;
            SoapExtension[] extensions = new SoapExtension[reflectedExtensions.Length];
            for (int i = 0; i < extensions.Length; i++) {
                extensions[i] = reflectedExtensions[i].CreateInstance(extensionInitializers[i]);
            }
            return extensions;
        }
 
        internal void InitExtensionStreamChain(SoapExtension[] extensions) {
            if (extensions == null)
                return;
            for (int i = 0; i < extensions.Length; i++) {
                stream = extensions[i].ChainStream(stream);
            }
        }
 
        internal void RunExtensions(SoapExtension[] extensions, bool throwOnException) {
            if (extensions == null)
                return;
 
            TraceMethod caller = Tracing.On ? new TraceMethod(this, "RunExtensions", extensions, throwOnException) : null;
 
            // Higher priority extensions (earlier in the list) run earlier for deserialization stages,
            // and later for serialization stages
            if ((stage & (SoapMessageStage.BeforeDeserialize | SoapMessageStage.AfterDeserialize)) != 0) {
                for (int i = 0; i < extensions.Length; i++) {
                    if (Tracing.On) Tracing.Enter("SoapExtension", caller, new TraceMethod(extensions[i], "ProcessMessage", stage));
                    extensions[i].ProcessMessage(this);
                    if (Tracing.On) Tracing.Exit("SoapExtension", caller);
                    if (Exception != null) {
                        if (throwOnException)
                            throw Exception;
                        if (Tracing.On) Tracing.ExceptionIgnore(TraceEventType.Warning, caller, Exception);
                    }
                }
            }
            else {
                for (int i = extensions.Length - 1; i >= 0; i--) {
                    if (Tracing.On) Tracing.Enter("SoapExtension", caller, new TraceMethod(extensions[i], "ProcessMessage", stage));
                    extensions[i].ProcessMessage(this);
                    if (Tracing.On) Tracing.Exit("SoapExtension", caller);
                    if (Exception != null) {
                        if (throwOnException)
                            throw Exception;
                        if (Tracing.On) Tracing.ExceptionIgnore(TraceEventType.Warning, caller, Exception);
                    }
                }
            }
        }
    }
}