Wednesday, June 27, 2012

Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property)

In my client application program I am referring to the service

myServiceReference.HelloWorldClient proxy = new Client.myServiceReference.HelloWorldClient("NetTcpBinding_IHelloWorld");
Console.WriteLine(proxy.ShowData("Hi There!"));

Here ShowData(string message) is a method that accepts a parameter of type string and returns a string. For testing purpose, I have added code for Thread.Sleep for 2 minutes. The default operation timeout on a WCF client channel is 00:01:00 (1 minute). So, the method call will result into the following exception:

This request operation sent to net.tcp://localhost:9000/ did not receive a reply within the configured timeout (00:01:00).  The time allotted to this operation may have been a portion of a longer timeout.  This may be because the service is still processing the operation or because the service was unable to send a reply message.  Please consider increasing the operation timeout (by casting the channel/proxy to IContextChannel and setting the OperationTimeout property) and ensure that the service is able to connect to the client.
<netTcpBinding>
                <binding name="NetTcpBinding_IHelloWorld" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="65536">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>

Increase the send timeout value:
sendTimeout="00:20:00"
The time required to increase the timeout value depends on the maximum response time of the service for a request.
If this does not fix the issue, the other way around as suggested by the error message itself is as below:
 myServiceReference.HelloWorldClient proxy = new Client.myServiceReference.HelloWorldClient("NetTcpBinding_IHelloWorld");
           
proxy.InnerChannel.OperationTimeout = new TimeSpan(0, 20, 00);
Anyways we need to know the service response time for a method call to set the operation timeout and fix the issue.

Monday, June 25, 2012

WCF Versioning

Part 2:WCF Versioning

Part 1: WCF Versioning-Understanding the versioning and common issues


Before understanding how to version the services, let us understand WSDL Contracts and policies.

Every client must agree on some of the policies and contracts with the service to utilize the operations provided by the services. These are defined in the WSDL file.

Basically WSDL file is used to describe a service and its endpoints, what are the protocols used to access the operations and types of the messages. It also may or may not comprise of policy sections.

WS-Policy dictates the security features used by the service, if the service supports reliable messaging or transactions and the message encoding supported and other information on the protocols supported by a service.

After sharing WSDL file with the clients, the service should not be changed unless the client is willing to handle the changes. But, in a real world the services always should evolve by supporting the backward compatibility. This is one of the requirements of the SOA principles. The policies may change in order to provide extra security policies and other reliability features. This should not force the clients to change their coding and of course, no client would like to subscribe to the services if they have to change their code every time. So, in order to make the versioning possible we may have to think on the versioning strategies before developing the services.

With reference to on the Microsoft articles on WCF, there are two types of strategies for versioning. One is Strict Versioning and the other one Practical Versioning.

Let us understand the versioning by example.

Create a WCF Library and a host as discussed in the Part 1. We are not going to use HTTPBinding for this to make the test simple. So, we do not need to change the app.config in the host project.

using System;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

using System.ServiceModel;

usingSystem.Runtime.Serialization;



namespace HelloWorld

{

[DataContract]

public class Customer

{

privateint m_Id;

privatestring m_Name;

privatestring m_Address;



[DataMember(IsRequired=true, Order=0)]

public int Id

{

get{ return m_Id; }

set{ m_Id = value; }

}



[DataMember(IsRequired = true, Order = 1)]

public string Name

{

get{ return m_Name; }

set{ m_Name = value; }

}



[DataMember(IsRequired = false, Order = 2)]

public string Address

{

get{ return m_Address; }

set{ m_Address = value; }

}



}

}





We have created a custom class called Customer and decorated it with [DataContract]. To create a data contract, we need to use the namespace“System.Runtime.Serialization”. We added few properties to the class. In WCF, each member of the data contract is designated with attribute [DataMember].

A very good information for Data contract from Microsoft is as follows:

A data contract is a formal agreement between a service and a client that abstractly describes the data to be exchanged. That is, to communicate, the client and the service do not have to share the same types, only the same data contracts. A data contract precisely defines, for each parameter or return type, what data is serialized (turned into XML) to be exchanged.

Windows Communication Foundation (WCF) uses a serialization engine called the Data Contract Serializer by default to serialize and deserialize data (convert it to and from XML). All .NET Framework primitive types, such as integers and strings, as well as certain types treated as primitives, such as DateTimeand XmlElement, can be serialized with no other preparation and are considered as having default data contracts. Many .NET Framework types also have existing data contracts. For a full list of serializable types, see Types Supported by the Data Contract Serializer.

New complex types that you create must have a data contract defined for them to be serializable. By default, the DataContractSerializerinfers the data contract and serializes all publicly visible types. All public read/write properties and fields of the type are serialized. You can opt out members from serialization by using the IgnoreDataMemberAttribute. You can also explicitly create a data contract by using DataContractAttributeand DataMemberAttributeattributes. This is normally done by applying the DataContractAttributeattribute to the type. This attribute can be applied to classes, structures, and enumerations. The DataMemberAttribute attribute must then be applied to each member of the data contract type to indicate that it is a data member, that is, it should be serialized.

