PageRenderTime 4ms CodeModel.GetById 22ms app.highlight 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/MassTransit/Automatonymous/Activities/FaultRequestActivity.cs

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