Sunday, 3 January 2010

How to write a good code – 2

How to write a good code – 2

Following design principles makes design/ architecture of your project good and we developer don’t have much role in this. This is primarily taken as role of software/ solution architect. So what developer can do to make code better and understandable?

So it’s in hand of to write an easily understandable, well refactored and clean code developer (at least in agile world, where everything is not documented).

So I collected some useful information from “Clean Code – Robert C. Martin” and “Refactoring Improving the Design of Existing Code – Martin Fowler” and trying to present here.

These two books are amazing books and nobody can present everything written in these books on blogs so I urge every programmer to read these. But I hope that this small article from those books will give a good start.

These information / tips are divided into few categories.

Comments

Inappropriate Information

You should not write irrelevant information in comments like Change History, Author Name, Company Name etc. Comments should tell viewer about technical things like code and design.

Obsolete Comment

In agile world its always advised not to write comments at all and reason behind this is with time code gets modified and no one cares about modifying comment related to these modification so after some time comments becomes misleading. So if you writing code then make it sure that comments are always up to date or simply delete it. Have your function name meaningful. Your function should say what its doing.

Redundant Comment

Now if comments above function or near code are saying same what function name or code is saying then this is a redundant comment. So it’s wise to remove such kind of comments.

Poorly Written Comment

If you have to write comments because of any policy in your company or some other reason then write it properly and manage it properly. Take some time while writing these and write wisely.

Commented-Out Code

If you go through some old code then you may see some code commented. So these commented code doing nothing just increasing size of your file and making code base heavier in version control system. This also makes your code look bad and irritate you when you scroll through your code. So simply delete it, this is not going to harm you as it was already commented and how you can recover it from your version controlling application.

Functions

Too Many Arguments

You should avoid passing so many arguments in a function, if you have to pass many arguments then better to refactor your code and extract a class or structure containing these all variables and pass an instance of this class. Passing so many variables makes code look ugly, hard to understand and debug. It’s also bad according to abstraction to have so many arguments in any function.

Output Arguments

Output arguments as very confusing as viewer expects arguments to input not output.

Flag Arguments

Flag arguments like some Boolean values based on which we performs differently inside function are also very confusing and make code tougher to understand. So try not to have any kind of flag arguments in your function and use polymorphism to avoid these.

Dead Function

Dead functions are function which is no body in use but resides in code. So try to find these and delete it. It may be some time tough to find these kinds of functions because you also may have some unit test around these functions so you will always find reference or usage of these functions. So delete it carefully and delete it quickly and even you have broken your code you can always get this back from version controlling application.

General

Obvious Behavior Is Unimplemented

Avoid things of surprises and follow principle of least astonishment. You function should return or do things which is expected. Like GetDateOfJoining function is expected to return a date not a string.

Incorrect Behavior at the Boundaries

Often we don’t test our functions or code for boundary conditions generally we assume that they will work, this is always wise to test them for their boundary condition and just not assume.

Duplication

Don’t let any of your code to duplicate, extract that piece of code in another class and all other code will access it from there only. This decreases your maintenance cost and makes your code easy.

If code look doing similar thing but that is not 100% similar then follow some design patterns like template or strategy pattern for avoiding duplication in code.

Code at Wrong Level of Abstraction

Follow correct level of abstraction. Your base classes should not contain code or variable which your derived class is to use. Keep lower level things separated from higher level things. Try creating thin interfaces so that you need not to define unnecessary behaviors and give a dummy implementation to those. These functions/ behaviors can lead to a great level of confusion.

Base Classes Depending on Their Derivatives

Base class thing should know nothing about derived class. Base class should not depend upon derived class both should depend upon abstraction.

Too Much Information

Create thin (fine grained) interfaces so that coupling remains low. Follow correct level of abstraction and encapsulation. Don’t create classes with lots of methods/ functions. And don’t allow function/ methods to do many things.

Dead Code

Remove part of code which never gets executed. For this try writing unit tests for all possible scenarios and use some code coverage measuring tool and see which part of code never gets executed, delete that code.

Vertical Separation

Declare your local variables just before their usage and should have small scope. Declare your private function just below their first usage. This helps managing your code better.

