public void SerializationTest()
        {
            // Arrange.
            const string DisplayName = "Test Type";
            const string Name = "TestType";
            const string ElementTypeName = "ElementType";
            const WebServiceTypeCode TypeCode = WebServiceTypeCode.String;
            const string DerivedTypeName = "TestDerivedType";
            const string FieldName = "TestField";
            const string FieldType = "TestFieldType";

            var service = new WebServiceClientDescription();
            var type = new WebServiceTypeDescription(service)
                           {
                               DisplayName = DisplayName,
                               Name = Name,
                               ElementTypeName = ElementTypeName,
                               IsSimple = true,
                               IsArray = true,
                               IsAbstract = true,
                               IsEnum = true,
                               IsNullable = true,
                               TypeCode = TypeCode
                           };

            type.AssignableTypes.Add(new WebServiceTypeReference { TypeName = DerivedTypeName });
            type.Fields.Add(new WebServiceTypeFieldDescription(type) { Name = FieldName, TypeName = FieldType });

            // Act.
            var element = type.GetXElement();
            var newType = WebServiceTypeDescription.CreateTypeDescription(service, element);

            // Assert.
            Assert.AreEqual(DisplayName, newType.DisplayName);
            Assert.AreEqual(Name, newType.Name);
            Assert.AreEqual(ElementTypeName, newType.ElementTypeName);
            Assert.IsTrue(newType.IsSimple);
            Assert.IsTrue(newType.IsArray);
            Assert.IsTrue(newType.IsAbstract);
            Assert.IsTrue(newType.IsEnum);
            Assert.IsTrue(newType.IsNullable);
            Assert.AreEqual(TypeCode, newType.TypeCode);
            
            Assert.AreEqual(1, newType.AssignableTypes.Count);
            Assert.AreEqual(DerivedTypeName, newType.AssignableTypes.ElementAt(0).TypeName);

            Assert.AreEqual(1, newType.Fields.Count);
            Assert.AreEqual(FieldName, newType.Fields.ElementAt(0).Name);
            Assert.AreEqual(FieldType, newType.Fields.ElementAt(0).TypeName);
        }
        /// <summary>
        /// Gets the service description.
        /// </summary>
        /// <param name="serviceContract">The service contract.</param>
        /// <returns>WebServiceClientDescription.</returns>
        /// <exception cref="System.InvalidOperationException">Service client type not found.</exception>
        private WebServiceClientDescription GetServiceDescription(Type serviceContract)
        {
            var contractClient = _proxyAssembly.GetTypes().FirstOrDefault(t => !t.IsAbstract && serviceContract.IsAssignableFrom(t));
            if (contractClient == null)
                throw new InvalidOperationException("Service client type not found.");

            var serviceDescription = new WebServiceClientDescription { ContractTypeName = serviceContract.GetAssemblyQualifiedName() };

            serviceDescription.Methods.AddRange(GetWebMethdods(serviceContract).Select(m => GetMethodDescription(serviceDescription, m)));

            var accessibleTypes = GetAccessibleTypes(serviceContract);

            foreach (var type in accessibleTypes)
                serviceDescription.TypeDescriptions.Add(GetTypeDescription(serviceDescription, type));

            return serviceDescription;
        }
        public void IsAssignableFromTest()
        {
            // Arrange.
            var service = new WebServiceClientDescription();
            var type1 = new WebServiceTypeDescription(service) { Name = "Type1" };
            var derived1 = new WebServiceTypeDescription(service) { Name = "Derived1" };
            var derived2 = new WebServiceTypeDescription(service) { Name = "Derived2" };
            var type2 = new WebServiceTypeDescription(service) { Name = "Type2" };

            type1.AssignableTypes.Add(new WebServiceTypeReference { TypeName = derived1.Name });
            type1.AssignableTypes.Add(new WebServiceTypeReference { TypeName = derived2.Name });

            // Act / Assert.
            Assert.IsTrue(type1.IsAssignableFrom(type1));
            Assert.IsTrue(type1.IsAssignableFrom(derived1));
            Assert.IsTrue(type1.IsAssignableFrom(derived2));
            Assert.IsFalse(type1.IsAssignableFrom(type2));
        }
        public void SerializationTest()
        {
            // Arrange.
            const string MethodName = "TestMethod";
            const string ParameterName = "testParameter";
            const string ParameterType = "TestType1";

            var serviceDescription = new WebServiceClientDescription();
            var method = new WebServiceMethodDescription(serviceDescription) { Name = MethodName };
            method.InputParameters.Add(new WebServiceMethodParameterDescription(method) { Name = ParameterName, TypeName = ParameterType });

            // Act.
            var element = method.GetXElement();
            var newMethod = WebServiceMethodDescription.CreateMethodDescription(serviceDescription, element);

            // Assert.
            Assert.AreEqual(MethodName, newMethod.Name);
            
            Assert.AreEqual(1, newMethod.InputParameters.Count);
            Assert.AreEqual(ParameterName, newMethod.InputParameters.ElementAt(0).Name);
            Assert.AreEqual(ParameterType, newMethod.InputParameters.ElementAt(0).TypeName);
        }
        public void GetAssignableTypesForTypeTest()
        {
            // Arrange.
            var serviceDescription = new WebServiceClientDescription();
            var type1 = new WebServiceTypeDescription(serviceDescription) { Name = "Type1" };
            var type2 = new WebServiceTypeDescription(serviceDescription) { Name = "Type2" };
            var type3 = new WebServiceTypeDescription(serviceDescription) { Name = "Type3", IsAbstract = true };

            type1.AssignableTypes.Add(new WebServiceTypeReference { TypeName = type2.Name });
            type1.AssignableTypes.Add(new WebServiceTypeReference { TypeName = type3.Name });

            serviceDescription.TypeDescriptions.Add(type1);
            serviceDescription.TypeDescriptions.Add(type2);
            serviceDescription.TypeDescriptions.Add(type3);

            // Act.
            var assignableTypes = serviceDescription.GetAssignableTypesForType(type1);

            // Assert.
            Assert.AreEqual(2, assignableTypes.Count);
            Assert.IsTrue(assignableTypes.Contains(type1));
            Assert.IsTrue(assignableTypes.Contains(type2));
        }
        public void SerializationTest()
        {
            // Arrange.
            const int Id = 123;
            const string ContractTypeName = "TestContract";
            const string EndpointConfiguration = "Test Endpoint Configuration";

            var serviceDescription = new WebServiceClientDescription
                                     {
                                         Id = Id,
                                         ContractTypeName = ContractTypeName,
                                         EndpointConfiguration = EndpointConfiguration
                                     };

            serviceDescription.Methods.Add(new WebServiceMethodDescription(serviceDescription) { Name = "Method1" });
            serviceDescription.Methods.Add(new WebServiceMethodDescription(serviceDescription) { Name = "Method2" });
            serviceDescription.TypeDescriptions.Add(new WebServiceTypeDescription(serviceDescription) { Name = "Type1", DisplayName = "Type 1" });
            serviceDescription.TypeDescriptions.Add(new WebServiceTypeDescription(serviceDescription) { Name = "Type2", DisplayName = "Type 2" });

            // Act.
            var bytes = serviceDescription.Serialize();
            var newServiceDescription = WebServiceClientDescription.Deserialize(bytes);

            // Assert.
            Assert.AreEqual(Id, newServiceDescription.Id);
            Assert.AreEqual(ContractTypeName, newServiceDescription.ContractTypeName);
            Assert.AreEqual(EndpointConfiguration, newServiceDescription.EndpointConfiguration);
            
            Assert.AreEqual(2, newServiceDescription.Methods.Count);
            Assert.AreEqual("Method1", newServiceDescription.Methods.ElementAt(0).Name);
            Assert.AreEqual("Method2", newServiceDescription.Methods.ElementAt(1).Name);

            Assert.AreEqual(2, newServiceDescription.TypeDescriptions.Count);
            Assert.AreEqual("Type1", newServiceDescription.TypeDescriptions.ElementAt(0).Name);
            Assert.AreEqual("Type2", newServiceDescription.TypeDescriptions.ElementAt(1).Name);
        }
        public void FindTypeByNameTest()
        {
            // Arrange.
            var serviceDescription = new WebServiceClientDescription();
            var type1 = new WebServiceTypeDescription(serviceDescription) { Name = "Type1" };
            var type2 = new WebServiceTypeDescription(serviceDescription) { Name = "Type2" };
            
            serviceDescription.TypeDescriptions.Add(type1);
            serviceDescription.TypeDescriptions.Add(type2);

            // Act / Assert.
            Assert.AreSame(type1, serviceDescription.FindTypeByName("Type1"));
            Assert.AreSame(type2, serviceDescription.FindTypeByName("Type2"));
            Assert.IsNull(serviceDescription.FindTypeByName("Type3"));
        }
        /// <summary>
        /// Gets the method description.
        /// </summary>
        /// <param name="declaringService">The declaring service.</param>
        /// <param name="method">The method.</param>
        /// <returns>WebServiceMethodDescription.</returns>
        private WebServiceMethodDescription GetMethodDescription(WebServiceClientDescription declaringService, MethodInfo method)
        {
            var requestType = GetRequestType(method);
            var methodDescription = new WebServiceMethodDescription(declaringService) { Name = method.Name };

            var requestFields = requestType.GetFields(BindingFlags.Instance | BindingFlags.Public);
            var resultFields = method.ReturnType.GetFields(BindingFlags.Instance | BindingFlags.Public);

            methodDescription.InputParameters.AddRange(
                requestFields.Where(IsMessageBodyMember).Select(p => GetMethodParameterDescription(methodDescription, p)));

            methodDescription.InputParameters.AddRange(
                requestFields.Where(IsMessageHeader).Select(h => GetMethodParameterDescription(methodDescription, h)));

            methodDescription.OutputParameters.AddRange(
                resultFields.Where(IsMessageBodyMember).Select(f => GetMethodParameterDescription(methodDescription, f)));

            methodDescription.OutputParameters.AddRange(
                resultFields.Where(IsMessageHeader).Select(f => GetMethodParameterDescription(methodDescription, f)));

            return methodDescription;
        }
        /// <summary>
        /// Gets the type description.
        /// </summary>
        /// <param name="declaringService">The declaring service.</param>
        /// <param name="type">The type.</param>
        /// <returns>WebServiceTypeDescription.</returns>
        private WebServiceTypeDescription GetTypeDescription(WebServiceClientDescription declaringService, Type type)
        {
            var underlyingType = Nullable.GetUnderlyingType(type);
            var typeDescription = new WebServiceTypeDescription(declaringService)
                                      {
                                          TypeCode = WebServiceTypeDescription.GetTypeCode(underlyingType ?? type),
                                          Name = type.GetAssemblyQualifiedName(),
                                          DisplayName = GetDisplayName(underlyingType ?? type),
                                          IsAbstract = type.IsAbstract,
                                          IsArray = type.IsArray,
                                          IsEnum = (underlyingType ?? type).IsEnum,
                                          IsSimple = IsSimpleType(underlyingType ?? type),
                                          IsNullable = IsNullableType(type)
                                      };

            if (type.IsArray)
                typeDescription.ElementTypeName = type.GetElementType().GetAssemblyQualifiedName();

            if (type.Assembly == _proxyAssembly && !type.IsArray && !IsSimpleType(type))
                typeDescription.Fields.AddRange(
                    type.GetFields(BindingFlags.Instance | BindingFlags.Public).Select(f => GetTypeFieldDescription(typeDescription, f)));

            typeDescription.AssignableTypes.AddRange(GetIncludedTypes(type).Where(type.IsAssignableFrom).Select(GetTypeReference));

            return typeDescription;
        }
        /// <summary>
        /// Creates the type description.
        /// </summary>
        /// <param name="declaringService">The declaring service.</param>
        /// <param name="element">The element.</param>
        /// <returns>The <see cref="WebServiceTypeDescription"/>.</returns>
        public static WebServiceTypeDescription CreateTypeDescription(WebServiceClientDescription declaringService, XElement element)
        {
            ParseHelper.CheckRequiredElement(element, CnType);

            var type = new WebServiceTypeDescription(declaringService)
                           {
                               TypeCode =
                                   (WebServiceTypeCode)
                                   Enum.Parse(
                                       typeof(WebServiceTypeCode),
                                       ParseHelper.ReadRequiredAttribute(element, CnTypeCode),
                                       true),
                               Name = ParseHelper.ReadRequiredAttribute(element, CnName),
                               DisplayName = ParseHelper.ReadRequiredAttribute(element, CnDisplayName),
                               IsSimple =
                                   bool.Parse(ParseHelper.ReadOptionalAttribute(element, CnIsSimple, bool.FalseString)),
                               IsArray =
                                   bool.Parse(ParseHelper.ReadOptionalAttribute(element, CnIsArray, bool.FalseString)),
                               IsAbstract =
                                   bool.Parse(ParseHelper.ReadOptionalAttribute(element, CnIsAbstract, bool.FalseString)),
                               IsEnum = bool.Parse(ParseHelper.ReadOptionalAttribute(element, CnIsEnum, bool.FalseString)),
                               IsNullable =
                                   bool.Parse(ParseHelper.ReadOptionalAttribute(element, CnIsNullable, bool.FalseString))
                           };

            if (element.Attribute(CnElementTypeName) != null)
                type.ElementTypeName = ParseHelper.ReadOptionalAttribute(element, CnElementTypeName);

            var fieldsElement = element.Element(CnFields);

            if (fieldsElement != null)
            {
                type.Fields.AddRange(
                    fieldsElement.Elements(WebServiceTypeFieldDescription.CnField).Select(f => WebServiceTypeFieldDescription.CreateFieldDescription(type, f)));
            }

            var includedTypesElement = element.Element(CnAssignableTypes);

            if (includedTypesElement != null)
            {
                type.AssignableTypes.AddRange(includedTypesElement.Elements(WebServiceTypeReference.CN_TypeRef).Select(WebServiceTypeReference.CreateTypeReference));
            }

            return type;
        }
        /// <summary>
        /// Creates a method description.
        /// </summary>
        /// <param name="declaringService">
        /// The declaring service.
        /// </param>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <returns>
        /// The <see cref="WebServiceMethodDescription"/>.
        /// </returns>
        public static WebServiceMethodDescription CreateMethodDescription(WebServiceClientDescription declaringService, XElement element)
        {
            ParseHelper.CheckRequiredElement(element, CnMethod);

            var method = new WebServiceMethodDescription(declaringService) { Name = ParseHelper.ReadRequiredAttribute(element, CnName) };

            var parametersElement = element.Element(CnInputParameters);
            if (parametersElement != null)
            {
                method.InputParameters.AddRange(
                    parametersElement.Elements(WebServiceMethodParameterDescription.CnParameter)
                        .Select(x => WebServiceMethodParameterDescription.CreateParameterDescription(method, x)));
            }

            var outputParametersElement = element.Element(CnOutputParameters);
            if (outputParametersElement != null)
            {
                method.OutputParameters.AddRange(
                    outputParametersElement.Elements(WebServiceMethodParameterDescription.CnParameter)
                        .Select(x => WebServiceMethodParameterDescription.CreateParameterDescription(method, x)));
            }

            return method;
        }
        private static WebServiceClientDescription CreateServiceDescription(XElement element)
        {
            ParseHelper.CheckRequiredElement(element, ServiceElementName);

            var service = new WebServiceClientDescription
            {
                Id = int.Parse(ParseHelper.ReadRequiredAttribute(element, IdAttributeName)),
                ContractTypeName = ParseHelper.ReadRequiredAttribute(element, ContractTypeNameAttributeName)
            };

            var endpointConfigurationElement = element.Element(EndpointConfigurationElementName);
            if (endpointConfigurationElement != null)
            {
                service.EndpointConfiguration = endpointConfigurationElement.Value;
            }

            var methodsElement = element.Element(MethodsElementName);

            if (methodsElement != null)
            {
                service.Methods.AddRange(
                    methodsElement.Elements(WebServiceMethodDescription.CnMethod).Select(x => WebServiceMethodDescription.CreateMethodDescription(service, x)));
            }

            var typesElement = element.Element(TypesElementName);

            if (typesElement != null)
            {
                service.TypeDescriptions.AddRange(
                    typesElement.Elements(WebServiceTypeDescription.CnType).Select(x => WebServiceTypeDescription.CreateTypeDescription(service, x)));
            }

            return service;
        }