Slides and Demos from Connecting Smart Clients with WCF talk last night - Feb CTP lessons learned

I gave a talk on Connecting Smart Clients at the Microsoft Integration and Connected Systems User Group (MICSUG) last night. I discussed and demoed the basics of using Windows Communication Foundation (WCF) to connect applications, using the newly released Feb CTP.

You can get the slides and demos here:SlidesDemos

In jumping through the hoops yesterday to get my demos running on the Feb CTP, there were a number of changes that I had to get used to compared to previous builds.

The biggest is that if you run svcutil against a service that uses wsHttpBinding to generate a proxy, you get a proxy service contract that uses custom message contracts to wrap the parameters and return values from each operation contract. XXXRequest and XXXResponse classes are defined in the proxy file for each operation, along with an XXXBody class that actually contains the raw parameter/DataContract types.

If you program against theservice contract interface like so:

IAccountsManager mgrProxy = new AccountsManagerProxy();

You will have to create the XXXRequestmessage contract types to wrap all the parameters you pass into the methods, and unwrap any return values from the XXXResponse types. However, they also expose a public method on the proxy class directly that encapsulates these details so that you can deal directly with the underlying parameters and return values.

So instead of calling IAccountsManager.GetAllAccounts for example, you will have an easier time calling AccountsManagerProxy.GetAllAccounts.

This is true for wsHttpBinding because of the message level security involved in the default binding. If you use basicHttpBinding, or turn down the security on the wsHttpBinding, then you will get more straightforward service contract interface definitions on the client side proxy.

The resulting proxy and service contract look like the following:


[System.CodeDom.Compiler.GeneratedCodeAttribute(“System.ServiceModel”, “3.0.0.0”)]
[System.ServiceModel.ServiceContractAttribute()]


public

interface IAccountsManager
{

// CODEGEN: Generating message contract since message part accountNo requires protection.

[System.ServiceModel.OperationContractAttribute(Action=http://tempuri.org/IAccountsManager/CreateAccount”, ReplyAction=http://tempuri.org/IAccountsManager/CreateAccountResponse”)]

CreateAccountResponse CreateAccount(CreateAccountRequest request);

// CODEGEN: Generating message contract since message part GetAllAccountsResult requires protection.

[System.ServiceModel.OperationContractAttribute(Action=http://tempuri.org/IAccountsManager/GetAllAccounts”, ReplyAction=http://tempuri.org/IAccountsManager/GetAllAccountsResponse”)]

GetAllAccountsResponse GetAllAccounts(GetAllAccountsRequest request);

// CODEGEN: Generating message contract since message part fromAccountNo requires protection.

[System.ServiceModel.OperationContractAttribute(Action=http://tempuri.org/IAccountsManager/Transfer”, ReplyAction=http://tempuri.org/IAccountsManager/TransferResponse”)]

TransferResponse Transfer(TransferRequest request);

}

[System.CodeDom.Compiler.GeneratedCodeAttribute(“System.ServiceModel”, “3.0.0.0”)]


public

interface IAccountsManagerChannel : IAccountsManager, System.ServiceModel.IClientChannel
{

}

[System.CodeDom.Compiler.GeneratedCodeAttribute(“System.ServiceModel”, “3.0.0.0”)]


public

partialclass AccountsManagerProxy : System.ServiceModel.ClientBase, IAccountsManager
{

public AccountsManagerProxy()

{

}

public AccountsManagerProxy(string endpointConfigurationName) :

base(endpointConfigurationName)

{

}

public AccountsManagerProxy(string endpointConfigurationName, string remoteAddress) :

base(endpointConfigurationName, remoteAddress)

{

}

public AccountsManagerProxy(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :

base(endpointConfigurationName, remoteAddress)

{

}

public AccountsManagerProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :

base(binding, remoteAddress)

{

}

CreateAccountResponse IAccountsManager.CreateAccount(CreateAccountRequest request)

{

returnbase.InnerProxy.CreateAccount(request);

}

publicvoid CreateAccount(int accountNo, string name, decimal initialBalance)

{

CreateAccountRequest inValue = new CreateAccountRequest();

inValue.Body = new CreateAccountRequestBody();

inValue.Body.accountNo = accountNo;

inValue.Body.name = name;

inValue.Body.initialBalance = initialBalance;

CreateAccountResponse retVal = ((IAccountsManager)(this)).CreateAccount(inValue);

}

GetAllAccountsResponse IAccountsManager.GetAllAccounts(GetAllAccountsRequest request)

{

returnbase.InnerProxy.GetAllAccounts(request);

}

public BankingBusinessLayer.Account[] GetAllAccounts()

{

GetAllAccountsRequest inValue = new GetAllAccountsRequest();

inValue.Body = new GetAllAccountsRequestBody();

GetAllAccountsResponse retVal = ((IAccountsManager)(this)).GetAllAccounts(inValue);

return retVal.Body.GetAllAccountsResult;

}

TransferResponse IAccountsManager.Transfer(TransferRequest request)

{

returnbase.InnerProxy.Transfer(request);

}

publicvoid Transfer(int fromAccountNo, int toAccountNo, decimal amount)

{

TransferRequest inValue = new TransferRequest();

inValue.Body = new TransferRequestBody();

inValue.Body.fromAccountNo = fromAccountNo;

inValue.Body.toAccountNo = toAccountNo;

inValue.Body.amount = amount;

TransferResponse retVal = ((IAccountsManager)(this)).Transfer(inValue);

}

}