Inconsistency

What ever you do, do in consistent manner. Name your variables, functions etc in consistent manner. Follow consistent code separation and design. Even a code not having good design but written in consistent way is easy to understand.

Clutter

Avoid clutters. i.e. remove all function, variables, constructors etc. which is never used or never executed in any condition.

Artificial Coupling & Feature Envy

Declare variables, functions, enums etc in the modules where they should be. Take your time to decide where they should go. This will reduce unnecessary coupling between different/ independent modules. If a function is using many variables from some other class then it indicates that function is declared at wrong location, it should be moved to then class which variables it using.

Inappropriate Static

Prefer non-static methods over static methods, only declare those methods static which need to be and in doubt make it non-static. In case your function can behave polymorphically then make it non-static.

Use Explanatory Variables

Variable name should say what purpose this variable is serving. Don’t hesitate to have a longer and explanatory name for your variable.

Function Names Should Say What They Do

Use explanatory name for your function, its name should say what function is doing.

Understand the Algorithm

If you working on some old code base and you are modifying some function then give proper time to understand how this function works and what all code lines are doing.

Prefer Polymorphism to If/Else or Switch/Case

According to Robert C. Martin “switch statements are probably appropriate in the parts of the system where adding new functions is more likely than adding new types” and he recommends “One Switch” rule : There may be no more than one switch statement for a given type of selection. The cases in that switch statement must create polymorphic objects that take the place of other such switch statements in the rest of the system.

Follow Standard Conventions

Follow standard conventions published by your company or team. This will eliminate the need of documentation and anyone who is new to project will find code very easy to understand.

Replace Magic Numbers with Named Constants

Replace all variables with Constants which values are not going to be changed through out the application.

Be Precise

When ever you have to make any decision in your code, make it very precisely. Like always think why have you give some specific scope to your variables functions, always think why you have declared any variable integer why float was not valid at this point. Always think of having transactions, locks, exception handling etc. Simply think about all parts of your code and think precisely.

Structure over Convention

Always prefer design decision with structure over convention. Its right that conventions makes your code readable but its design decision which makes code simpler and manageable.

Encapsulate Conditionals

Always try to encapsulate your conditions. Like if condition having many decision separated with and && sometimes becomes hard to understand and it also not very manageable it increases chances of duplication too. So always try to move these things in function and keep if condition small.

Avoid Negative Conditionals

Negative conditions are not easy to understand so always try to check for positive conditions.

Like if(!fileNotCreated()) is hard to understand than if(fileCreated()).

Functions Should Do One Thing

One function should do one thing only, if it is doing more than one thing then refactor it and extract few more functions out of this function.

Keep Configurable Data at High Levels

Keep all constants, read-only variables and other configurable data at one position and that is at top position.

Avoid Transitive Navigation

If module 1 is dependent on module 2 and module 2 is dependent on module 3 then 1 should not know about 3.

Replace Temp with Query

Avoid temporary variables with query like functions. Though calling function every time may decrease performance but it makes code more readable. Using temporary variables makes code hard to manage and understand.

Replace Error Code with Exception

Instead of returning any error code tries throwing exception back. Exceptions carry much detail with itself which make debugging and problem solving easy. Just returning error code may lead to confusion sometime.

Saturday, 14 November 2009

Custom Retry Logic in Message Only Solution Using Pipeline

Custom Retry Logic in Message Only Solution Using Pipeline

I struggled a lot while implementing retry interval and retry frequency while working on message only solution. So I thought to document it and post on my blog. It’s easy to configure retry interval and retry frequency using Biztalk administration console. But this configuration is not dynamic, I mean this is static configuration and can not be modified based on some logical decisions. So if we like to modify retry interval and frequency according to some logical decisions then we should use Dynamic send port and expression shape in orchestration to reset these values. What if we are not using orchestration and developing a message only solution based on publisher and subscriber model?

Then only place to do this is in send pipeline. So I wrote a pipeline component for this purpose.

Using send pipeline I configured three type of retry logic.

a) Deadline based retry

b) Limited number of retry

c) Unlimited retry

I divided my schema into three categories (as suggested by my architect “John Catlin”)

