public ISoapHeaderAttributesCalculator CreateCalculator(Type requestType, WebMethodHeaderMappingDefinition mappingDefinition)
        {
            if (requestType == null)
                throw new ArgumentNullException("requestType");

            if (mappingDefinition == null)
                throw new ArgumentNullException("mappingDefinition");

            var fieldInfo = requestType.GetField(mappingDefinition.Name, BindingFlags.Instance | BindingFlags.Public);
            if (fieldInfo == null)
                throw new ArgumentException(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        "Could not find the field \"{0}\" in type \"{1}\".",
                        mappingDefinition.Name,
                        requestType.AssemblyQualifiedName),
                    "mappingDefinition");

            var messageHeaderAttribute = fieldInfo.GetCustomAttribute<MessageHeaderAttribute>();

            IValueCalculator actorCalculator = null;
            if (mappingDefinition.ActorMapping != null)
                actorCalculator = ValueCalculatorFactory.CreateValueCalculator(mappingDefinition.ActorMapping);

            IValueCalculator mustUnderstandCalculator = null;
            if (mappingDefinition.MustUnderstandMapping != null)
                mustUnderstandCalculator = ValueCalculatorFactory.CreateValueCalculator(mappingDefinition.MustUnderstandMapping);

            IValueCalculator relayCalculator = null;
            if (mappingDefinition.RelayMapping != null)
                relayCalculator = ValueCalculatorFactory.CreateValueCalculator(mappingDefinition.RelayMapping);

            return new SoapHeaderAttributesCalculator(
                messageHeaderAttribute.Name ?? fieldInfo.Name,
                messageHeaderAttribute.Namespace,
                actorCalculator,
                mustUnderstandCalculator,
                relayCalculator,
                TypeConverter);
        }
        public void ExecuteTest()
        {
            // Arrange.
            const int ServiceDescriptionId = 123;
            const string ServiceName = "TestService";
            const string Username = "******";
            const string ProcessDisplayName = "Test Process";
            const string RequestXml = "Test Request";
            const string ResponseXml = "Test Response";
            var serviceGuid = new Guid("{298F9413-AB7F-4DCC-A3E0-9B5E5640FC68}");

            var headerValueMappingDefinition = new WebMethodParameterMappingDefinition();
            var headerDefinition = new WebMethodHeaderMappingDefinition { ValueMapping = headerValueMappingDefinition };
            var parameterDefinition = new WebMethodParameterMappingDefinition();

            var callDefinition = new WebMethodCallDefinition
                                     {
                                         ServiceDescriptionId = ServiceDescriptionId,
                                         Name = ServiceName,
                                         Guid = serviceGuid,
                                         ProcessDisplayName = ProcessDisplayName
                                     };
            callDefinition.HeaderMappings.Add(headerDefinition);
            callDefinition.ParameterMappings.Add(parameterDefinition);

            var editableRoot = Mock.Create<IEditableRoot>(Behavior.Loose);
            var callContext = Mock.Create<IDataContext>(Behavior.Loose);
            var callContextFactory = Mock.Create<IEditableRootDataContextFactory>(Behavior.Loose);
            Mock.Arrange(() => callContextFactory.CreateDataContext(editableRoot)).Returns(callContext);

            var soapHeaderAttributes = new SoapHeaderAttributes
                                           {
                                               HeaderName = "Test Header",
                                               HeaderNamespace = "Test Namespace",
                                               Actor = "Test Actor",
                                               MustUnderstand = true,
                                               Relay = true
                                           };
            var headerAttributesCalculator = Mock.Create<ISoapHeaderAttributesCalculator>(Behavior.Loose);
            Mock.Arrange(() => headerAttributesCalculator.GetHeaderAttributes(callContext)).Returns(soapHeaderAttributes);

            var headerValue = new object();
            var headerSetter = Mock.Create<IPropertySetter>(Behavior.Loose);
            Mock.Arrange(() => headerSetter.Update(callContext, Arg.IsAny<InputMessage>()))
                .DoInstead<IDataContext, InputMessage>((dc, target) => target.Header = headerValue);

            var parameterValue = new object();
            var parameterSetter = Mock.Create<IPropertySetter>(Behavior.Loose);
            Mock.Arrange(() => parameterSetter.Update(callContext, Arg.IsAny<InputMessage>()))
                .DoInstead<IDataContext, InputMessage>((dc, target) => target.Parameter = parameterValue);

            var mappingFactory = Mock.Create<IWebMethodParameterCalculatorFactory>(Behavior.Loose);
            Mock.Arrange(() => mappingFactory.CreatePropertySetter(typeof(InputMessage), headerValueMappingDefinition)).Returns(headerSetter);
            Mock.Arrange(() => mappingFactory.CreatePropertySetter(typeof(InputMessage), parameterDefinition)).Returns(parameterSetter);

            var headerMappingFactory = Mock.Create<ISoapHeaderAttributesCalculatorFactory>(Behavior.Loose);
            Mock.Arrange(() => headerMappingFactory.CreateCalculator(typeof(InputMessage), headerDefinition)).Returns(headerAttributesCalculator);

            WebMethodCallData callData = null;
            var methodProxy = Mock.Create<IWebMethodProxy>();
            Mock.Arrange(() => methodProxy.RequestType).Returns(typeof(InputMessage));
            Mock.Arrange(() => methodProxy.Invoke(Arg.IsAny<WebMethodCallData>())).DoInstead<WebMethodCallData>(
                data =>
                    {
                        callData = data;
                        if (IntegrationServiceCallScope.Current != null)
                        {
                            IntegrationServiceCallScope.Current.Request = RequestXml;
                            IntegrationServiceCallScope.Current.Response = ResponseXml;
                        }
                    });

            var utils = Mock.Create<IUtils>(Behavior.Loose);
            Mock.Arrange(() => utils.CurrentUserName).Returns(Username);

            var events = new List<IntegrationEvent>();
            var eventLogger = Mock.Create<IIntegrationEventLogger>(Behavior.Loose);
            Mock.Arrange(() => eventLogger.Log(Arg.IsAny<IntegrationEvent>())).DoInstead<IntegrationEvent>(events.Add);

            var serviceCaller = new WebMethodServiceCaller
                                    {
                                        ParameterCalculatorFactory = mappingFactory,
                                        HeaderAttributesCalculatorFactory = headerMappingFactory,
                                        MethodProxy = methodProxy,
                                        EditableRootDataContextFactory = callContextFactory,
                                        Utils = utils,
                                        IntegrationEventLogger = eventLogger
                                    };
            serviceCaller.Initialize(callDefinition);

            // Act.
            serviceCaller.Execute(editableRoot);

            // Assert.
            Assert.IsNotNull(callData);
            var request = callData.Message as InputMessage;

            Assert.IsNotNull(request);
            Assert.AreSame(headerValue, request.Header);
            Assert.AreSame(parameterValue, request.Parameter);
            Assert.AreEqual(1, callData.Options.HeaderAttributes.Count);
            Assert.IsTrue(callData.Options.HeaderAttributes.Contains(soapHeaderAttributes));
            Mock.Assert(() => methodProxy.Invoke(Arg.IsAny<WebMethodCallData>()), Occurs.Once());

            Assert.AreEqual(1, events.Count);
            Assert.IsTrue(events[0].IsSuccessful);
            Assert.AreEqual(ProcessDisplayName, events[0].Process);
            Assert.AreEqual(ServiceName, events[0].Service);
            Assert.AreEqual(Username, events[0].Username);
            Assert.AreEqual(RequestXml, events[0].Request);
            Assert.AreEqual(ResponseXml, events[0].Response);

            // Exceptions.
            TestsHelper.VerifyThrow<ArgumentNullException>(() => serviceCaller.Execute(null));
        }
        public void EnqueueServiceCall_InsertsScheduledCall()
        {
            const int ServiceDescriptionId = 123;
            const string ServiceName = "TestService";
            const string SerializedRequest = "TestData";
            const string SerializedOptions = "TestOptions";
            var serviceGuid = new Guid("{298F9413-AB7F-4DCC-A3E0-9B5E5640FC68}");
            const string ProcessName = "TestProcess";
            const int ItemId = 456;

            var headerValueMappingDefinition = new WebMethodParameterMappingDefinition();
            var headerDefinition = new WebMethodHeaderMappingDefinition { ValueMapping = headerValueMappingDefinition };
            var parameterDefinition = new WebMethodParameterMappingDefinition();

            var callDefinition = new WebMethodCallDefinition { ServiceDescriptionId = ServiceDescriptionId, Name = ServiceName, Guid = serviceGuid };
            callDefinition.HeaderMappings.Add(headerDefinition);
            callDefinition.ParameterMappings.Add(parameterDefinition);

            var editableRoot = Mock.Create<IEditableRoot>(Behavior.Loose);
            Mock.Arrange(() => editableRoot.Id).Returns(ItemId);
            Mock.Arrange(() => editableRoot.ProcessName).Returns(ProcessName);

            var callContext = Mock.Create<IDataContext>(Behavior.Loose);
            var callContextFactory = Mock.Create<IEditableRootDataContextFactory>(Behavior.Loose);
            Mock.Arrange(() => callContextFactory.CreateDataContext(editableRoot)).Returns(callContext);

            var soapHeaderAttributes = new SoapHeaderAttributes
                                           {
                                               HeaderName = "Test Header",
                                               HeaderNamespace = "Test Namespace",
                                               Actor = "Test Actor",
                                               MustUnderstand = true,
                                               Relay = true
                                           };
            var headerAttributesCalculator = Mock.Create<ISoapHeaderAttributesCalculator>(Behavior.Loose);
            Mock.Arrange(() => headerAttributesCalculator.GetHeaderAttributes(callContext)).Returns(soapHeaderAttributes);

            var headerValue = new object();
            var headerSetter = Mock.Create<IPropertySetter>(Behavior.Loose);
            Mock.Arrange(() => headerSetter.Update(callContext, Arg.IsAny<InputMessage>()))
                .DoInstead<IDataContext, InputMessage>((dc, target) => target.Header = headerValue);

            var parameterValue = new object();
            var parameterSetter = Mock.Create<IPropertySetter>(Behavior.Loose);
            Mock.Arrange(() => parameterSetter.Update(callContext, Arg.IsAny<InputMessage>()))
                .DoInstead<IDataContext, InputMessage>((dc, target) => target.Parameter = parameterValue);

            var mappingFactory = Mock.Create<IWebMethodParameterCalculatorFactory>(Behavior.Loose);
            Mock.Arrange(() => mappingFactory.CreatePropertySetter(typeof(InputMessage), headerValueMappingDefinition)).Returns(headerSetter);
            Mock.Arrange(() => mappingFactory.CreatePropertySetter(typeof(InputMessage), parameterDefinition)).Returns(parameterSetter);

            var headerMappingFactory = Mock.Create<ISoapHeaderAttributesCalculatorFactory>(Behavior.Loose);
            Mock.Arrange(() => headerMappingFactory.CreateCalculator(typeof(InputMessage), headerDefinition)).Returns(headerAttributesCalculator);

            var methodProxy = Mock.Create<IWebMethodProxy>(Behavior.Loose);
            Mock.Arrange(() => methodProxy.RequestType).Returns(typeof(InputMessage));
            Mock.Arrange(() => methodProxy.ContractType).Returns(typeof(ITestService));
            Mock.Arrange(() => methodProxy.Method).Returns(typeof(ITestService).GetMethod("TestMethod"));

            var requestSerializer = Mock.Create<IWebMethodRequestSerializer>(Behavior.Loose);
            Mock.Arrange(() => requestSerializer.SerializeRequest(Arg.IsAny<object>())).Returns(SerializedRequest);
            Mock.Arrange(() => requestSerializer.SerializeOptions(Arg.IsAny<WebMethodCallOptions>())).Returns(SerializedOptions);

            WebMethodScheduledCall scheduledCall = null;

            var callScheduler = Mock.Create<IServiceCallScheduler>(Behavior.Loose);
            Mock.Arrange(() => callScheduler.InsertScheduledCall(Arg.IsAny<ServiceScheduledCall>()))
                .DoInstead<ServiceScheduledCall>(sc => scheduledCall = (WebMethodScheduledCall)sc);
            var utils = Mock.Create<IUtils>(Behavior.Loose);
            var eventLogger = Mock.Create<IIntegrationEventLogger>(Behavior.Loose);

            var serviceCaller = new WebMethodServiceCaller
                                    {
                                        ParameterCalculatorFactory = mappingFactory,
                                        HeaderAttributesCalculatorFactory = headerMappingFactory,
                                        MethodProxy = methodProxy,
                                        EditableRootDataContextFactory = callContextFactory,
                                        RequestSerializer = requestSerializer,
                                        CallScheduler = callScheduler,
                                        Utils = utils,
                                        IntegrationEventLogger = eventLogger
                                    };
            serviceCaller.Initialize(callDefinition);

            // Act.
            serviceCaller.EnqueueServiceCall(editableRoot);

            // Assert.
            Mock.Assert(() => callScheduler.InsertScheduledCall(Arg.IsAny<ServiceScheduledCall>()), Occurs.Once());
            Assert.IsNotNull(scheduledCall);
            Assert.AreEqual(serviceGuid, scheduledCall.IntegrationServiceGuid);
            Assert.AreEqual(ProcessName, scheduledCall.ProcessName);
            Assert.AreEqual(ItemId, scheduledCall.ItemId);
            Assert.AreEqual(0, scheduledCall.CallCount);
            Assert.AreEqual(ServiceCallStatus.Scheduled, scheduledCall.Status);
            Assert.AreEqual(ServiceDescriptionId, scheduledCall.ServiceDescriptionId);
            Assert.AreEqual(typeof(ITestService).AssemblyQualifiedName, scheduledCall.ContractTypeName);
            Assert.AreEqual("TestMethod", scheduledCall.MethodName);
            Assert.AreEqual(SerializedRequest, scheduledCall.Data);
            Assert.AreEqual(SerializedOptions, scheduledCall.Options);
        }
        public void WhenExecutionFails_ServiceCallExceptionIsThrown()
        {
            // Arrange.
            const int ServiceDescriptionId = 123;
            const string ServiceName = "TestService";
            const string SerializedRequest = "TestData";
            const string SerializedOptions = "TestOptions";
            var serviceGuid = new Guid("{298F9413-AB7F-4DCC-A3E0-9B5E5640FC68}");
            const string ProcessName = "TestProcess";
            const int ItemId = 456;

            var headerValueMappingDefinition = new WebMethodParameterMappingDefinition();
            var headerDefinition = new WebMethodHeaderMappingDefinition { ValueMapping = headerValueMappingDefinition };
            var parameterDefinition = new WebMethodParameterMappingDefinition();

            var callDefinition = new WebMethodCallDefinition { ServiceDescriptionId = ServiceDescriptionId, Name = ServiceName, Guid = serviceGuid };
            callDefinition.HeaderMappings.Add(headerDefinition);
            callDefinition.ParameterMappings.Add(parameterDefinition);

            var editableRoot = Mock.Create<IEditableRoot>(Behavior.Loose);
            Mock.Arrange(() => editableRoot.Id).Returns(ItemId);
            Mock.Arrange(() => editableRoot.ProcessName).Returns(ProcessName);

            var callContext = Mock.Create<IDataContext>(Behavior.Loose);
            var callContextFactory = Mock.Create<IEditableRootDataContextFactory>(Behavior.Loose);
            Mock.Arrange(() => callContextFactory.CreateDataContext(editableRoot)).Returns(callContext);

            var soapHeaderAttributes = new SoapHeaderAttributes
                                           {
                                               HeaderName = "Test Header",
                                               HeaderNamespace = "Test Namespace",
                                               Actor = "Test Actor",
                                               MustUnderstand = true,
                                               Relay = true
                                           };
            var headerAttributesCalculator = Mock.Create<ISoapHeaderAttributesCalculator>(Behavior.Loose);
            Mock.Arrange(() => headerAttributesCalculator.GetHeaderAttributes(callContext)).Returns(soapHeaderAttributes);

            var headerValue = new object();
            var headerSetter = Mock.Create<IPropertySetter>(Behavior.Loose);
            Mock.Arrange(() => headerSetter.Update(callContext, Arg.IsAny<InputMessage>()))
                .DoInstead<IDataContext, InputMessage>((dc, target) => target.Header = headerValue);

            var parameterValue = new object();
            var parameterSetter = Mock.Create<IPropertySetter>(Behavior.Loose);
            Mock.Arrange(() => parameterSetter.Update(callContext, Arg.IsAny<InputMessage>()))
                .DoInstead<IDataContext, InputMessage>((dc, target) => target.Parameter = parameterValue);

            var mappingFactory = Mock.Create<IWebMethodParameterCalculatorFactory>(Behavior.Loose);
            Mock.Arrange(() => mappingFactory.CreatePropertySetter(typeof(InputMessage), headerValueMappingDefinition)).Returns(headerSetter);
            Mock.Arrange(() => mappingFactory.CreatePropertySetter(typeof(InputMessage), parameterDefinition)).Returns(parameterSetter);

            var headerMappingFactory = Mock.Create<ISoapHeaderAttributesCalculatorFactory>(Behavior.Loose);
            Mock.Arrange(() => headerMappingFactory.CreateCalculator(typeof(InputMessage), headerDefinition)).Returns(headerAttributesCalculator);

            var methodProxy = Mock.Create<IWebMethodProxy>(Behavior.Loose);
            Mock.Arrange(() => methodProxy.RequestType).Returns(typeof(InputMessage));
            Mock.Arrange(() => methodProxy.Invoke(Arg.IsAny<WebMethodCallData>())).Throws(new CommunicationException());
            Mock.Arrange(() => methodProxy.ContractType).Returns(typeof(ITestService));
            Mock.Arrange(() => methodProxy.Method).Returns(typeof(ITestService).GetMethod("TestMethod"));

            var requestSerializer = Mock.Create<IWebMethodRequestSerializer>(Behavior.Loose);
            Mock.Arrange(() => requestSerializer.SerializeRequest(Arg.IsAny<object>())).Returns(SerializedRequest);
            Mock.Arrange(() => requestSerializer.SerializeOptions(Arg.IsAny<WebMethodCallOptions>())).Returns(SerializedOptions);

            var callScheduler = Mock.Create<IServiceCallScheduler>(Behavior.Loose);
            var utils = Mock.Create<IUtils>(Behavior.Loose);
            var eventLogger = Mock.Create<IIntegrationEventLogger>(Behavior.Loose);

            var serviceCaller = new WebMethodServiceCaller
                                    {
                                        ParameterCalculatorFactory = mappingFactory,
                                        HeaderAttributesCalculatorFactory = headerMappingFactory,
                                        MethodProxy = methodProxy,
                                        EditableRootDataContextFactory = callContextFactory,
                                        RequestSerializer = requestSerializer,
                                        CallScheduler = callScheduler,
                                        Utils = utils,
                                        IntegrationEventLogger = eventLogger
                                    };
            serviceCaller.Initialize(callDefinition);

            // Act / Assert.
            TestsHelper.VerifyThrow<ServiceCallException>(() => serviceCaller.Execute(editableRoot));
        }