< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.JsonMessageEncoderFactory
Assembly: CoreWCF.WebHttp
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.WebHttp/src/CoreWCF/Channels/JsonMessageEncoderFactory.cs
Line coverage
59%
Covered lines: 105
Uncovered lines: 71
Coverable lines: 176
Total lines: 535
Line coverage: 59.6%
Branch coverage
51%
Covered branches: 34
Total branches: 66
Branch coverage: 51.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.WebHttp/src/CoreWCF/Channels/JsonMessageEncoderFactory.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.IO;
 6using System.Runtime.Serialization.Json;
 7using System.Text;
 8using System.Threading.Tasks;
 9using System.Xml;
 10using CoreWCF.Runtime;
 11using Microsoft.Extensions.ObjectPool;
 12
 13namespace CoreWCF.Channels
 14{
 15    internal class JsonMessageEncoderFactory : MessageEncoderFactory
 16    {
 117        private static readonly ContentEncoding[] s_applicationJsonContentEncoding = GetContentEncodingMap(JsonGlobals.A
 18        private readonly JsonMessageEncoder _messageEncoder;
 19
 2920        public JsonMessageEncoderFactory(Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, XmlDictionar
 21        {
 2922            _messageEncoder = new JsonMessageEncoder(writeEncoding, maxReadPoolSize, maxWritePoolSize, quotas, crossDoma
 2923        }
 24
 2925        public override MessageEncoder Encoder => _messageEncoder;
 26
 027        public override MessageVersion MessageVersion => _messageEncoder.MessageVersion;
 28
 29        internal static string GetContentType(WebMessageEncodingBindingElement encodingElement)
 30        {
 031            if (encodingElement == null)
 32            {
 033                return WebMessageEncoderFactory.GetContentType(JsonGlobals.ApplicationJsonMediaType, TextEncoderDefaults
 34            }
 35            else
 36            {
 037                return WebMessageEncoderFactory.GetContentType(JsonGlobals.ApplicationJsonMediaType, encodingElement.Wri
 38            }
 39        }
 40
 41        private static ContentEncoding[] GetContentEncodingMap(string mediaType)
 42        {
 143            Encoding[] readEncodings = ContentTypeHelpers.GetSupportedEncodings();
 144            ContentEncoding[] map = new ContentEncoding[readEncodings.Length];
 845            for (int i = 0; i < readEncodings.Length; i++)
 46            {
 347                ContentEncoding contentEncoding = new ContentEncoding();
 348                contentEncoding.contentType = WebMessageEncoderFactory.GetContentType(mediaType, readEncodings[i]);
 349                contentEncoding.encoding = readEncodings[i];
 350                map[i] = contentEncoding;
 51            }
 52
 153            return map;
 54        }
 55
 56        internal class JsonMessageEncoder : MessageEncoder
 57        {
 58            private const int MaxPooledXmlReadersPerMessage = 2;
 59
 60            // Double-checked locking pattern requires volatile for read/write synchronization
 61            private volatile SynchronizedPool<JsonBufferedMessageData> _bufferedReaderPool;
 62            private volatile SynchronizedPool<JsonBufferedMessageWriter> _bufferedWriterPool;
 63            private readonly int _maxReadPoolSize;
 64            private readonly int _maxWritePoolSize;
 65            private readonly OnXmlDictionaryReaderClose _onStreamedReaderClose;
 66            private readonly XmlDictionaryReaderQuotas _readerQuotas;
 67            private readonly XmlDictionaryReaderQuotas _bufferedReadReaderQuotas;
 68
 69            // Double-checked locking pattern requires volatile for read/write synchronization
 70            private volatile SynchronizedPool<RecycledMessageState> _recycledStatePool;
 71            private volatile SynchronizedPool<XmlDictionaryReader> _streamedReaderPool;
 72            private volatile SynchronizedPool<XmlDictionaryWriter> _streamedWriterPool;
 73            private readonly Encoding _writeEncoding;
 74
 2975            public JsonMessageEncoder(Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, XmlDictionaryRe
 76            {
 2977                if (writeEncoding == null)
 78                {
 079                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(writeEncoding));
 80                }
 81
 2982                ThisLock = new object();
 83
 2984                TextEncoderDefaults.ValidateEncoding(writeEncoding);
 2985                _writeEncoding = writeEncoding;
 86
 2987                _maxReadPoolSize = maxReadPoolSize;
 2988                _maxWritePoolSize = maxWritePoolSize;
 89
 2990                _readerQuotas = new XmlDictionaryReaderQuotas();
 2991                _onStreamedReaderClose = new OnXmlDictionaryReaderClose(ReturnStreamedReader);
 2992                quotas.CopyTo(_readerQuotas);
 93
 2994                _bufferedReadReaderQuotas = EncoderHelpers.GetBufferedReadQuotas(_readerQuotas);
 95
 2996                ContentType = WebMessageEncoderFactory.GetContentType(JsonGlobals.ApplicationJsonMediaType, writeEncodin
 2997            }
 98
 099            public override string ContentType { get; }
 100
 0101            public override string MediaType => JsonGlobals.ApplicationJsonMediaType;
 102
 30103            public override MessageVersion MessageVersion => MessageVersion.None;
 104
 105            private SynchronizedPool<RecycledMessageState> RecycledStatePool
 106            {
 107                get
 108                {
 6109                    if (_recycledStatePool == null)
 110                    {
 6111                        lock (ThisLock)
 112                        {
 6113                            if (_recycledStatePool == null)
 114                            {
 6115                                _recycledStatePool = new SynchronizedPool<RecycledMessageState>(_maxReadPoolSize);
 116                            }
 6117                        }
 118                    }
 119
 6120                    return _recycledStatePool;
 121                }
 122            }
 123
 36124            private object ThisLock { get; }
 125
 126            public override bool IsContentTypeSupported(string contentType)
 127            {
 9128                if (contentType == null)
 129                {
 0130                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(contentType));
 131                }
 132
 9133                return IsJsonContentType(contentType);
 134            }
 135
 136            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentTy
 137            {
 6138                if (bufferManager == null)
 139                {
 0140                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(bufferMan
 141                }
 142
 143                //if (WebTD.JsonMessageDecodingStartIsEnabled())
 144                //{
 145                //    WebTD.JsonMessageDecodingStart();
 146                //}
 147
 148                Message message;
 149
 6150                JsonBufferedMessageData messageData = TakeBufferedReader();
 6151                messageData.Encoding = ContentTypeHelpers.GetEncodingFromContentType(contentType, JsonMessageEncoderFact
 6152                messageData.Open(buffer, bufferManager);
 6153                RecycledMessageState messageState = messageData.TakeMessageState();
 6154                if (messageState == null)
 155                {
 6156                    messageState = new RecycledMessageState();
 157                }
 6158                message = new BufferedMessage(messageData, messageState);
 159
 6160                message.Properties.Encoder = this;
 161
 162                //if (SMTD.MessageReadByEncoderIsEnabled() && buffer != null)
 163                //{
 164                //    SMTD.MessageReadByEncoder(
 165                //        EventTraceActivityHelper.TryExtractActivity(message, true),
 166                //        buffer.Count,
 167                //        this);
 168                //}
 169
 170                //if (MessageLogger.LogMessagesAtTransportLevel)
 171                //{
 172                //    MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
 173                //}
 174
 6175                return message;
 176            }
 177
 178            public override Task<Message> ReadMessageAsync(Stream stream, int maxSizeOfHeaders, string contentType)
 179            {
 0180                if (stream == null)
 181                {
 0182                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(stream)))
 183                }
 184
 185                //if (WebTD.JsonMessageDecodingStartIsEnabled())
 186                //{
 187                //    WebTD.JsonMessageDecodingStart();
 188                //}
 189
 0190                XmlReader reader = TakeStreamedReader(stream, ContentTypeHelpers.GetEncodingFromContentType(contentType,
 0191                Message message = Message.CreateMessage(reader, maxSizeOfHeaders, MessageVersion.None);
 0192                message.Properties.Encoder = this;
 193
 194                //if (SMTD.StreamedMessageReadByEncoderIsEnabled())
 195                //{
 196                //    SMTD.StreamedMessageReadByEncoder(EventTraceActivityHelper.TryExtractActivity(message, true));
 197                //}
 198
 199                //if (MessageLogger.LogMessagesAtTransportLevel)
 200                //{
 201                //    MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
 202                //}
 203
 0204                return Task.FromResult(message);
 205            }
 206
 207            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferMan
 208            {
 24209                if (message == null)
 210                {
 0211                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(message))
 212                }
 213
 24214                if (bufferManager == null)
 215                {
 0216                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(bufferManager)), message);
 217                }
 218
 24219                if (maxMessageSize < 0)
 220                {
 0221                    throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(maxMessageSize), maxMessa
 0222                        SR.Format(SRCommon.ValueMustBeNonNegative)), message);
 223                }
 224
 24225                if (messageOffset < 0 || messageOffset > maxMessageSize)
 226                {
 0227                    throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(messageOffset), messageOf
 0228                        SR.Format(SR.JsonValueMustBeInRange, 0, maxMessageSize)), message);
 229                }
 230
 231                //EventTraceActivity eventTraceActivity = null;
 232                //if (WebTD.JsonMessageEncodingStartIsEnabled())
 233                //{
 234                //    eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
 235                //    WebTD.JsonMessageEncodingStart(eventTraceActivity);
 236                //}
 237
 24238                ThrowIfMismatchedMessageVersion(message);
 24239                message.Properties.Encoder = this;
 24240                JsonBufferedMessageWriter messageWriter = TakeBufferedWriter();
 241
 24242                ArraySegment<byte> messageData = messageWriter.WriteMessage(message, bufferManager, messageOffset, maxMe
 24243                ReturnMessageWriter(messageWriter);
 244
 245                //if (SMTD.MessageWrittenByEncoderIsEnabled() && messageData != null)
 246                //{
 247                //    SMTD.MessageWrittenByEncoder(
 248                //        eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message),
 249                //        messageData.Count,
 250                //        this);
 251                //}
 252
 253                //if (MessageLogger.LogMessagesAtTransportLevel)
 254                //{
 255                //    XmlDictionaryReader xmlDictionaryReader = JsonReaderWriterFactory.CreateJsonReader(
 256                //        messageData.Array, messageData.Offset, messageData.Count, null, XmlDictionaryReaderQuotas.Max,
 257                //    MessageLogger.LogMessage(ref message, xmlDictionaryReader, MessageLoggingSource.TransportSend);
 258                //}
 259
 24260                return messageData;
 261            }
 262
 263            public override Task WriteMessageAsync(Message message, Stream stream)
 264            {
 0265                if (message == null)
 266                {
 0267                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(message))
 268                }
 269
 0270                if (stream == null)
 271                {
 0272                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(stream)), message);
 273                }
 274
 0275                ThrowIfMismatchedMessageVersion(message);
 276
 277                //EventTraceActivity eventTraceActivity = null;
 278                //if (WebTD.JsonMessageEncodingStartIsEnabled())
 279                //{
 280                //    eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
 281                //    WebTD.JsonMessageEncodingStart(eventTraceActivity);
 282                //}
 283
 0284                message.Properties.Encoder = this;
 0285                XmlDictionaryWriter xmlWriter = TakeStreamedWriter(stream);
 286
 0287                xmlWriter.WriteStartDocument();
 0288                message.WriteMessage(xmlWriter);
 0289                xmlWriter.WriteEndDocument();
 0290                xmlWriter.Flush();
 0291                ReturnStreamedWriter(xmlWriter);
 292
 293                //if (SMTD.StreamedMessageWrittenByEncoderIsEnabled())
 294                //{
 295                //    SMTD.StreamedMessageWrittenByEncoder(
 296                //        eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message));
 297                //}
 298
 299                //if (MessageLogger.LogMessagesAtTransportLevel)
 300                //{
 301                //    MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
 302                //}
 303
 0304                return Task.CompletedTask;
 305            }
 306
 0307            protected override bool IsCharSetSupported(string charSet) => TextEncoderDefaults.TryGetEncoding(charSet, ou
 308
 9309            private bool IsJsonContentType(string contentType) => IsContentTypeSupported(contentType, JsonGlobals.Applic
 310
 311            private void ReturnBufferedData(JsonBufferedMessageData messageData)
 312            {
 0313                _bufferedReaderPool.Return(messageData);
 0314            }
 315
 316            private void ReturnMessageWriter(JsonBufferedMessageWriter messageWriter)
 317            {
 24318                _bufferedWriterPool.Return(messageWriter);
 24319            }
 320
 321            private void ReturnStreamedReader(XmlDictionaryReader xmlReader)
 322            {
 0323                _streamedReaderPool.Return(xmlReader);
 0324            }
 325
 326            private void ReturnStreamedWriter(XmlWriter xmlWriter)
 327            {
 0328                xmlWriter.Close();
 0329                _streamedWriterPool.Return((XmlDictionaryWriter)xmlWriter);
 0330            }
 331
 332            private JsonBufferedMessageData TakeBufferedReader()
 333            {
 6334                if (_bufferedReaderPool == null)
 335                {
 6336                    lock (ThisLock)
 337                    {
 6338                        if (_bufferedReaderPool == null)
 339                        {
 6340                            _bufferedReaderPool = new SynchronizedPool<JsonBufferedMessageData>(_maxReadPoolSize);
 341                        }
 6342                    }
 343                }
 344
 6345                JsonBufferedMessageData messageData = _bufferedReaderPool.Take();
 6346                if (messageData == null)
 347                {
 6348                    messageData = new JsonBufferedMessageData(this, MaxPooledXmlReadersPerMessage);
 349                }
 350
 6351                return messageData;
 352            }
 353
 354            private JsonBufferedMessageWriter TakeBufferedWriter()
 355            {
 24356                if (_bufferedWriterPool == null)
 357                {
 24358                    lock (ThisLock)
 359                    {
 24360                        if (_bufferedWriterPool == null)
 361                        {
 24362                            _bufferedWriterPool = new SynchronizedPool<JsonBufferedMessageWriter>(_maxWritePoolSize);
 363                        }
 24364                    }
 365                }
 366
 24367                JsonBufferedMessageWriter messageWriter = _bufferedWriterPool.Take();
 24368                if (messageWriter == null)
 369                {
 24370                    messageWriter = new JsonBufferedMessageWriter(this);
 371                }
 372
 24373                return messageWriter;
 374            }
 375
 376            private XmlDictionaryReader TakeStreamedReader(Stream stream, Encoding enc)
 377            {
 0378                if (_streamedReaderPool == null)
 379                {
 0380                    lock (ThisLock)
 381                    {
 0382                        if (_streamedReaderPool == null)
 383                        {
 0384                            _streamedReaderPool = new SynchronizedPool<XmlDictionaryReader>(_maxReadPoolSize);
 385                        }
 0386                    }
 387                }
 388
 0389                XmlDictionaryReader xmlReader = _streamedReaderPool.Take();
 0390                if (xmlReader == null)
 391                {
 0392                    xmlReader = JsonReaderWriterFactory.CreateJsonReader(stream, enc, _readerQuotas, _onStreamedReaderCl
 393                }
 394                else
 395                {
 0396                    ((IXmlJsonReaderInitializer)xmlReader).SetInput(stream, enc, _readerQuotas, _onStreamedReaderClose);
 397                }
 398
 0399                return xmlReader;
 400            }
 401
 402            private XmlDictionaryWriter TakeStreamedWriter(Stream stream)
 403            {
 0404                if (_streamedWriterPool == null)
 405                {
 0406                    lock (ThisLock)
 407                    {
 0408                        if (_streamedWriterPool == null)
 409                        {
 0410                            _streamedWriterPool = new SynchronizedPool<XmlDictionaryWriter>(_maxWritePoolSize);
 411                        }
 0412                    }
 413                }
 414
 0415                XmlDictionaryWriter xmlWriter = _streamedWriterPool.Take();
 0416                if (xmlWriter == null)
 417                {
 0418                    xmlWriter = JsonReaderWriterFactory.CreateJsonWriter(stream, _writeEncoding, false);
 419                }
 420                else
 421                {
 0422                    ((IXmlJsonWriterInitializer)xmlWriter).SetOutput(stream, _writeEncoding, false);
 423                }
 424
 0425                return xmlWriter;
 426            }
 427
 428            internal class JsonBufferedMessageData : BufferedMessageData
 429            {
 430                private Encoding _encoding;
 431                private readonly JsonMessageEncoder _messageEncoder;
 432                private readonly OnXmlDictionaryReaderClose _onClose;
 433                private readonly Pool<XmlDictionaryReader> _readerPool;
 434
 435                public JsonBufferedMessageData(JsonMessageEncoder messageEncoder, int maxReaderPoolSize)
 6436                    : base(messageEncoder.RecycledStatePool)
 437                {
 6438                    _messageEncoder = messageEncoder;
 6439                    _onClose = new OnXmlDictionaryReaderClose(OnXmlReaderClosed);
 6440                    _readerPool = new Pool<XmlDictionaryReader>(maxReaderPoolSize);
 6441                }
 442
 6443                public override MessageEncoder MessageEncoder => _messageEncoder;
 444
 6445                public override XmlDictionaryReaderQuotas Quotas => _messageEncoder._bufferedReadReaderQuotas;
 446
 447                internal Encoding Encoding
 448                {
 449                    set
 450                    {
 6451                        _encoding = value;
 6452                    }
 453                }
 454
 455                protected override void OnClosed()
 456                {
 0457                    _messageEncoder.ReturnBufferedData(this);
 0458                }
 459
 460                protected override void ReturnXmlReader(XmlDictionaryReader xmlReader)
 461                {
 0462                    if (xmlReader != null)
 463                    {
 0464                        _readerPool.Return(xmlReader);
 465                    }
 0466                }
 467
 468                protected override XmlDictionaryReader TakeXmlReader()
 469                {
 6470                    ArraySegment<byte> buffer = Buffer;
 471
 6472                    XmlDictionaryReader xmlReader = _readerPool.Take();
 6473                    if (xmlReader == null)
 474                    {
 6475                        xmlReader = JsonReaderWriterFactory.CreateJsonReader(buffer.Array, buffer.Offset, buffer.Count, 
 476                    }
 477                    else
 478                    {
 0479                        ((IXmlJsonReaderInitializer)xmlReader).SetInput(buffer.Array, buffer.Offset, buffer.Count, _enco
 480                    }
 481
 6482                    return xmlReader;
 483                }
 484            }
 485
 486            internal class JsonBufferedMessageWriter : BufferedMessageWriter
 487            {
 488                private readonly JsonMessageEncoder _messageEncoder;
 489                private XmlDictionaryWriter _returnedWriter;
 490
 24491                public JsonBufferedMessageWriter(JsonMessageEncoder messageEncoder)
 492                {
 24493                    _messageEncoder = messageEncoder;
 24494                }
 495
 496                protected override void OnWriteEndMessage(XmlDictionaryWriter writer)
 497                {
 24498                    writer.WriteEndDocument();
 24499                }
 500
 501                protected override void OnWriteStartMessage(XmlDictionaryWriter writer)
 502                {
 24503                    writer.WriteStartDocument();
 24504                }
 505
 506                protected override void ReturnXmlWriter(XmlDictionaryWriter writer)
 507                {
 24508                    writer.Close();
 509
 24510                    if (_returnedWriter == null)
 511                    {
 24512                        _returnedWriter = writer;
 513                    }
 24514                }
 515
 516                protected override XmlDictionaryWriter TakeXmlWriter(Stream stream)
 517                {
 518                    XmlDictionaryWriter writer;
 24519                    if (_returnedWriter == null)
 520                    {
 24521                        writer = JsonReaderWriterFactory.CreateJsonWriter(stream, _messageEncoder._writeEncoding, false)
 522                    }
 523                    else
 524                    {
 0525                        writer = _returnedWriter;
 0526                        ((IXmlJsonWriterInitializer)writer).SetOutput(stream, _messageEncoder._writeEncoding, false);
 0527                        _returnedWriter = null;
 528                    }
 529
 24530                    return writer;
 531                }
 532            }
 533        }
 534    }
 535}

Methods/Properties

.cctor()
.ctor(System.Text.Encoding,System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas,System.Boolean)
Encoder()
MessageVersion()
GetContentType(CoreWCF.Channels.WebMessageEncodingBindingElement)
GetContentEncodingMap(System.String)
.ctor(System.Text.Encoding,System.Int32,System.Int32,System.Xml.XmlDictionaryReaderQuotas,System.Boolean)
ContentType()
MediaType()
MessageVersion()
RecycledStatePool()
ThisLock()
IsContentTypeSupported(System.String)
ReadMessage(System.ArraySegment`1<System.Byte>,CoreWCF.Channels.BufferManager,System.String)
ReadMessageAsync(System.IO.Stream,System.Int32,System.String)
WriteMessage(CoreWCF.Channels.Message,System.Int32,CoreWCF.Channels.BufferManager,System.Int32)
WriteMessageAsync(CoreWCF.Channels.Message,System.IO.Stream)
IsCharSetSupported(System.String)
IsJsonContentType(System.String)
ReturnBufferedData(CoreWCF.Channels.JsonMessageEncoderFactory/JsonMessageEncoder/JsonBufferedMessageData)
ReturnMessageWriter(CoreWCF.Channels.JsonMessageEncoderFactory/JsonMessageEncoder/JsonBufferedMessageWriter)
ReturnStreamedReader(System.Xml.XmlDictionaryReader)
ReturnStreamedWriter(System.Xml.XmlWriter)
TakeBufferedReader()
TakeBufferedWriter()
TakeStreamedReader(System.IO.Stream,System.Text.Encoding)
TakeStreamedWriter(System.IO.Stream)
.ctor(CoreWCF.Channels.JsonMessageEncoderFactory/JsonMessageEncoder,System.Int32)
MessageEncoder()
Quotas()
Encoding(System.Text.Encoding)
OnClosed()
ReturnXmlReader(System.Xml.XmlDictionaryReader)
TakeXmlReader()
.ctor(CoreWCF.Channels.JsonMessageEncoderFactory/JsonMessageEncoder)
OnWriteEndMessage(System.Xml.XmlDictionaryWriter)
OnWriteStartMessage(System.Xml.XmlDictionaryWriter)
ReturnXmlWriter(System.Xml.XmlDictionaryWriter)
TakeXmlWriter(System.IO.Stream)