File: System\ServiceModel\Web\WebOperationContext.cs
Project: ndp\cdf\src\NetFx35\System.ServiceModel.Web\System.ServiceModel.Web.csproj (System.ServiceModel.Web)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
#pragma warning disable 1634, 1691
 
namespace System.ServiceModel.Web
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.IO;
    using System.Net;
    using System.Runtime.Serialization.Json;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.ServiceModel.Syndication;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    using System.Xml.Serialization;
    using System.ServiceModel.Dispatcher;
 
    public class WebOperationContext : IExtension<OperationContext>
    {
        internal static readonly string DefaultTextMediaType = "text/plain";
        internal static readonly string DefaultJsonMediaType = JsonGlobals.applicationJsonMediaType;
        internal static readonly string DefaultXmlMediaType = "application/xml";
        internal static readonly string DefaultAtomMediaType = "application/atom+xml";
        internal static readonly string DefaultStreamMediaType = WebHttpBehavior.defaultStreamContentType;
 
        OperationContext operationContext;
 
        public WebOperationContext(OperationContext operationContext)
        {
            if (operationContext == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationContext");
            }
            this.operationContext = operationContext;
#pragma warning disable 56506 // Microsoft, operationContext.Extensions is never null
            if (operationContext.Extensions.Find<WebOperationContext>() == null)
            {
                operationContext.Extensions.Add(this);
            }
#pragma warning enable 56506
        }
 
        public static WebOperationContext Current
        {
            get
            {
                if (OperationContext.Current == null)
                {
                    return null;
                }
                WebOperationContext existing = OperationContext.Current.Extensions.Find<WebOperationContext>();
                if (existing != null)
                {
                    return existing;
                }
                return new WebOperationContext(OperationContext.Current);
            }
        }
 
        public IncomingWebRequestContext IncomingRequest
        { 
            get { return new IncomingWebRequestContext(this.operationContext); } 
        }
 
        public IncomingWebResponseContext IncomingResponse
        { 
            get { return new IncomingWebResponseContext(this.operationContext); } 
        }
 
        public OutgoingWebRequestContext OutgoingRequest
        { 
            get { return new OutgoingWebRequestContext(this.operationContext); } 
        }
 
        public OutgoingWebResponseContext OutgoingResponse
        { 
            get { return new OutgoingWebResponseContext(this.operationContext); } 
        }
 
        public void Attach(OperationContext owner)
        {
        }
        
        public void Detach(OperationContext owner)
        {
        }        
 
        public Message CreateJsonResponse<T>(T instance)
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            return CreateJsonResponse<T>(instance, serializer);
        }
 
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "CreateJsonMessage requires the DataContractJsonSerializer.  Allowing the base type XmlObjectSerializer would let deveopers supply a non-Json Serializer.")]
        public Message CreateJsonResponse<T>(T instance, DataContractJsonSerializer serializer)
        {
            if (serializer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, instance, serializer);
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.JsonProperty);
            AddContentType(WebOperationContext.DefaultJsonMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        public Message CreateXmlResponse<T>(T instance)
        {
            System.Runtime.Serialization.DataContractSerializer serializer = new System.Runtime.Serialization.DataContractSerializer(typeof(T));
            return CreateXmlResponse(instance, serializer);
        }
 
        public Message CreateXmlResponse<T>(T instance, System.Runtime.Serialization.XmlObjectSerializer serializer)
        {
            if (serializer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, instance, serializer);
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        public Message CreateXmlResponse<T>(T instance, XmlSerializer serializer)
        {
            if (serializer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, new XmlSerializerBodyWriter(instance, serializer));
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Other XNode derived types such as XAttribute don't make sense in this context, so we are not using the XNode base type.")]
        public Message CreateXmlResponse(XDocument document)
        {
            if (document == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("document");
            }
            Message message;
            if (document.FirstNode == null)
            {
                message = Message.CreateMessage(MessageVersion.None, (string)null);
            }
            else
            {
                message = Message.CreateMessage(MessageVersion.None, (string)null, document.CreateReader());
            }
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Other XNode derived types such as XAttribute don't make sense in this context, so we are not using the XNode base type.")]
        public Message CreateXmlResponse(XElement element)
        {
            if (element == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, element.CreateReader());
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultXmlMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        public Message CreateAtom10Response(SyndicationItem item)
        {
            if (item == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("item");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, item.GetAtom10Formatter());
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultAtomMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        public Message CreateAtom10Response(SyndicationFeed feed)
        {
            if (feed == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("feed");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, feed.GetAtom10Formatter());
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultAtomMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        public Message CreateAtom10Response(ServiceDocument document)
        {
            if (document == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("document");
            }
            Message message = Message.CreateMessage(MessageVersion.None, (string)null, document.GetFormatter());
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProperty);
            AddContentType(WebOperationContext.DefaultAtomMediaType, this.OutgoingResponse.BindingWriteEncoding);
            return message;
        }
 
        public Message CreateTextResponse(string text)
        {
            return CreateTextResponse(text, WebOperationContext.DefaultTextMediaType, Encoding.UTF8);
        }
 
        public Message CreateTextResponse(string text, string contentType)
        {
            return CreateTextResponse(text, contentType, Encoding.UTF8);
        }
 
        public Message CreateTextResponse(string text, string contentType, Encoding encoding)
        {
            if (text == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("text");
            }
            if (contentType == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
            }
            if (encoding == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoding");
            }
 
            Message message = new HttpStreamMessage(StreamBodyWriter.CreateStreamBodyWriter((stream) =>
            {
                byte[] preamble = encoding.GetPreamble();
                if (preamble.Length > 0)
                {
                    stream.Write(preamble, 0, preamble.Length);
                }
                byte[] bytes = encoding.GetBytes(text);
                stream.Write(bytes, 0, bytes.Length);
                stream.Flush();
            }));
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
            AddContentType(contentType, null);
            return message;
        }
 
        public Message CreateTextResponse(Action<TextWriter> textWriter, string contentType)
        {
            Encoding encoding = this.OutgoingResponse.BindingWriteEncoding;
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            return CreateTextResponse(textWriter, contentType, encoding);
        }
 
        public Message CreateTextResponse(Action<TextWriter> textWriter, string contentType, Encoding encoding)
        {
            if (textWriter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("textWriter");
            }
            if (contentType == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
            }
            if (encoding == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("encoding");
            }
 
            Message message = new HttpStreamMessage(StreamBodyWriter.CreateStreamBodyWriter((stream) =>
            {
                using (TextWriter writer = new StreamWriter(stream, encoding))
                {
                    textWriter(writer);
                }
            }));
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
            AddContentType(contentType, null);
            return message;
        }
 
        public Message CreateStreamResponse(Stream stream, string contentType)
        {
            if (stream == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("stream");
            }
            if (contentType == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
            }
            Message message = ByteStreamMessage.CreateMessage(stream);
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
            AddContentType(contentType, null);
            return message;
        }
 
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "Using the StreamBodyWriter type instead of the BodyWriter type for discoverability.  The StreamBodyWriter provides a helpful overload of the OnWriteBodyContents method that takes a Stream")]
        public Message CreateStreamResponse(StreamBodyWriter bodyWriter, string contentType)
        {
            if (bodyWriter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("bodyWriter");
            }
            if (contentType == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
            }
            Message message = new HttpStreamMessage(bodyWriter);
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
            AddContentType(contentType, null);
            return message;
        }
 
        public Message CreateStreamResponse(Action<Stream> streamWriter, string contentType)
        {
            if (streamWriter == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("streamWriter");
            }
            if (contentType == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contentType");
            }
            Message message = new HttpStreamMessage(StreamBodyWriter.CreateStreamBodyWriter(streamWriter));
            message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProperty);
            AddContentType(contentType, null);
            return message;
        }
 
        public UriTemplate GetUriTemplate(string operationName)
        {
            if (String.IsNullOrEmpty(operationName))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("operationName");
            }
 
            WebHttpDispatchOperationSelector selector = OperationContext.Current.EndpointDispatcher.DispatchRuntime.OperationSelector as WebHttpDispatchOperationSelector;
            if (selector == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR2.GetString(SR2.OperationSelectorNotWebSelector, typeof(WebHttpDispatchOperationSelector))));
            }
            return selector.GetUriTemplate(operationName);
        }
 
        void AddContentType(string contentType, Encoding encoding)
        {      
            if (string.IsNullOrEmpty(this.OutgoingResponse.ContentType))
            {
                if (encoding != null)
                {
                    contentType = WebMessageEncoderFactory.GetContentType(contentType, encoding);
                }
                this.OutgoingResponse.ContentType = contentType;
            }
        }
 
        class XmlSerializerBodyWriter : BodyWriter
        {
            object instance;
            XmlSerializer serializer;
 
            public XmlSerializerBodyWriter(object instance, XmlSerializer serializer)
                : base(false)
            {
                if (instance == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance");
                }
                if (serializer == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serializer");
                }
                this.instance = instance;
                this.serializer = serializer;
            }
 
            protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
            {
                serializer.Serialize(writer, instance);
            }
        }
    }
}