1) Public: - This is the schema which is exposed to outer world using receive ports, receive port will contain inbound mapping files which will convert it into internal schema and put on message bus.

2) Internal: - This is only used inside message bus and usually a copy of Public schema with some extra nodes and different namespace. These extra nodes will be helpful while implementing limited number retry. While calling some service or on off ramp (leaving message bus) will use an outbound mapping file and will get converted into abstracted schema.

3) Abstracted: - This schema belongs to others (other services which message bus will call)

Please see pipeline component code posted below.

[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]

[ComponentCategory(CategoryTypes.CATID_Encoder)]

[System.Runtime.InteropServices.Guid("9d0e4103-4cce-4536-83fa-4a5040674ad6")]

public class CustomRetry : Microsoft.BizTalk.Component.Interop.IComponent, IBaseComponent, IComponentUI, IPersistPropertyBag

{

#region IComponent Members

public IBaseMessage Execute(IPipelineContext pipelineContext, IBaseMessage pbaseInMsg)

{

int retryCount = 0;

//DeadLine

if (RetryParameter == "Deadline")

{

object objectFulfilmentDeadline = pbaseInMsg.Context.Read(RetryParameter, RetryParameterNamespace);

DateTime fulfilmentDeadline = DateTime.Parse(objectFulfilmentDeadline.ToString());

if (fulfilmentDeadline > DateTime.Now)

{

retryCount = 1;

}

else

{

retryCount = 0;

}

}

//RetryCount

if (RetryParameter == "RetryCount")

{

object objectFulfilmentDeadline = pbaseInMsg.Context.Read(RetryParameter, RetryParameterNamespace);

object objectFulfilmentDeadline = pbaseInMsg.Context.Read(RetryParameter, RetryParameterNamespace);

retryCount = int.Parse(objectFulfilmentDeadline.ToString());

pbaseInMsg.Context.Write("RetryCount", "http://schemas.microsoft.com/BizTalk/2003/system-properties", --retryCount);

}

//UnlimitedRetry

if (RetryParameter == "UnlimitedRetry")

{

retryCount = 1; //Anynumber larger than 0, will keep this retry going for ever.

}

pbaseInMsg.Context.Write("RetryCount", "http://schemas.microsoft.com/BizTalk/2003/system-properties", retryCount);

pbaseInMsg.Context.Write("RetryInterval", "http://schemas.microsoft.com/BizTalk/2003/system-properties", int.Parse(RetryParameterValue));

return pbaseInMsg;

}

#endregion

#region IBaseComponent Members

public string Description

{

get { return "Resets RetryCount, RetryInterval, Action, OutboundTransportLocation, OutboundTransportType"; }

}

public string Name

{

get { return "CustomRetryPipelineComponent"; }

}

public string Version

{

get { return "1.0.0.0"; }

}

#endregion

#region Extra Properties

private string _retryParameter;

public string RetryParameter

{

get { return _retryParameter; }

set { _retryParameter = value; }

}

private string _retryParameterValue;

public string RetryParameterValue

{

get { return _retryParameterValue; }

set { _retryParameterValue = value; }

}

private string _retryParameterNamespace;

public string RetryParameterNamespace

{

get { return _retryParameterNamespace; }

set { _retryParameterNamespace = value; }

}

#endregion

#region IComponentUI Members

public IntPtr Icon

{

get { return new System.IntPtr(); }

}

public System.Collections.IEnumerator Validate(object projectSystem)

{

return null;

}

#endregion

#region IPersistPropertyBag Members

public void GetClassID(out Guid classID)

{

classID = new Guid("655B591F-8994-4e52-8ECD-2D7E8E78B25C");

}

public void InitNew()

{

//TODO

}

public void Load(IPropertyBag propertyBag, int errorLog)

{

object valueRetryParameter = null;

object valueRetryParameterValue = null;

object valueRetryParameterNamespace = null;

try

{

propertyBag.Read("RetryParameter", out valueRetryParameter, errorLog);

_retryParameter = valueRetryParameter.ToString();

}

catch (Exception ex)

{

valueRetryParameter = "Deadline";

propertyBag.Write("RetryParameter", ref valueRetryParameter);

}

try

{

propertyBag.Read("RetryParameterValue", out valueRetryParameterValue, errorLog);

_retryParameterValue = valueRetryParameterValue.ToString();

}

catch (Exception ex)

{

valueRetryParameterValue = "0";

propertyBag.Write("RetryParameterValue", ref valueRetryParameterValue);

}

try

{

propertyBag.Read("RetryParameterNamespace", out valueRetryParameterNamespace, errorLog);

_retryParameterNamespace = valueRetryParameterNamespace.ToString();

}

catch (Exception ex)

{

valueRetryParameterNamespace = "http://My.Custom.Application.Contracts.Internal.PropertySchema.PropertySchema";

propertyBag.Write("RetryParameterNamespace", ref valueRetryParameterNamespace);

}

}

public void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)

