File: ContractInferenceHelper.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (733 lines) | stat: -rw-r--r-- 31,895 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.ServiceModel.Activities
{
    using System.Activities;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Net.Security;
    using System.Runtime;
    using System.ServiceModel.Activities.Description;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using System.Xml;
    using System.Xml.Linq;

    static class ContractInferenceHelper
    {
        static DataContractFormatAttribute dataContractFormatAttribute;
        static XmlSerializerFormatAttribute xmlSerializerFormatAttribute;
        static Type exceptionType;
        static Type faultExceptionType;

        public static DataContractFormatAttribute DataContractFormatAttribute
        {
            get
            {
                if (dataContractFormatAttribute == null)
                {
                    dataContractFormatAttribute = new DataContractFormatAttribute();
                }
                return dataContractFormatAttribute;
            }
        }

        public static XmlSerializerFormatAttribute XmlSerializerFormatAttribute
        {
            get
            {
                if (xmlSerializerFormatAttribute == null)
                {
                    xmlSerializerFormatAttribute = new XmlSerializerFormatAttribute
                    {
                        SupportFaults = true
                    };
                }
                return xmlSerializerFormatAttribute;
            }
        }

        public static Type ExceptionType
        {
            get
            {
                if (exceptionType == null)
                {
                    exceptionType = typeof(Exception);
                }
                return exceptionType;
            }
        }

        public static Type FaultExceptionType
        {
            get
            {
                if (faultExceptionType == null)
                {
                    faultExceptionType = typeof(FaultException<>);
                }
                return faultExceptionType;
            }
        }

        public static void ProvideDefaultNamespace(ref XName serviceContractName)
        {
            Fx.Assert(serviceContractName != null, "Argument cannot be null!");

            if (string.IsNullOrEmpty(serviceContractName.NamespaceName))
            {
                // If no namespace is given by the user, we provide default namespace. This is consistent with WCF.
                serviceContractName = XName.Get(serviceContractName.LocalName, NamingHelper.DefaultNamespace);
            }
        }

        public static ContractDescription CreateContractFromOperation(XName serviceContractName, OperationDescription operation)
        {
            Fx.Assert(serviceContractName != null, "serviceContractName cannot be null");
            ProvideDefaultNamespace(ref serviceContractName);

            ContractDescription contract = new ContractDescription(serviceContractName.LocalName, serviceContractName.NamespaceName)
            {
                // For inferred client side contracts, we do not set ContractType

                ConfigurationName = serviceContractName.LocalName,
                SessionMode = SessionMode.Allowed
            };
            contract.Operations.Add(operation);
            return contract;
        }

        public static ContractDescription CreateOutputChannelContractDescription(XName serviceContractName, ProtectionLevel? protectionLevel)
        {
            Fx.Assert(serviceContractName != null, "cannot be null");
            Type channelType = typeof(IOutputChannel);

            ProvideDefaultNamespace(ref serviceContractName);
            
            ContractDescription contract = new ContractDescription(serviceContractName.LocalName, serviceContractName.NamespaceName)
            {
                ContractType = channelType,
                ConfigurationName = serviceContractName.LocalName,
                SessionMode = SessionMode.Allowed
            };
            OperationDescription operation = new OperationDescription("Send", contract);
            MessageDescription message = new MessageDescription(MessageHeaders.WildcardAction, MessageDirection.Input);
            operation.Messages.Add(message);

            if (protectionLevel.HasValue)
            {
                operation.ProtectionLevel = protectionLevel.Value;
            }

            contract.Operations.Add(operation);
            return contract;
        }

        public static ContractDescription CreateRequestChannelContractDescription(XName serviceContractName, ProtectionLevel? protectionLevel)
        {
            Fx.Assert(serviceContractName != null, "cannot be null");
            Type channelType = typeof(IRequestChannel);

            ProvideDefaultNamespace(ref serviceContractName);

            ContractDescription contract = new ContractDescription(serviceContractName.LocalName, serviceContractName.NamespaceName)
            {
                ContractType = channelType,
                ConfigurationName = serviceContractName.LocalName,
                SessionMode = SessionMode.Allowed
            };
            OperationDescription operation = new OperationDescription("Request", contract);
            MessageDescription request = new MessageDescription(MessageHeaders.WildcardAction, MessageDirection.Input);
            MessageDescription reply = new MessageDescription(MessageHeaders.WildcardAction, MessageDirection.Output);
            operation.Messages.Add(request);
            operation.Messages.Add(reply);

            if (protectionLevel.HasValue)
            {
                operation.ProtectionLevel = protectionLevel.Value;
            }

            contract.Operations.Add(operation);
            return contract;
        }

        public static void EnsureTransactionFlowOnContract(
            ref ServiceEndpoint serviceEndpoint,
            XName serviceContractName,
            string operationName,
            string action,
            ProtectionLevel? protectionLevel)
        {
            Fx.Assert(serviceEndpoint != null, "ServiceEndpoint cannot be null!");

            // Client side fully inferred contract always has null ContractType
            if (serviceEndpoint.Contract.ContractType == null)
            {
                // If we are using the real contract, we only need to add TrancactionFlowAttribute to the operation
                Fx.Assert(serviceEndpoint.Contract.Operations.Count == 1, "Client side contract should have exactly one operation!");

                serviceEndpoint.Contract.Operations[0].Behaviors.Add(new TransactionFlowAttribute(TransactionFlowOption.Allowed));
            }
            else
            {
                // Replace the original fake contract with a fake contract tailored for transaction

                ContractDescription contract = null;
                OperationDescription operation = null;
                MessageDescription request = null;
                MessageDescription reply = null;

                Type channelType = typeof(IRequestChannel);

                // We need to create a contract description with the real service contract name
                // and operation name and actions and with the TransactionFlow operation behavior
                // because the TransactionChannelFactory has a dictionary of "Directional Action" to
                // transaction flow value that it uses to decide whether or not to include the
                // transaction header in the message.
                Fx.Assert(serviceContractName != null, "Argument serviceContractName cannot be null!");
                Fx.Assert(operationName != null, "Argument operationName cannot be null!");

                ProvideDefaultNamespace(ref serviceContractName);

                contract = new ContractDescription(serviceContractName.LocalName, serviceContractName.NamespaceName)
                {
                    ContractType = channelType,
                    SessionMode = SessionMode.Allowed
                };
                operation = new OperationDescription(operationName, contract);
                operation.Behaviors.Add(new TransactionFlowAttribute(TransactionFlowOption.Allowed));

                string requestAction = null;
                string replyAction = null;
                if (String.IsNullOrEmpty(action))
                {
                    // Construct the action.
                    requestAction = NamingHelper.GetMessageAction(operation, false);
                    replyAction = NamingHelper.GetMessageAction(operation, true);
                }
                else
                {
                    requestAction = action;
                    replyAction = action + TypeLoader.ResponseSuffix;
                }

                request = new MessageDescription(requestAction, MessageDirection.Input);
                reply = new MessageDescription(replyAction, MessageDirection.Output);

                operation.Messages.Add(request);
                operation.Messages.Add(reply);

                if (protectionLevel.HasValue)
                {
                    operation.ProtectionLevel = protectionLevel.Value;
                }

                contract.Operations.Add(operation);

                // We need to replace the ServiceEndpoint because ServiceEndpoint.Contract does not have a public setter
                Uri listenUri = serviceEndpoint.ListenUri;
                serviceEndpoint = new ServiceEndpoint(contract)
                {
                    Binding = serviceEndpoint.Binding,
                    Address = serviceEndpoint.Address,
                    Name = serviceEndpoint.Name,
                };
                if (listenUri != null)
                {
                    serviceEndpoint.ListenUri = listenUri;
                }
            }
        }

        public static OperationDescription CreateOneWayOperationDescription(Send send)
        {
            Fx.Assert(send != null, "Argument cannot be null!");
            return CreateOperationDescriptionCore(send, null);
        }

        public static OperationDescription CreateTwoWayOperationDescription(Send send, ReceiveReply receiveReply)
        {
            Fx.Assert(send != null && receiveReply != null, "Arguments cannot be null!");
            return CreateOperationDescriptionCore(send, receiveReply);
        }

        static OperationDescription CreateOperationDescriptionCore(Send send, ReceiveReply receiveReply)
        {
            XName contractXName = send.ServiceContractName;
            ProvideDefaultNamespace(ref contractXName);

            // Infer Name, Namespace, ConfigurationName
            ContractDescription contract = new ContractDescription(contractXName.LocalName, contractXName.NamespaceName);
            contract.ConfigurationName = send.EndpointConfigurationName;

            OperationDescription operation = new OperationDescription(NamingHelper.XmlName(send.OperationName), contract);
            if (send.ProtectionLevel.HasValue)
            {
                operation.ProtectionLevel = send.ProtectionLevel.Value;
            }

            AddKnownTypesToOperation(operation, send.KnownTypes);

            // Infer In-Message
            send.InternalContent.InferMessageDescription(operation, send, MessageDirection.Input);

            // Infer Out-Message
            if (receiveReply != null)
            {
                receiveReply.InternalContent.InferMessageDescription(operation, receiveReply, MessageDirection.Output);
            }

            PostProcessOperation(operation);
            AddSerializerProvider(operation, send.SerializerOption);

            contract.Operations.Add(operation);

            return operation;
        }

        // Create server side OperationDescription. 
        // Note this method assumes that CacheMetadata has been called on the Receive activity (as part of
        // the activity tree walk that is done in WorkflowService.GetContractDescriptions) because it relies on 
        // InternalReceiveMessage property of the Receive actitivy to be non-null.
        public static OperationDescription CreateOperationDescription(Receive receive, ContractDescription contract)
        {
            Fx.Assert(receive.InternalReceive != null, "This method can only be called if CacheMetadata has been called on the receive activity");

            OperationDescription operation = new OperationDescription(NamingHelper.XmlName(receive.OperationName), contract);

            if (receive.ProtectionLevel.HasValue)
            {
                operation.ProtectionLevel = receive.ProtectionLevel.Value;
            }

            // Infer In-Message
            receive.InternalContent.InferMessageDescription(operation, receive, MessageDirection.Input);

            // Infer Out-Message
            if (receive.HasReply)
            {
                // At this point, we already know all the following SendReplies are equivalent
                SendReply sendReply = receive.FollowingReplies[0];
                sendReply.InternalContent.InferMessageDescription(operation, sendReply, MessageDirection.Output);
            }
            else if (receive.HasFault)
            {
                // We infer Receive-SendFault pair as a two-way operation with void return value
                CheckForDisposableParameters(operation, Constants.EmptyTypeArray);
                AddOutputMessage(operation, null, Constants.EmptyStringArray, Constants.EmptyTypeArray);
            }

            PostProcessOperation(operation);

            // Behaviors
            AddSerializerProvider(operation, receive.SerializerOption);
            AddWorkflowOperationBehaviors(operation, receive.InternalReceive.OperationBookmarkName, receive.CanCreateInstance);

            if (receive.InternalReceive.AdditionalData.IsInsideTransactedReceiveScope)
            {
                operation.IsInsideTransactedReceiveScope = true;
                EnableTransactionBehavior(operation);
                if (receive.InternalReceive.AdditionalData.IsFirstReceiveOfTransactedReceiveScopeTree)
                {
                    operation.IsFirstReceiveOfTransactedReceiveScopeTree = true;
                }
            }

            return operation;
        }

        public static void AddInputMessage(OperationDescription operation, string overridingAction, Type type, SerializerOption serializerOption)
        {
            Fx.Assert(operation.Messages.Count == 0, "Operation already has input message");

            bool isResponse = false;
            MessageDescription message = MessageBuilder.CreateMessageDescription(
                operation, isResponse, MessageDirection.Input, overridingAction, type, serializerOption);

            operation.Messages.Add(message);
        }

        public static void AddInputMessage(OperationDescription operation, string overridingAction,
            string[] argumentNames, Type[] argumentTypes)
        {
            Fx.Assert(operation.Messages.Count == 0, "Operation already has input message");

            bool isResponse = false;
            MessageDescription message = MessageBuilder.CreateMessageDescription(
                operation, isResponse, MessageDirection.Input, overridingAction, argumentNames, argumentTypes);

            operation.Messages.Add(message);
        }

        public static void AddOutputMessage(OperationDescription operation, string overridingAction, Type type, SerializerOption serializerOption)
        {
            Fx.Assert(operation.Messages.Count > 0, "Operation does not have input message");
            Fx.Assert(operation.Messages.Count < 2, "Operation already has output message");

            bool isResponse = true;
            MessageDescription message = MessageBuilder.CreateMessageDescription(
                operation, isResponse, MessageDirection.Output, overridingAction, type, serializerOption);

            operation.Messages.Add(message);
        }

        public static void AddOutputMessage(OperationDescription operation, string overridingAction,
            string[] argumentNames, Type[] argumentTypes)
        {
            Fx.Assert(operation.Messages.Count > 0, "Operation does not have input message");
            Fx.Assert(operation.Messages.Count < 2, "Operation already has output message");

            bool isResponse = true;
            MessageDescription message = MessageBuilder.CreateMessageDescription(
                operation, isResponse, MessageDirection.Output, overridingAction, argumentNames, argumentTypes);

            operation.Messages.Add(message);
        }

        static void AddKnownTypesToOperation(OperationDescription operation, Collection<Type> knownTypes)
        {
            if (knownTypes != null)
            {
                foreach (Type knownType in knownTypes)
                {
                    operation.KnownTypes.Add(knownType);
                }
            }
        }

        public static void CheckForDisposableParameters(OperationDescription operation, Type type)
        {
            if (type == null)
            {
                 operation.HasNoDisposableParameters = true;
            }
            else
            {
                operation.HasNoDisposableParameters = !ServiceReflector.IsParameterDisposable(type);
            }
        }

        public static void CheckForDisposableParameters(OperationDescription operation, Type[] types)
        {
            Fx.Assert(types != null, "Argument cannot be null!");

            operation.HasNoDisposableParameters = true;
            foreach (Type type in types)
            {
                if (ServiceReflector.IsParameterDisposable(type))
                {
                    operation.HasNoDisposableParameters = false;
                    break;
                }
            }
        }

        static void EnableTransactionBehavior(OperationDescription operationDescription)
        {
            Fx.Assert(operationDescription != null, "OperationDescription is null");

            OperationBehaviorAttribute attribute = operationDescription.Behaviors.Find<OperationBehaviorAttribute>();
            if (attribute != null)
            {
                attribute.TransactionScopeRequired = true;
                attribute.TransactionAutoComplete = false;
            }
            else
            {
                OperationBehaviorAttribute attr = new OperationBehaviorAttribute
                {
                    TransactionAutoComplete = false,
                    TransactionScopeRequired = true
                };
                operationDescription.Behaviors.Add(attr);
            }
            TransactionFlowAttribute transactionFlowAttribute = operationDescription.Behaviors.Find<TransactionFlowAttribute>();
            if (transactionFlowAttribute != null)
            {
                if (transactionFlowAttribute.Transactions != TransactionFlowOption.Allowed)
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ContractInferenceValidationForTransactionFlowBehavior));
                }
            }
            else
            {
                if (!operationDescription.IsOneWay)
                {
                    operationDescription.Behaviors.Add(new TransactionFlowAttribute(TransactionFlowOption.Allowed));
                }
            }
        }
        
        static void PostProcessOperation(OperationDescription operation)
        {
            MessageBuilder.ClearWrapperNames(operation);
        }

        static void AddSerializerProvider(OperationDescription operation, SerializerOption serializerOption)
        {
            switch (serializerOption)
            {
                case SerializerOption.DataContractSerializer:
                    AddDataContractSerializerFormat(operation);
                    break;
                case SerializerOption.XmlSerializer:
                    AddXmlSerializerFormat(operation);
                    break;
            }
        }

        static void AddDataContractSerializerFormat(OperationDescription operation)
        {
            if (operation.Behaviors.Find<DataContractSerializerOperationBehavior>() != null)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.OperationHasSerializerBehavior(
                    operation.Name, operation.DeclaringContract.Name, typeof(DataContractSerializerOperationBehavior))));
            }
            operation.Behaviors.Add(new DataContractSerializerOperationBehavior(operation, DataContractFormatAttribute));
            if (!operation.Behaviors.Contains(typeof(DataContractSerializerOperationGenerator)))
            {
                operation.Behaviors.Add(new DataContractSerializerOperationGenerator());
            }
        }

        static void AddXmlSerializerFormat(OperationDescription operation)
        {
            if (operation.Behaviors.Find<XmlSerializerOperationBehavior>() != null)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(
                    SR.OperationHasSerializerBehavior(operation.Name, operation.DeclaringContract.Name, typeof(XmlSerializerOperationBehavior))));
            }
            operation.Behaviors.Add(new XmlSerializerOperationBehavior(operation, XmlSerializerFormatAttribute));
            if (!operation.Behaviors.Contains(typeof(XmlSerializerOperationGenerator)))
            {
                operation.Behaviors.Add(new XmlSerializerOperationGenerator(new XmlSerializerImportOptions()));
            }
        }

        static void AddWorkflowOperationBehaviors(OperationDescription operation, string bookmarkName, bool canCreateInstance)
        {
            KeyedByTypeCollection<IOperationBehavior> behaviors = operation.Behaviors;
            WorkflowOperationBehavior workflowOperationBehavior = behaviors.Find<WorkflowOperationBehavior>();
            if (workflowOperationBehavior == null)
            {
                behaviors.Add(new WorkflowOperationBehavior(new Bookmark(bookmarkName), canCreateInstance));
            }
            else
            {
                workflowOperationBehavior.CanCreateInstance = workflowOperationBehavior.CanCreateInstance || canCreateInstance;
            }
        }

        public static void CorrectOutMessageForOperation(Receive receive, OperationDescription operation)
        {
            // Remove the original outMessage
            Fx.Assert(operation.Messages.Count == 2, "OperationDescription must be two-way for CorrectOutMessageForOperation to be invoked!");
            operation.Messages.RemoveAt(1);

            SendReply sendReply = receive.FollowingReplies[0];
            sendReply.InternalContent.InferMessageDescription(operation, sendReply, MessageDirection.Output);

            ContractInferenceHelper.PostProcessOperation(operation);
        }

        public static void UpdateIsOneWayFlag(Receive receive, OperationDescription operation)
        {
            // Set InternalReceiveMessage.IsOneWay to false for two-way operations
            if (!operation.IsOneWay)
            {
                receive.SetIsOneWay(false);
            }
        }

        public static void AddFaultDescription(Receive activity, OperationDescription operation)
        {
            if (activity.HasFault)
            {
                foreach (SendReply sendFault in activity.FollowingFaults)
                {
                    string action = null;
                    Type type = null;

                    action = sendFault.Action;

                    SendMessageContent sendReply = sendFault.InternalContent as SendMessageContent;
                    if (sendReply != null)
                    {
                        type = sendReply.InternalDeclaredMessageType;
                    }
                    else
                    {
                        SendParametersContent sendReplyParameters = sendFault.InternalContent as SendParametersContent;
                        if (sendReplyParameters != null)
                        {
                            type = sendReplyParameters.ArgumentTypes[0];  // Exception should be the only parameter in SendFault
                        }
                    }

                    Fx.Assert(type != null, "Exception type cannot be null!");
                    if (type.IsGenericType && type.GetGenericTypeDefinition() == FaultExceptionType)
                    {
                        Type faultType = type.GetGenericArguments()[0];
                        bool exists = false;

                        // We expect the number of fault types to be small, so we use iterative comparison 
                        foreach (FaultDescription faultDescription in operation.Faults)
                        {
                            if (faultDescription.DetailType == faultType)
                            {
                                if (faultDescription.Action != action)
                                {
                                    throw FxTrace.Exception.AsError(new ValidationException(SR.SendRepliesHaveSameFaultTypeDifferentAction));
                                }
                                else
                                {
                                    exists = true;
                                    break;
                                }
                            }
                        }

                        if (!exists)
                        {
                            FaultDescription faultDescription = MessageBuilder.CreateFaultDescription(operation, faultType, action);
                            operation.Faults.Add(faultDescription);
                        }
                    }
                }
            }
        }

        public static void AddKnownTypesToOperation(Receive receive, OperationDescription operation)
        {
            Collection<Type> knownTypes = receive.InternalKnownTypes;

            if (knownTypes != null)
            {
                foreach (Type knownType in knownTypes)
                {
                    // We expect the number of known types to be small, so we use iterative comparison 
                    if (!operation.KnownTypes.Contains(knownType))
                    {
                        operation.KnownTypes.Add(knownType);
                    }
                }
            }
        }

        public static void AddReceiveToFormatterBehavior(Receive receive, OperationDescription operation)
        {
            Fx.Assert(receive != null && operation != null, "Argument cannot be null!");

            KeyedByTypeCollection<IOperationBehavior> behaviors = operation.Behaviors;
            WorkflowFormatterBehavior formatterBehavior = behaviors.Find<WorkflowFormatterBehavior>();
            if (formatterBehavior == null)
            {
                formatterBehavior = new WorkflowFormatterBehavior();
                behaviors.Add(formatterBehavior);
            }

            formatterBehavior.Receives.Add(receive);
        }

        public static void RemoveReceiveFromFormatterBehavior(Receive receive, OperationDescription operation)
        {
            Fx.Assert(receive != null && operation != null, "Arguments cannot be null!");

            KeyedByTypeCollection<IOperationBehavior> behaviors = operation.Behaviors;
            WorkflowFormatterBehavior formatterBehavior = behaviors.Find<WorkflowFormatterBehavior>();
            if (formatterBehavior != null)
            {
                formatterBehavior.Receives.Remove(receive);
            }
        }

        public static CorrelationQuery CreateServerCorrelationQuery(MessageQuerySet select, Collection<CorrelationInitializer> correlationInitializers,
            OperationDescription operation, bool isResponse)
        {
            Fx.Assert(operation != null, "Argument cannot be null!");

            CorrelationQuery correlationQuery = CreateCorrelationQueryCore(select, correlationInitializers);

            if (correlationQuery != null)
            {
                string action = !isResponse ? operation.Messages[0].Action : operation.Messages[1].Action;
                correlationQuery.Where = new CorrelationActionMessageFilter { Action = action };
            }

            return correlationQuery;
        }

        // this method generates the correlationQuery for client side send and receiveReply
        public static Collection<CorrelationQuery> CreateClientCorrelationQueries(MessageQuerySet select, Collection<CorrelationInitializer> correlationInitializers,
            string overridingAction, XName serviceContractName, string operationName, bool isResponse)
        {
            Fx.Assert(serviceContractName != null && operationName != null, "Argument cannot be null!");

            Collection<CorrelationQuery> queryCollection = new Collection<CorrelationQuery>();
            CorrelationQuery correlationQuery = CreateCorrelationQueryCore(select, correlationInitializers);

            if (correlationQuery != null)
            {
                if (overridingAction != null)
                {
                    correlationQuery.Where = new CorrelationActionMessageFilter { Action = overridingAction };
                }
                else
                {
                    ProvideDefaultNamespace(ref serviceContractName);
                    string defaultAction = NamingHelper.GetMessageAction(new XmlQualifiedName(serviceContractName.LocalName, serviceContractName.NamespaceName),
                        operationName, null, isResponse);

                    correlationQuery.Where = new CorrelationActionMessageFilter { Action = defaultAction };
                }

                queryCollection.Add(correlationQuery);

                if (isResponse)
                {
                    // we need an additional query with empty action to support soap1.1 reply cases
                    CorrelationQuery noActionQuery = correlationQuery.Clone();
                    noActionQuery.Where = new CorrelationActionMessageFilter { Action = String.Empty };
                    queryCollection.Add(noActionQuery);
                }
            }

            return queryCollection;
        }

        static CorrelationQuery CreateCorrelationQueryCore(MessageQuerySet select, Collection<CorrelationInitializer> correlationInitializers)
        {
            CorrelationQuery correlationQuery = null;

            if (select != null)
            {
                Fx.Assert(select.Count != 0, "Empty MessageQuerySet is not allowed!");

                correlationQuery = new CorrelationQuery
                {
                    Select = select
                };
            }

            if (correlationInitializers != null && correlationInitializers.Count > 0)
            {
                foreach (CorrelationInitializer correlation in correlationInitializers)
                {
                    QueryCorrelationInitializer queryCorrelation = correlation as QueryCorrelationInitializer;
                    if (queryCorrelation != null)
                    {
                        Fx.Assert(queryCorrelation.MessageQuerySet.Count != 0, "Empty MessageQuerySet is not allowed!");

                        correlationQuery = correlationQuery ?? new CorrelationQuery();
                        correlationQuery.SelectAdditional.Add(queryCorrelation.MessageQuerySet);
                    }
                }
            }

            return correlationQuery;
        }
    }
}