More information on this can be had from MSDN link http://msdn.microsoft.com/en-us/library/ms733127%28v=vs.90%29.aspx

And also observe that each data member has got a property“isRequired”. This instructs the serialization engine that the member must be present when reading or deserializing. That means, if the client do not set the property, the service throws an error when the member is decorated with“isRequired=true”. Second thing to notice in the attribute properties is the order. The property Order dictates the order of serialization and deserialization of a member.

If any of the data member attribute has a property“isRequired=false”, this will not enforce the serialization engine to check if the value is set while reading the property. Meaning that client never need to set a value for this member.

By default WCF contracts are version tolerant. That means service contracts, data contracts and message contracts if the client does not send the non-required data or any missing information from the client or any extra information from the client. So, we do not need to worry if we have to change the contracts by adding new operations or new members for data contracts or removing the non-required members or parameters.

There is a table provided in one of the Microsoft web casts on the versioning and how it matters based on the type of change. This gives a clear picture on the effect of versioning the existing services without taking care of proper procedures or guide lines.





Let us see the above said in practice.

Now modify the IHelloWorld interface created in the previous example.

using System;

usingSystem.Collections.Generic;

usingSystem.Linq;

using System.Runtime.Serialization;

usingSystem.ServiceModel;

usingSystem.Text;



namespace HelloWorld

{

// NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in App.config.

[ServiceContract(SessionMode=SessionMode.Allowed)]

public interface IHelloWorld

{

[OperationContract]

voidSetCustomer(Customer customer);



[OperationContract]

CustomerGetCustomer();


}




}



And implement the interface in the service class HelloWorld.cs:

using System;

usingSystem.Collections.Generic;

usingSystem.Linq;

using System.Runtime.Serialization;

usingSystem.ServiceModel;

usingSystem.Text;



namespace HelloWorld

{

// NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in App.config.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]

public class HelloWorld :IHelloWorld

{

privateCustomer customer;

#region IHelloWorld Members



public void SetCustomer(Customercustomer)

{

this.customer = customer;

Console.WriteLine("Setting Customer");

}



public Customer GetCustomer()

{

returnthis.customer;

}



#endregion

}

}



Now rebuild the solution and run an instance of host project to check if everything is good till now.

Now we need to refer the service hosted on TCP/IP from the client application. Create a console application for client and add the Customer.cs class from the HelloWorld project and add a reference to System.Runtime.Serialization. Since we are not generating any WSDL, we cannot reference the service directly from visual studio àAdd service reference mechanism.

In real world, we are going to generate WSDL and share the same with our clients.

So, your solution should like as below:




Program.cs in your client application should look as in the below:

using System;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingSystem.ServiceModel;

usingHelloWorld;



namespace Client

{

class Program

{

[ServiceContract]

public interface IHelloWorld

{

[OperationContract]

voidSetCustomer(Customer customer);



[OperationContract]

CustomerGetCustomer();



}



static void Main(string[] args)

{



IHelloWorldproxy = ChannelFactory&lt;IHelloWorld&gt;.CreateChannel(new NetTcpBinding(),new EndpointAddress("net.tcp://localhost:9000/HelloWorld"));

Customercustomer = new Customer();

customer.Id = 1;

customer.Name = "John";

customer.Address = "NYC";

proxy.SetCustomer(customer);



CustomerlocalCustomer = proxy.GetCustomer();



Console.WriteLine("Customer ID is {0}", localCustomer.Id);

Console.WriteLine("Customer Name is {0}", localCustomer.Name);

Console.WriteLine("Customer Address is {0}", localCustomer.Address);

Console.ReadLine();

}

}

}



Now run the instances of host and client and check if you are able to send and get the values back. Put break points if needed in the service to check the communication.


Since the property “Address” is not marked as required in the Data Contract class in the WCF Service Library project, even if we comment the property, client still do not run into any exceptions. Rebuild the solution again.

//[DataMember(IsRequired = false, Order = 2)]

//public string Address

//{

// get { return m_Address; }

// set { m_Address = value; }

//}

Now run the service host application and client again.


Everything went well except client did not get the address back. This is OK if the client does not have any issue if the property value is not returned. But, in real world scenario we cannot comment something client expects it to be return.

Now uncomment the above and this time try to comment out the property with “isRequired = true”. Let us comment the property “Name” and check what happens:

//[DataMember(IsRequired = true, Order = 1)]

//public string Name

//{

// get { return m_Name; }

// set { m_Name = value; }

//}


You see the following error:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:GetCustomerResult. The InnerException message was ''Element' 'Address' from namespace 'http://schemas.datacontract.org/2004/07/HelloWorld' is not expected. Expecting element 'Name'.'. Please see InnerException for more details.

As we have already discussed at the beginning of the article, isRequired = true for any property instructs the serialization engine that the member must be present when reading or deserializing.

Now uncomment the one we did earlier and now try to add extra parameter to one of the operations and check again.

Change the interface and service class:

[ServiceContract(SessionMode=SessionMode.Allowed)]

public interface IHelloWorld