{

object valRetryParameter = _retryParameter;

propertyBag.Write("RetryParameter", ref valRetryParameter);

object valRetryParameterValue = _retryParameterValue;

propertyBag.Write("RetryParameterValue", ref valRetryParameterValue);

object valRetryParameterNamespace = _retryParameterNamespace;

propertyBag.Write("RetryParameterNamespace", ref valRetryParameterNamespace);

}

#endregion

}

So this component exposes three properties, 1) RetryParameter 2) RetryParameterValue 3) RetryParameterNamespace. We can set these three properties while designing send pipeline and also while configuring pipeline in Biztalk Administration console.

For Unlimited retry we only need to set retry parameter count any number greater than 0.

And till our Deadline (which is suppose to be a datetime element) is not over, we will keep retryCount any number greater than 0 and will set it to 0 once Deadline is expired.

For RetryCount based retry we will pick RetryCount from schema and will write again to schema after reducing count by 1.

RetryParameterNamespace is used to get value of element from schema, I passed Namespace of Propertyschema which gets created when you promote any property.

Hope this post will save time of some other programmer if they like to implement retry thing using pipelines.

Saturday, 24 October 2009

Object Orientation Design Principles

How to write a good code?

What is a good code and how can we write a more object oriented code?
Sometimes I heard my team members complaining about the quality of code which I wrote, so I started a search for some instructions about “What is a good code?”
I went through “Agile Priniciples, Patterns and Practices in C# by Robert C. Martin”, “Refactoring by Martin Fowler” and “Head first Design Patterns from O’Reilly press” and found some useful tips.

So before going through those tips, let’s start with what is bad code?
The most common criterion which is responsible for bad design(in real life) is “TNTWIWHDI” means “That’s not the way I would have done it” so this should not be a criteria for declaring a code piece be bad code. But the main criteria should be

a) Rigidity: - It is hard to change because every change affects too many other parts of the system.
b) Fragility: - When you make a change, unexpected parts of the system break.
c) Immobility: - It is hard to reuse in another application because it cannot be disentangled from the current application.
d) Viscosity: - It’s hard to do right things but easy to do wrong things.

For avoiding above causes and writing good code experts have accumulated 10 OOAD (Object orientation analysis and design) principles.

1) Open Closed Principle (OCP): - Code should be open for extension and close for modification.
2) Liskov Substitution Principle (LSP): - Every function which operates upon a reference or a pointer to a base class should be able to operate upon derivatives of that base class without knowing it.
3) Dependency Inversion Principle (DIP): - High level modules should not depend upon low level modules. Both should depend upon abstraction. Abstraction should not depend upon details. Details should depend upon abstraction.
4) Interface segregation Principle (ISP): - Client should not be forced to depend upon interfaces that they do not use. Many client specific interface are better then one general purpose interface.
5) Release Reuse Equivalency Principle (REP): - The granule of reuse is the granule of release. Users will be unwilling to use the element if they need or forced to upgrade every time author changes it.
6) Common Closure Principle (CCP): - Classes those changes together belong together. The more packages that change in any given release, the greater the work to rebuild, test and deploy the release. So they should be grouped together.
7) Common Reuse Principle (CRP): - Classes that are not used together should not be grouped together. A dependency upon a package is a dependency upon everything in the package. When a package changes, and its release number is bumped , all clients of that package must verify that they work with the new package even if nothing they used within package actually changed.
8) Acyclic Dependencies Principle (ADP): - The dependencies between packages must not form cycles.
9) Stable Dependencies Principle (SDP): - Depend in the direction of stability. A package with lots of incoming dependencies is very stable because it requires a great deal of work to reconcile any changes with all the dependent packages.
10) Stable Abstraction Principle (SAP): - Stable packages should be abstract packages. The SAP I sjust a restatement of the DIP. It states that the packages that are most dependent upon (i.e. stable) should also be most abstract.

