BloggingAbout.NET
Thoughts of developers
WCF Test Harness: Release 1.1.1.1

The WCF Test Harness has been updated

  • The previous version would fail to build the dynamic proxy for some services.  In particular BizTalk isolated host service endpoints.  The new version will still attempt to build the proxy even if warnings are encountered when downloading the metadata.
  • This version uses an untyped channel to send the requests and responses (see below).  This allows for the messages to be more easily constructed and for more flexibility (or leniency) on the receive.  As a test tool this is useful for debugging and determining when an application does not conform to the metadata.  For example, the subtle differences between Java and .Net base soap solutions.
  • DataContractSerialization is now used for building the input message.

Untyped Channel

After a TestCase has been created that indicates the contract to call and the input, the InvokeProxyMethod method is used to call the service using an untyped channel.  By untyped, I mean conforming to the following signature:

[ServiceContract]
public interface IUntypedChannel
{
    [OperationContract(Action = "*", ReplyAction = "*")]
    Message Post(Message content);
}

The following code is used to create a ContractChannelFactory<T> using reflection.  Reflection is necessary as the contract type (T) is not known until runtime.  The ContractChannelFactory is based on the ClientChannelFactory<T> from the Microsoft WCF Samples.  The main difference is it can be used to create a IUntypedChannel channel.  This can be used to post a Message based on the contract type's message properties.

public string InvokeProxyMethod(TestCase test)
{
    string ret = "Failed to call test case...";
 
    // determine the contract type
    ServiceClientContract contract = _contracts[test.ContractName];
    ClientEndpoint endpoint = contract.Endpoints[test.EndpointName];
    Type contractType = Assemblies[test.Assembly].GetType(endpoint.Contract);
    
    // create the factory to generate the channel
    Type factoryType = typeof(ContractChannelFactory<>).MakeGenericType(contractType);
    Object factory = Activator.CreateInstance(factoryType, new object[] {test.EndpointName, contract.FileName});
   
    // create the channel
    IUntypedChannel channel = (IUntypedChannel)factoryType.InvokeMember("CreateUntypedChannel", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, factory, new object[] { test.URL });
    
    // determine the action
    MemberInfo s = contractType.GetMethod(test.Method);
    object[] attributes = s.GetCustomAttributes(typeof(OperationContractAttribute), true);
    if (attributes.Length == 1)
    {
        using (StringReader sr = new StringReader(test.Input))
        {
            // build an untyped message with the same message version, input and action
            XmlReader xr = XmlTextReader.Create(sr);
            OperationContractAttribute attribute = (OperationContractAttribute)attributes[0];
            MessageVersion version = (MessageVersion)factoryType.InvokeMember("GetMessageVersion", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, factory, new object[] { });
            Message request = Message.CreateMessage(version, attribute.Action, xr);
 
            // call the service
            Message response = channel.Post(request);
 
            ret = response.ToString();
 
            xr.Close();
            sr.Close();
        }
    }
 
    return ret;
}

ContractChannelFactory<T>

The ContractChannelFactory<T> is used to build the ChannelFactory<T> using a supplied configuration file.  The new methods, CreateUntypedChanee() and GetMessageVersion() are used to create a channel that will send a untyped message.

public class ContractChannelFactory<T> : ChannelFactory<T>
{
    // contructor and methods to build channelfactory based on supplied configuration file
    ...
    public IUntypedChannel CreateUntypedChannel(string overrideUrl)
    {
        EndpointAddress address = this.Endpoint.Address;
          
        // if an override then take the new address
        if(overrideUrl!=string.Empty)
            address = new EndpointAddress(new Uri(overrideUrl), address.Identity, address.Headers, address.GetReaderAtMetadata(), address.GetReaderAtExtensions());
 
        ChannelFactory<IUntypedChannel> factory = new ChannelFactory<IUntypedChannel>(this.Endpoint.Binding, address);            
        return factory.CreateChannel();
    }
 
    public MessageVersion GetMessageVersion()
    {
        return this.Endpoint.Binding.MessageVersion;
    }
  }

Posted Tue, Feb 24 2009 3:11 PM by chilberto
Filed under: ,

Comments

Christopher Steen wrote Link Listing - February 25, 2009
on Thu, Feb 26 2009 2:45 PM

Link Listing - February 25, 2009

Christopher Steen wrote Link Listing - February 25, 2009
on Thu, Feb 26 2009 2:45 PM

Podcasts Alan Stevens on Community 2.0 [Via: dotnetrocks ] Episode 26: Discovering Azure SQL Services...

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Please add 7 and 7 and type the answer here:
Copyright © 2003-2010 BloggingAbout.NET