PageRenderTime 2ms CodeModel.GetById 75ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 1ms

/src/MassTransit/Automatonymous/Activities/CompleteRequestActivity.cs

http://github.com/phatboyg/MassTransit
C# | 188 lines | 140 code | 48 blank | 0 comment | 12 complexity | ecf7d12bb2e8ff0d08076dae4e635261 MD5 | raw file
  1namespace Automatonymous.Activities
  2{
  3    using System;
  4    using System.Collections.Generic;
  5    using System.IO;
  6    using System.Linq;
  7    using System.Text;
  8    using System.Threading.Tasks;
  9    using System.Xml.Linq;
 10    using Contracts;
 11    using GreenPipes;
 12    using MassTransit;
 13    using MassTransit.Serialization;
 14    using Newtonsoft.Json;
 15    using Newtonsoft.Json.Linq;
 16    using Requests;
 17
 18
 19    public class CompleteRequestActivity :
 20        Activity<RequestState, RequestCompleted>
 21    {
 22        public void Probe(ProbeContext context)
 23        {
 24            context.CreateScope("completeRequest");
 25        }
 26
 27        public void Accept(StateMachineVisitor visitor)
 28        {
 29            visitor.Visit(this);
 30        }
 31
 32        public async Task Execute(BehaviorContext<RequestState, RequestCompleted> context, Behavior<RequestState, RequestCompleted> next)
 33        {
 34            if (!context.Instance.ExpirationTime.HasValue || context.Instance.ExpirationTime.Value > DateTime.UtcNow)
 35            {
 36                if (!context.TryGetPayload(out ConsumeContext<RequestCompleted> consumeContext))
 37                    throw new ArgumentException("The ConsumeContext was not present", nameof(context));
 38
 39                string body = GetResponseBody(consumeContext, context.Instance);
 40
 41                IPipe<SendContext> pipe = new CompletedMessagePipe(context.GetPayload<ConsumeContext<RequestCompleted>>(), context.Instance, body);
 42
 43                var endpoint = await context.GetSendEndpoint(context.Instance.ResponseAddress).ConfigureAwait(false);
 44
 45                var scheduled = new CompletedEvent();
 46
 47                await endpoint.Send(scheduled, pipe).ConfigureAwait(false);
 48            }
 49
 50            await next.Execute(context).ConfigureAwait(false);
 51        }
 52
 53        public Task Faulted<TException>(BehaviorExceptionContext<RequestState, RequestCompleted, TException> context,
 54            Behavior<RequestState, RequestCompleted> next)
 55            where TException : Exception
 56        {
 57            return next.Faulted(context);
 58        }
 59
 60        static string GetResponseBody(ConsumeContext<RequestCompleted> context, RequestState requestState)
 61        {
 62            string body = Encoding.UTF8.GetString(context.ReceiveContext.GetBody());
 63
 64            var mediaType = context.ReceiveContext.ContentType?.MediaType;
 65
 66            if (JsonMessageSerializer.JsonContentType.MediaType.Equals(mediaType, StringComparison.OrdinalIgnoreCase))
 67                return TranslateJsonBody(body, requestState);
 68
 69            if (XmlMessageSerializer.XmlContentType.MediaType.Equals(mediaType, StringComparison.OrdinalIgnoreCase))
 70                return TranslateXmlBody(body, requestState);
 71
 72            throw new InvalidOperationException("Only JSON and XML messages can be scheduled");
 73        }
 74
 75        static string TranslateJsonBody(string body, RequestState requestState)
 76        {
 77            JObject envelope = JObject.Parse(body);
 78
 79            envelope["destinationAddress"] = requestState.ResponseAddress.ToString();
 80
 81            JToken message = envelope["message"];
 82
 83            JToken payload = message["payload"];
 84            JToken payloadType = message["payloadType"];
 85
 86            envelope["message"] = payload;
 87            envelope["messageType"] = payloadType;
 88
 89            if (requestState.ConversationId.HasValue)
 90                envelope["conversationId"] = requestState.ConversationId.Value.ToString("D");
 91
 92            envelope["sourceAddress"] = requestState.SagaAddress.ToString();
 93            envelope["requestId"] = requestState.CorrelationId.ToString("D");
 94
 95            if (requestState.FaultAddress != null)
 96                envelope["faultAddress"] = requestState.FaultAddress.ToString();
 97
 98            return JsonConvert.SerializeObject(envelope, Formatting.Indented);
 99        }
100
101        static string TranslateXmlBody(string body, RequestState requestState)
102        {
103            using (var reader = new StringReader(body))
104            {
105                XDocument document = XDocument.Load(reader);
106
107                XElement envelope = (from e in document.Descendants("envelope") select e).Single();
108
109                XElement destinationAddress = (from a in envelope.Descendants("destinationAddress") select a).Single();
110
111                XElement message = (from m in envelope.Descendants("message") select m).Single();
112                IEnumerable<XElement> messageType = (from mt in envelope.Descendants("messageType") select mt);
113
114                XElement payload = (from p in message.Descendants("payload") select p).Single();
115                IEnumerable<XElement> payloadType = (from pt in message.Descendants("payloadType") select pt);
116
117                message.Remove();
118                messageType.Remove();
119
120                if (requestState.ConversationId.HasValue)
121                {
122                    XElement conversationId = (from a in envelope.Descendants("conversationId") select a).Single();
123                    conversationId.Value = requestState.ConversationId.Value.ToString("D");
124                }
125
126                destinationAddress.Value = requestState.ResponseAddress.ToString();
127
128                XElement sourceAddress = (from a in envelope.Descendants("sourceAddress") select a).Single();
129                sourceAddress.Value = requestState.SagaAddress.ToString();
130
131                message = new XElement("message");
132                message.Add(payload.Descendants());
133                envelope.Add(message);
134
135                envelope.Add(payloadType.Select(x => new XElement("messageType", x.Value)));
136
137                envelope.Add(new XElement("requestId", requestState.CorrelationId.ToString("D")));
138                if (requestState.FaultAddress != null)
139                    envelope.Add(new XElement("faultAddress", requestState.FaultAddress.ToString()));
140
141                return document.ToString(SaveOptions.DisableFormatting);
142            }
143        }
144
145
146        class CompletedEvent
147        {
148        }
149
150
151        class CompletedMessagePipe :
152            IPipe<SendContext>
153        {
154            readonly ConsumeContext<RequestCompleted> _context;
155            readonly RequestState _instance;
156            readonly string _body;
157
158            public CompletedMessagePipe(ConsumeContext<RequestCompleted> context, RequestState instance, string body)
159            {
160                _context = context;
161                _instance = instance;
162                _body = body;
163            }
164
165            void IProbeSite.Probe(ProbeContext context)
166            {
167            }
168
169            public async Task Send(SendContext context)
170            {
171                context.DestinationAddress = _instance.ResponseAddress;
172                context.SourceAddress = _instance.SagaAddress;
173                context.FaultAddress = _instance.FaultAddress;
174                context.RequestId = _instance.CorrelationId;
175
176                if (_instance.ExpirationTime.HasValue)
177                {
178                    var timeToLive = DateTime.UtcNow - _instance.ExpirationTime.Value;
179                    context.TimeToLive = timeToLive > TimeSpan.Zero ? timeToLive : TimeSpan.FromSeconds(1);
180                }
181
182                var bodySerializer = new StringMessageSerializer(_context.ReceiveContext.ContentType, _body);
183
184                context.Serializer = bodySerializer;
185            }
186        }
187    }
188}