/// <summary>
        /// Creates a <see cref="IValueCalculator"/> for the specified <see cref="WebMethodParameterMappingDefinition"/>.
        /// </summary>
        /// <param name="mappingDefinition">
        /// The mapping definition.
        /// </param>
        /// <returns>
        /// The <see cref="IValueCalculator"/>.
        /// </returns>
        public IValueCalculator CreateValueCalculator(WebMethodParameterMappingDefinition mappingDefinition)
        {
            if (mappingDefinition == null)
                throw new ArgumentNullException("mappingDefinition");

            var type = TypeResolver.FindType(mappingDefinition.TypeName);

            if (type.IsArray)
                return CreateArrayValueCalculator(type, mappingDefinition);

            if (IsSimpleType(type))
                return CreateSimpleValueCalculator(type, mappingDefinition);

            return CreateComplexValueCalculator(type, mappingDefinition);
        }
        public void CreateSimpleValueCalculatorTest()
        {
            // Arrange.
            const string FieldName = "TestField";
            const string TypeName = "TestType";

            var typeResolver = new Mock<ITypeResolver>();
            typeResolver.Setup(x => x.FindType(TypeName)).Returns(typeof(string));

            var typeConverter = Mock.Create<ITypeConverter>(Behavior.Loose);

            var mappingDefinition = new WebMethodParameterMappingDefinition { Name = FieldName, TypeName = TypeName };
            var factory = new WebMethodParameterCalculatorFactory { TypeResolver = typeResolver.Object, TypeConverter = typeConverter };

            // Act.
            var valueCalculator = factory.CreateValueCalculator(mappingDefinition);

            // Assert.
            Assert.IsTrue(valueCalculator is SimpleValueCalculator);
        }
        public void CreateDynamicLengthArrayValueCalculatorTest()
        {
            // Arrange.
            const string FieldName = "TestField";
            const string TypeName = "TestType";
            const string ElementTypeName = "TestElementType";

            var typeResolver = new Mock<ITypeResolver>();
            typeResolver.Setup(x => x.FindType(TypeName)).Returns(typeof(Employee[]));
            typeResolver.Setup(x => x.FindType(ElementTypeName)).Returns(typeof(Employee));

            var typeConverter = Mock.Create<ITypeConverter>(Behavior.Loose);

            var elementMappingDefinition = new WebMethodParameterMappingDefinition { Name = Constants.ArrayItemGenericFieldName, TypeName = ElementTypeName };
            var mappingDefinition = new WebMethodParameterMappingDefinition { Name = FieldName, TypeName = TypeName, Subfields = { elementMappingDefinition } };

            var factory = new WebMethodParameterCalculatorFactory { TypeResolver = typeResolver.Object, TypeConverter = typeConverter };

            // Act.
            var valueCalculator = factory.CreateValueCalculator(mappingDefinition);

            // Assert.
            Assert.IsTrue(valueCalculator is ArrayValueCalculator);
        }
 private IValueCalculator CreateComplexValueCalculator(Type valueType, WebMethodParameterMappingDefinition mappingDefinition)
 {
     return new ComplexValueCalculator(valueType, mappingDefinition.Subfields.Select(m => CreatePropertySetter(valueType, m)));
 }
        private IValueCalculator CreateArrayValueCalculator(Type valueType, WebMethodParameterMappingDefinition mappingDefinition)
        {
            var elementType = valueType.GetElementType();

            if (mappingDefinition.ArrayItemCount.HasValue)
            {
                var elementSetters = new List<IPropertySetter>();
                var mappingDictionary = mappingDefinition.Subfields.ToDictionary(m => m.Name);

                for (var i = 0; i < mappingDefinition.ArrayItemCount.Value; ++i)
                {
                    var elementName = string.Format(CultureInfo.InvariantCulture, Constants.ArrayItemFieldNamePattern, i);
                    if (mappingDictionary.ContainsKey(elementName))
                        elementSetters.Add(new ArrayElementSetter(i, CreateValueCalculator(mappingDictionary[elementName])));
                }

                return new FixedLengthArrayValueCalculator(elementType, mappingDefinition.ArrayItemCount.Value, elementSetters);
            }
            
            IValueCalculator elementCalculator = null;
            var elementMappingDefinition = mappingDefinition.Subfields.FirstOrDefault(m => m.Name == Constants.ArrayItemGenericFieldName);
            if (elementMappingDefinition != null)
            {
                elementCalculator = CreateValueCalculator(elementMappingDefinition);
            }

            return new ArrayValueCalculator(elementType, mappingDefinition.ValueExpression, elementCalculator, TypeConverter);
        }
 private IValueCalculator CreateSimpleValueCalculator(Type valueType, WebMethodParameterMappingDefinition mappingDefinition)
 {
     return new SimpleValueCalculator(mappingDefinition.ValueExpression, valueType, TypeConverter);
 }
        /// <summary>
        /// Creates a property setter for the specified <see cref="WebMethodParameterMappingDefinition"/>.
        /// </summary>
        /// <param name="targetType">
        /// The target type.
        /// </param>
        /// <param name="mappingDefinition">
        /// The mapping definition.
        /// </param>
        /// <returns>
        /// The <see cref="IPropertySetter"/>.
        /// </returns>
        public IPropertySetter CreatePropertySetter(Type targetType, WebMethodParameterMappingDefinition mappingDefinition)
        {
            if (targetType == null)
                throw new ArgumentNullException("targetType");

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

            var propertyInfo = targetType.GetProperty(mappingDefinition.Name, BindingFlags.Instance | BindingFlags.Public);
            if (propertyInfo != null)
            {
                return new PropertySetter(propertyInfo, CreateValueCalculator(mappingDefinition));
            }

            var fieldInfo = targetType.GetField(mappingDefinition.Name, BindingFlags.Instance | BindingFlags.Public);
            if (fieldInfo != null)
            {
                return new FieldSetter(fieldInfo, CreateValueCalculator(mappingDefinition));
            }

            throw new ArgumentException(
                string.Format(
                    CultureInfo.InvariantCulture,
                    "Could not find the field or property \"{0}\" in type \"{1}\".",
                    mappingDefinition.Name,
                    targetType.AssemblyQualifiedName),
                "mappingDefinition");
        }
        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));
        }