File: ServiceModel\MessageContractTest.4.4.0.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\tests\System.ServiceModel.Primitives.Tests.csproj (System.ServiceModel.Primitives.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Text;
using Infrastructure.Common;
using Xunit;
 
public static class MessageContractTest_4_4_0
{
    [WcfTheory]
    [InlineData(true)]
    [InlineData(false)]
    public static void MessageHeaderArray_MustUnderStand_Sets(bool mustUnderstand)
    {
        MessageHeaderArrayAttribute attribute = new MessageHeaderArrayAttribute();
        attribute.MustUnderstand = mustUnderstand;
        Assert.Equal(mustUnderstand, attribute.MustUnderstand);
    }
 
    [WcfTheory]
    [InlineData(new object[] { null })]
    [InlineData("")]
    [InlineData("testName")]
    public static void MessageProperty_Name_Sets(string name)
    {
        MessagePropertyAttribute attribute = new MessagePropertyAttribute();
        attribute.Name = name;
        Assert.True(String.Equals(name, attribute.Name),
                    String.Format("Set Name to '{0}' but getter returned '{1}'", name, attribute.Name));
    }
 
    [WcfFact]
    public static void MessageContract_ContractDescription_MessageHeaders()
    {
        // -----------------------------------------------------------------------------------------------
        // IMessageContract_4_4_0:
        //    This service exposes a single operation that uses MessageContract.
        //    This contract uses attributes added to the public API only after 1.1.0
        //    (MessageHeaderArrayAttribute and MessageProperty)
        // -----------------------------------------------------------------------------------------------
        string results = ContractDescriptionTestHelper.ValidateContractDescription<IMessageContract_4_4_0>(new ContractDescriptionData
        {
            Operations = new OperationDescriptionData[]
            {
                new OperationDescriptionData
                {
                    Name = TestTypeConstants_4_4_0.MessageContract_RequestReply_OperationName,
                    IsOneWay = false,
                    HasTask = false,
                    Messages = new MessageDescriptionData[]
                    {
                        // The request message description
                        new MessageDescriptionData
                        {
                            Action = TestTypeConstants_4_4_0.MessageContract_Request_Action,
                            Direction = MessageDirection.Input,
                            MessageType = typeof(RequestBankingData_4_4_0),
                            Body = new PartDescriptionData[]
                            {
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Request_TransactionDateName,
                                                          Type = typeof(DateTime),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Request_CustomerName,
                                                          Type = typeof(string),
                                                          Multiple = false }
                            },
                            Headers = new PartDescriptionData[]
                            {
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Request_SingleValueName,
                                                          Type = typeof(string),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Request_MultipleValueName,
                                                          Type = typeof(string[]),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Request_MultipleArrayValueName,
                                                          Type = typeof(string),
                                                          Multiple = true },
                            },
                            Properties = new PartDescriptionData[]
                            {
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Request_PropertyName,
                                                          Type = null,
                                                          Multiple = false },
                            }
                        },
 
                        // The reply message description
                        new MessageDescriptionData
                        {
                            Action = TestTypeConstants_4_4_0.MessageContract_Reply_Action,
                            Direction = MessageDirection.Output,
                            MessageType = typeof(ReplyBankingData_4_4_0),
                            Body = new PartDescriptionData[]
                            {
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_TransactionDateName,
                                                          Type = typeof(DateTime),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_CustomerName,
                                                          Type = typeof(string),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_TransactionAmountName,
                                                          Type = typeof(decimal),
                                                          Multiple = false },
                            },
                            Headers = new PartDescriptionData[]
                            {
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_SingleValueName,
                                                          Type = typeof(string),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_MultipleValueName,
                                                          Type = typeof(string[]),
                                                          Multiple = false },
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_MultipleArrayValueName,
                                                          Type = typeof(string),
                                                          Multiple = true },
                            },
                            Properties = new PartDescriptionData[]
                            {
                                new PartDescriptionData { Name = TestTypeConstants_4_4_0.MessageContract_Reply_PropertyName,
                                                          Type = null,
                                                          Multiple = false },
                            }
                        }
                    }
               }
            }
        });
 
        // Assert.True because results contains informative error failure
        Assert.True(results == null, results);
    }
 
    [WcfFact]
    public static void MessageContract_Builds_Correct_Request_Message_Properties_And_Headers()
    {
        MockChannelFactory<IRequestChannel> mockChannelFactory = null;
        MockRequestChannel mockRequestChannel = null;
        RequestBankingData_4_4_0 request = null;
        Dictionary<string, string> properties = new Dictionary<string, string>();
        Dictionary<string, List<string>> headers = new Dictionary<string, List<string>>();
 
        // *** SETUP *** \\
        // Intercept the creation of the factory so we can intercept creation of the channel
        Func<Type, BindingContext, IChannelFactory> buildFactoryAction = (Type type, BindingContext context) =>
        {
            mockChannelFactory = new MockChannelFactory<IRequestChannel>(context, new TextMessageEncodingBindingElement().CreateMessageEncoderFactory());
            mockChannelFactory.OnCreateChannelOverride = (EndpointAddress endpoint, Uri via) =>
            {
                // When the channel is created, override the Request method to capture properties and headers
                mockRequestChannel = (MockRequestChannel)mockChannelFactory.DefaultOnCreateChannel(endpoint, via);
                mockRequestChannel.RequestOverride = (msg, timeout) =>
                {
                    // Capture properties and headers before the message is read and closed
                    foreach (var property in msg.Properties)
                    {
                        properties[property.Key] = property.Value.ToString();
                    }
 
                    foreach (MessageHeader header in msg.Headers)
                    {
                        List<string> values = null;
                        if (!headers.TryGetValue(header.Name, out values))
                        {
                            values = new List<string>();
                            headers[header.Name] = values;
                        }
 
                        string headerValue = header.ToString().Replace(Environment.NewLine, String.Empty).Replace("  ", String.Empty);
                        values.Add(headerValue);
                    }
 
                    // Echo back a fresh copy of the request
                    MessageBuffer buffer = msg.CreateBufferedCopy(Int32.MaxValue);
                    return buffer.CreateMessage();
                };
 
                return mockRequestChannel;
            };
 
            return mockChannelFactory;
        };
 
        MockTransportBindingElement mockBindingElement = new MockTransportBindingElement();
        mockBindingElement.BuildChannelFactoryOverride = buildFactoryAction;
 
        CustomBinding binding = new CustomBinding(mockBindingElement);
        EndpointAddress address = new EndpointAddress("myprotocol://localhost:5000");
        var factory = new ChannelFactory<IMessageContractRoundTrip_4_4_0>(binding, address);
        IMessageContractRoundTrip_4_4_0 channel = factory.CreateChannel();
 
        // Prepare a strongly-typed request
        request = new RequestBankingData_4_4_0();
        request.accountName = "My account";
        request.transactionDate = DateTime.Now;
        request.requestTestProperty = "test property";
        request.testValue = "test value";
        request.testValues = new string[] { "test", "values" };
        request.testValuesArray = new string[] { "test", "values", "array"};
 
        // *** EXECUTE *** \\
        channel.MessageContractRoundTrip(request);
 
        // *** VALIDATE *** \\
 
        string propertyValue = null;
        bool hasProperty = properties.TryGetValue(TestTypeConstants_4_4_0.MessageContract_Request_PropertyName, out propertyValue);
        Assert.True(hasProperty, String.Format("Expected message property '{0}'", TestTypeConstants_4_4_0.MessageContract_Request_PropertyName));
        Assert.True(String.Equals(request.requestTestProperty, propertyValue),
                    String.Format("Message property value for '{0}' expected = '{1}', actual = '{2}'",
                                  TestTypeConstants_4_4_0.MessageContract_Request_PropertyName, request.requestTestProperty, propertyValue));
 
        ValidateHeader(headers, TestTypeConstants_4_4_0.MessageContract_Request_SingleValueName,
@"<?xml version=""1.0"" encoding=""utf-16""?>" +
@"<h:Request_SingleRequestValue xmlns:h=""http://www.contoso.com"">test value</h:Request_SingleRequestValue>");
 
        ValidateHeader(headers, TestTypeConstants_4_4_0.MessageContract_Request_MultipleValueName,
@"<?xml version=""1.0"" encoding=""utf-16""?>" + 
@"<h:Request_MultipleRequestValue xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:h=""http://www.contoso.com"">" + 
@"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/Arrays"">test</string>" + 
@"<string xmlns=""http://schemas.microsoft.com/2003/10/Serialization/Arrays"">values</string>" +
@"</h:Request_MultipleRequestValue>");
 
        ValidateHeader(headers, TestTypeConstants_4_4_0.MessageContract_Request_MultipleArrayValueName,
@"<?xml version=""1.0"" encoding=""utf-16""?>" + 
@"<h:Request_MultipleArrayRequestValue xmlns:h=""http://www.contoso.com"">test</h:Request_MultipleArrayRequestValue>",
 
@"<?xml version=""1.0"" encoding=""utf-16""?>" + 
@"<h:Request_MultipleArrayRequestValue xmlns:h=""http://www.contoso.com"">values</h:Request_MultipleArrayRequestValue>",
 
@"<?xml version=""1.0"" encoding=""utf-16""?>" + 
@"<h:Request_MultipleArrayRequestValue xmlns:h=""http://www.contoso.com"">array</h:Request_MultipleArrayRequestValue>");
    }
 
    [WcfFact]
    public static void MessageContract_RoundTrips_Properties_And_Headers()
    {
        MockChannelFactory<IRequestChannel> mockChannelFactory = null;
        MockRequestChannel mockRequestChannel = null;
        RequestBankingData_4_4_0 request = null;
        RequestBankingData_4_4_0 reply = null;
 
        // *** SETUP *** \\
        // Intercept the creation of the factory so we can intercept creation of the channel
        Func<Type, BindingContext, IChannelFactory> buildFactoryAction = (Type type, BindingContext context) =>
        {
            mockChannelFactory = new MockChannelFactory<IRequestChannel>(context, new TextMessageEncodingBindingElement().CreateMessageEncoderFactory());
            mockChannelFactory.OnCreateChannelOverride = (EndpointAddress endpoint, Uri via) =>
            {
                // When the channel is created, override the Request method to capture properties and headers
                mockRequestChannel = (MockRequestChannel)mockChannelFactory.DefaultOnCreateChannel(endpoint, via);
                mockRequestChannel.RequestOverride = (msg, timeout) =>
                {
                    // Echo back a fresh copy of the request
                    MessageBuffer buffer = msg.CreateBufferedCopy(Int32.MaxValue);
                    Message replyMsg = buffer.CreateMessage();
                    return replyMsg;
                };
 
                return mockRequestChannel;
            };
 
            return mockChannelFactory;
        };
 
        MockTransportBindingElement mockBindingElement = new MockTransportBindingElement();
        mockBindingElement.BuildChannelFactoryOverride = buildFactoryAction;
 
        CustomBinding binding = new CustomBinding(mockBindingElement);
        EndpointAddress address = new EndpointAddress("myprotocol://localhost:5000");
        var factory = new ChannelFactory<IMessageContractRoundTrip_4_4_0>(binding, address);
        IMessageContractRoundTrip_4_4_0 channel = factory.CreateChannel();
 
        // Prepare a strongly-typed request
        request = new RequestBankingData_4_4_0();
        request.accountName = "My account";
        request.transactionDate = DateTime.Now;
        request.requestTestProperty = "test property";
        request.testValue = "test value";
        request.testValues = new string[] { "test", "values" };
        request.testValuesArray = new string[] { "test", "values", "array" };
 
        // *** EXECUTE *** \\
        reply = channel.MessageContractRoundTrip(request);
 
        // *** VALIDATE *** \\
        Assert.True(String.Equals(request.requestTestProperty, reply.requestTestProperty),
                    String.Format("TestProperty expected = '{0}' actual = '{1}'",
                                  request.requestTestProperty, reply.requestTestProperty));
 
        ValidateArray("TestValues", request.testValues, reply.testValues);
        ValidateArray("TestValuesArray", request.testValuesArray, reply.testValuesArray);
    }
 
    private static void ValidateHeader(Dictionary<string, List<string>> headers, string name, params string[] values)
    {
        List<string> headerValues;
        bool hasHeader = headers.TryGetValue(name, out headerValues);
        Assert.True(hasHeader, String.Format("Expected header '{0}'", name));
 
        StringBuilder errorBuilder = new StringBuilder();
        for (int i = 0; i < headerValues.Count; ++i)
        {
            errorBuilder.AppendLine(String.Format("---- Header[{0}] ----", i));
            errorBuilder.AppendLine(String.Format("{0}", headerValues[i]));
        }
 
        Assert.True(values.Length == headerValues.Count,
                    String.Format("Expected header '{0}' to have {1} values, actual = {2}", name, values.Length, headerValues.Count));
 
        foreach (string value in values)
        {
            Assert.True(headerValues.Contains(value),
                        String.Format("Expected header '{0}' to contain value:{1}{2}{1} but it contained these:{1}{3}", 
                                      name, Environment.NewLine, value, errorBuilder.ToString()));
        }
    }
 
    private static void ValidateArray(string elementName, string[] array1, string[] array2)
    {
        Assert.True(array2 != null,
                    String.Format("The {0} element returned a null array", elementName));
 
        Assert.True(array1.Length == array2.Length,
                    String.Format("The {0} element was expected to return {1} items, actual = {2}",
                                    elementName, array1.Length, array2.Length));
 
        for (int i = 0; i < array1.Length; ++i)
        {
            Assert.True(array1[i] == array2[i],
                        String.Format("Array item {0} of element {1} was expected to be {2}, actual was {3}",
                                        i, elementName, array1[i], array2[i]));
        }
    }
}