So I think that if we all try to follow these principles then our code quality will be mush better and easy to maintain.
And one more thing most of these experts were convinced that a code following all the principles described above is not possible but we should try to follow most of them until there is a suitable reason for not following any.
Details of all of these design principles are availabe on www.objectmentor.com and book published by Robert C. Martin but i would still like to describe all of these on my blog and will try to relate the with different design patterns.

WCF Callback

Implementing callback in WCF services.

This is a way of writing asynchronous code using wcf services. But do we know why to do this explicitly when adding a service reference also gives you a facility of generating asynchronous operations? This is because the asynchronous operations which we generate while adding service reference are not fake asynchronous calls, in fact they are synchronous call only, just let code not to wait for the response/ notification and it has its timeout period and will throw a timeout exception if response/notification will not be received before timeout. So for implementing real asynchronous operations we like to implement callbacks using callback contract.

Not all bindings supports callback mechanism. We got 2 binding with the help of which we can implement callback

  1. netTcpBinding
  2. wsDualHttpBinding

There are 2 important things which make any binding to support callback

  1. binding must allow session
  2. binding protocol should allow call from server to client.

BasicHttpBinding does not support session so callbacks are not allowed and other http binding do not support callback because http protocol does not allow notification server to each on the on same port.

Then how wsDualHttpBinding supports callback?

While using wsDualHttpBinding client used to pass a callback address to server and server can use this address to notify back to client.

However netTcpBinding protocol allows notification from server on same port.

So we will see how we can implement callback using these 2 bindings. For wsDualHttpBinding we will host our application in IIS and for netTcpBinding we will host our application in a console, as in IIS 6.0 we can not host netTcpBinding applications.

For these implementations I have used one service contract and used with both kind of bindings and have used “Add Service Reference” mechanism to add service references in client. I have used Http Url to expose metadata of netTcpBinding service so use http Url to add service reference.

Using wsDualHttpBinding :

Service Contract:

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

[ServiceContract(CallbackContract = typeof(ICallback), SessionMode=SessionMode.Required)]

public interface ISampleService

{

[OperationContract(IsOneWay = true)]

void GetData(string value);

// TODO: Add your service operations here

}

public interface ICallback

{

[OperationContract(IsOneWay = true)]

void Notify(string value);

}

Server Implementation:

public class SampleService : ISampleService

{

private string result;

public void GetData(string value)

{

result = string.Format("You entered: {0}", value);

Thread.Sleep(5000);

OperationContext.Current.GetCallbackChannel<ICallback>().Notify(value);

}

}

Server Configuration:

<system.serviceModel>

<services>

<service name="wsDualHttpBinding.SampleService" behaviorConfiguration="wsDualHttpBinding.SampleServiceBehavior">

<endpoint address="" binding="wsDualHttpBinding" contract="wsDualHttpBinding.ISampleService">

<identity>

<dns value="localhost"/>

identity>

endpoint>

<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>

service>

services>

<behaviors>

<serviceBehaviors>

<behavior name="wsDualHttpBinding.SampleServiceBehavior">

<serviceMetadata httpGetEnabled="true"/>

<serviceDebug includeExceptionDetailInFaults="false"/>

behavior>

serviceBehaviors>

behaviors>

system.serviceModel>

Client Implementation:

public partial class TestForm : Form

{

public TestForm()

{

InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)

{

InstanceContext instanceContext=new InstanceContext(new SampleServiceCallback());

SampleServiceProxy.SampleServiceClient sampleServiceClient = new SampleServiceClient(instanceContext);

sampleServiceClient.GetData("using wsDualHttpBinding,You have entered :"+textBox1.Text);

netTcpSampleServiceProxy.SampleServiceClient netTcpsampleServiceClient=new netTcpSampleServiceProxy.SampleServiceClient(instanceContext);

sampleServiceClient.GetData("using netTcpBinding, You have entered :"+textBox1.Text);

}

}