{

[OperationContract]

void SetCustomer(Customer customer, stringIamNotRequired);



[OperationContract]

CustomerGetCustomer();


}

public void SetCustomer(Customercustomer, string IamNotRequired)

{

this.customer = customer;

Console.WriteLine("Setting Customer");

}

Everything went fine. You might have remembered that the WCF services are version tolerant. They can ignore superfluous data.


Even if you add another operation to the service and the client does not consume the operation, still no exception occurs.

Add a new operation to the service and run the service host and client again.

In the interface:

[OperationContract]

void WasteMethod();

In the service class:

public void WasteMethod()

{

Console.WriteLine("I am waste");

}

Now test the changes and still the application is doing good with no errors. Similarly if you add a new non-required property nothing happens. But if you add any of the required properties in the data contract and client is not aware of the changes and if the client consumes the service, the service will get into an exception.

Test this again by adding a required method in the service.

[DataMember(IsRequired = true, Order = 3)]

public string Description

{

get{ return m_Description; }

set{ m_Description = value; }

}



The service has thrown the following exception:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:customer. The InnerException message was ''EndElement' 'customer' from namespace 'http://tempuri.org/' is not expected. Expecting element 'Description'.'. Please see InnerException for more details.

So, we cannot change the service without effecting the client every time and we need to think about the strategies of versioning the services when change is needed.

You can test the above without adding Customer.cs and modifying the Program.cs class in the client project with the interface definition, by adding basicHttpBinding in the service configuration and referring the service in the client project.

We will discuss the versioning strategies in the next article.

Wednesday, June 20, 2012

Hosting WCF Service Library in IIS

A service file (.svc) and web.config files are required for the WCF service to be hosted in IIS. Since WCF Service Library do not have these files by default we may not be able to host it in IIS directly. WCF Service Library project is basically to be able to host the service in Console, Windows Service, Windows application or IIS. So, we need to follow these steps to host the WCF Service Library in IIS:

1. Create a virtual directory in the IIS for the service.
2. Create two files in the virtual directory folder. One is the web.config and the other one somename.svc.
3. Now copy the content of <system.ServiceModel> in the app.config file of the WCF Service Library into the web.config.
4. Add the following content in the .svc file:
<% @ServiceHost Service="Namespace.MyServiceClass" language="C#" debug="false" %>
<%@ Assembly Name="Assembly Name" %>

From our previous examples in Part 1 and Part 2, it should be as follows:
<%@ ServiceHost Service="HelloWorld.HelloWorld"%>
<%@ Assembly Name="HelloWorld" %>
5. Create a bin folder in the virtual directory and place the HelloWorld.dll generated in the bin\debug folder of the WCF Service Library project.
6. Make sure that the IIS has got sufficient permissions on the folders and files created in the virtual directory.

Note:
In case if your config file has localhost anywhere, change it to the machine name. Otherwise, when you generate proxy using visual studio, your WSDL will have the "localhost" instead of the machine name and if you are trying to access it from another computer it will not work.

Hope this helps... Happy coding guys!!!

Monday, June 18, 2012

An endpoint configuration section for contract could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.


An endpoint configuration section for contract 'MyServiceReference.IHelloWorld' could not be loaded because more than one endpoint configuration for that contract was found. Please indicate the preferred endpoint configuration section by name.



This is due to the app.config in the client project has multiple endpoints defined and so the application does not know which one to use to communicate with the service. So, comment the other endpoints which you client application is not intending to refer to and run the client application again. The error should be gone.

For example, look at the following configuration in the app.config file in the client project:
<client>
            <endpoint address="http://localhost:8000/HelloWorld" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"
                name="BasicHttpBinding_IHelloWorld" />
            <endpoint address="net.tcp://localhost:9000/HelloWorld" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"
                name="NetTcpBinding_IHelloWorld">
                <identity>
                    <userPrincipalName value="MyPC\ComputerName" />
                </identity>
            </endpoint>
        </client>
The error is due to the app.config in the client project has two endpoints defined and so the application does not know which one to use to communicate with the service. So, comment the one endpoint which is referring to NetTcpBinding and run the program again.
<client>
            <endpoint address="http://localhost:8000/HelloWorld" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"
                name="BasicHttpBinding_IHelloWorld" />
            <!--<endpoint address="net.tcp://localhost:9000/HelloWorld" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IHelloWorld" contract="MyServiceReference.IHelloWorld"
                name="NetTcpBinding_IHelloWorld">
                <identity>
                    <userPrincipalName value="MyPC\ComputerName" />
                </identity>
            </endpoint>-->
        </client>

Otherwise, specify in your code which endpoint is to be used as in the below sample code:
 MyServiceReference.HelloWorldClient proxy = new Client.MyServiceReference.HelloWorldClient("BasicHttpBinding_IHelloWorld");
            Console.WriteLine(proxy.ShowData("Hello World From Client using basicHttpBinding"));

            proxy = new Client.MyServiceReference.HelloWorldClient("NetTcpBinding_IHelloWorld");
            Console.WriteLine(proxy.ShowData("Hello World From Client using netTcpBinding"));
Hope this helps!!!