public class SampleServiceCallback : ISampleServiceCallback

{

#region ISampleServiceCallback Members

public void Notify(string value)

{

MessageBox.Show(value);

}

#endregion

}

Client Configuration:

<system.serviceModel>

<bindings>

<netTcpBinding>

<binding name="NetTcpBinding_ISampleService" 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>

<wsDualHttpBinding>

<binding name="WSDualHttpBinding_ISampleService" closeTimeout="00:01:00"

openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"

bypassProxyOnLocal="false" clientBaseAddress="http://localhost:8881/wsDualHttpBinding"

transactionFlow="false" hostNameComparisonMode="StrongWildcard"

maxBufferPoolSize="524288" maxReceivedMessageSize="65536"

messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">

<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

maxBytesPerRead="4096" maxNameTableCharCount="16384" />

<reliableSession ordered="true" inactivityTimeout="00:10:00" />

<security mode="Message">

<message clientCredentialType="Windows" negotiateServiceCredential="true"

algorithmSuite="Default" />

security>

binding>

wsDualHttpBinding>

bindings>

<client>

<endpoint address="http://localhost/wsDualHttpBinding/SampleService.svc" binding="wsDualHttpBinding"

bindingConfiguration="WSDualHttpBinding_ISampleService" contract="SampleServiceProxy.ISampleService"

name="WSDualHttpBinding_ISampleService">

<identity>

<dns value="localhost" />

identity>

endpoint>

<endpoint address="net.tcp://localhost:9000/SampleService" binding="netTcpBinding"

bindingConfiguration="NetTcpBinding_ISampleService" contract="netTcpSampleServiceProxy.ISampleService"

name="NetTcpBinding_ISampleService">

<identity>

<dns value="localhost" />

identity>

endpoint>

client>

system.serviceModel>

Using netTcpBinding :

Service Contract:

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

[ServiceContract(CallbackContract = typeof(ICallback), SessionMode=SessionMode.Required)]

public interface ISampleService

{

[OperationContract(IsOneWay = true)]

void GetData(string value);

// TODO: Add your service operations here

}

public interface ICallback

{

[OperationContract(IsOneWay = true)]

void Notify(string value);

}

Server Implementation:

public class SampleService : ISampleService

{

private string result;

public void GetData(string value)

{

result = string.Format("You entered: {0}", value);

Thread.Sleep(5000);

OperationContext.Current.GetCallbackChannel<ICallback>().Notify(value);

}

}

Server Configuration:

<system.serviceModel>

<services>

<service name="wsDualHttpBinding.SampleService" behaviorConfiguration="wsDualHttpBinding.SampleServiceBehavior">

<endpoint address="net.tcp://localhost:9000/SampleService" binding="netTcpBinding" contract="wsDualHttpBinding.ISampleService">

<identity>

<dns value="localhost"/>

identity>

endpoint>

service>

services>

<behaviors>

<serviceBehaviors>

<behavior name="wsDualHttpBinding.SampleServiceBehavior">

<serviceMetadata httpGetEnabled="true"/>

<serviceDebug includeExceptionDetailInFaults="false"/>

behavior>

serviceBehaviors>

behaviors>

system.serviceModel>

Server Hosting:

ServiceHost host = new ServiceHost(typeof(SampleService), new Uri("http://localhost:8090/SampleService"));

host.Open();

ServiceEndpointCollection endpoints = host.Description.Endpoints;

foreach (ServiceEndpoint endpoint in endpoints)

{

Console.WriteLine("The 'SampleService' service host is listening at {0}", endpoint.Address);

}

Console.WriteLine("Press to terminate the service.");

Console.ReadLine();

Client Implementation:

Same as wsDualHttpBinding client implementation (As I have used same client for both kind of bindings.)

Client Configuration:

Same as wsDualHttpBinding client implementation (As I have used same client for both kind of bindings.)