Creating a Banking Service and Client with Reliable Sessions


In this first exercise, we will showcase how to create code that utilizes Reliable Sessions.

Creating the Banking Service

  1. Create a new WinFX Service project in C:\WCFHandsOn\Chapter5\PartI\Before\.

    Specify a name of ConsumerBankingService as the name of the project, and ReliableSessions as the name of the solution.

  2. Within Visual Studio, add a new class and name it ConsumerBankingCore.cs.

  3. Add a reference to System.ServiceModel.

  4. Add using System.ServiceModel; to the top of the Program.cs file:

    using System; using System.Collections.Generic; using System.Text; using System.ServiceModel;

  5. Next, create the service interface and service implementation. Specify that this Service Contract will use reliable sessions by specifying (Session=true):

    namespace ConsumerBankingService {     [ServiceContract(Session=true)]     public interface IConsumerBankingCore     {         [OperationContract]         bool Deposit(int accountNumber, decimal amount);         [OperationContract]         bool Withdraw(int accountNumber, decimal amount);         [OperationContract]         decimal GetBalance(int accountNumber);     }     // This will share the information per a single session     // [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]     // This will share the information in a single session, across multiple     // clients     // [ServiceBehavior(InstanceContextMode = InstanceContextMode.Shareable)]     [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]     class ConsumerBankingCore : IConsumerBankingCore     {         private decimal _balance = default(decimal);         public bool Deposit(int accountNumber, decimal amount)         {             _balance = _balance + amount;             Console.WriteLine("Depositing {0} into Account {1}", amount, accountNumber);             Console.WriteLine("Balance:" + _balance.ToString());             return true; }         public bool Withdraw(int accountNumber, decimal amount)         {            _balance = _balance - amount;            Console.WriteLine("Withdrawing {0} from Account {1}", amount accountNumber);            Console.WriteLine("Balance:" +_balance.ToString());            return true; }         public decimal GetBalance(int accountNumber)         { return _balance; }     } }

The next step is to create the host for the service.

  1. Open Program. cs.

  2. Add a reference to System.ServiceModel.

  3. Add a reference to System.Configuration:

  4. Modify Program.cs to use the ConsumerBankingService namespace and contain the following code:

    [View full width]

    using System; using System.Collections.Generic; using System.Text; using System.ServiceModel; using System.Configuration; namespace ConsumerBankingService { class Program { static void Main(string[] args) { // Get base address from app settings in configuration Uri baseAddressCore = new Uri(ConfigurationManager.AppSettings["baseAddressCore"]); // Instantiate new ServiceHost ServiceHost CoreServiceHost = new ServiceHost(typeof (ConsumerBankingCore), baseAddressCore); CoreServiceHost.Open(); Console.WriteLine("Consumer Banking Service is Online."); Console.WriteLine("-----------------------------------"); Console.WriteLine("Press any key to terminate service."); Console.ReadKey(); CoreServiceHost.Close(); } } }

    The next step is to create the application configuration file for the banking service.

  5. Within Visual Studio, add a new application configuration file named App.Config.

  6. Using Solution Explorer, open the App.Config file and populate it to resemble the following code listing:

    <xml version="1.0"; encoding="utf-8"?> <configuration>     <appSettings>     <!-- use appSetting to configure base address provided by host -->     <add key="baseAddressCore" value="http://localhost:8080/ConsumerBankingService" /> </appSettings> <system.serviceModel>   <services>     <service         type="ConsumerBankingService.ConsumerBankingCore";     <!-- use base address provided by host -->     <endpoint address=""                binding="wsHttpBinding"                contract="ConsumerBankingService.IConsumerBankingCore" />   </service>   <service     type="ConsumerBankingService.ConsumerBankingBillPayment"   >     <!-- use base address provided by host -->     <endpoint address=""               binding="wsHttpBinding"               contract="ConsumerBankingService.IConsumerBankingBillPayment" />       </service>     </services> </system.serviceModel> </configuration>

Creating the Client for the Service

Having created the service, you will now create a client to interact with it.

  1. In the open solution, add a new project.

  2. Create a new Windows Forms application named ATMClient in C:\WCFHandsOn\Chapter5\Before\PartI\.

  3. Create the proxy for the banking service.

  4. Right-click on the ConsumerBankingService project, click Debug, and select Start New Instance.

    This will start the ConsumerBankingService, making it available for us to query it for metadata with the svcutil utility.

  5. Enter the following at the command prompt:

    [View full width]

    "C:\Program Files\Microsoft SDKs\Windows\v1.0\Bin\SvcUtil.exe" http://localhost:8080 /ConsumerBankingService

  6. Stop the Debugger.

  7. Open a Visual Studio command prompt and navigate to the directory C:\WCFHandsOn\Chapter5\Before\PartI\.

  8. Using Solution Explorer, add ConsumerBankingCoreProxy.cs to the ATMClient project.

  9. Using Solution Explorer, add output.config to the ATMClient project.

  10. Rename output.config to App.config.

  11. Open the App.Config file.

  12. Modify the endpoint element to include the attribute name with a value of CoreBanking:

    [View full width]

    <?xml version="1.0" encoding="utf-8"?> <configuration> <system.serviceModel> <client> <endpoint name="CoreBanking" address="http://localhost:8080/ ConsumerBankingService" bindingConfiguration="WSHttpBinding_IConsumerBankingCore" binding="customBinding" contract="IConsumerBankingCore" /> </client> <bindings> <customBinding> <binding name="Secure conversation bootstrap binding 5d58043f-7615-48c7-80e6-95668c8117f3" <security defaultAlgorithmSuite="Default" authenticationMode="SspiNegotiated" defaultProtectionLevel="EncryptAndSign" requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true" keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncrypt" protectTokens="false" requireSecurityContextCancellation="true" securityVersion="WSSecurityXXX2005" requireSignatureConfirmation="false"> <localClientSettings cacheCookies="true" detectReplays="true" replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="10675199.02:48:05.4775807" replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00" sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true" timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="90" /> <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00" maxStatefulNegotiations="1024" replayCacheSize="900000" MaxClockSkew="00:05:00" negotiationTimeout="00:02:00" replayWindow="00:05:00" inactivityTimeout="01:00:00" sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true" maxConcurrentSessions="1000" timestampValidityDuration="00:05:00" /> </security> <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16" messageVersion="Default"writeEncoding="utf-8" /> </binding> <binding name="WSHttpBinding_IConsumerBankingCore"> <security defaultAlgorithmSuite="Default" authenticationMode="SecureConversation" bootstrapBindingConfiguration="Secure conversation bootstrap binding 5d58043f-7615-48c7-80e6-95668c8117f3" bootstrapBindingSectionName="customBinding" defaultProtectionLevel="EncryptAndSign" requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true" keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncrypt" protectTokens="false" requireSecurityContextCancellation="true" securityVersion="WSSecurityXXX2005" requireSignatureConfirmation="false" <localClientSettings cacheCookies="true" detectReplays="true" replayCacheSize="900000"maxClockSkew="00:05:00" maxCookieCachingTime="10675199.02:48:05.4775807" replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00" sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true" timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="90" /> <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00" maxStatefulNegotiations="1024" replayCacheSize="900000" maxClockSkew="00:05:00" negotiationTimeout="00:02:00" replayWindow="00:05:00" inactivityTimeout="01:00:00" sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true" maxConcurrentSessions="1000" timestampValidityDuration="00:05:00"/> </security> <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16" messageVersion="Default" writeEncoding="utf-8" /> <httpTransport manualAddressing="false" maxBufferPoolSize="524288" maxMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" mapAddressingHeadersToHttpHeaders="false" proxyAuthenticationScheme="Anonymous" realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false" useDefaultWebProxy="true" /> </binding> <binding name="Secure conversation bootstrap binding d58973a4-c474-42f2-8fb8-f2a64bc07c96"> <security defaultAlgorithmSuite="Default" authenticationMode="SspiNegotiated" defaultProtectionLevel="EncryptAndSign" requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true" keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncrypt" protectTokens="false" requireSecurityContextCancellation="true" securityVersion="WSSecurityXXX2005" requireSignatureConfirmation="false"> <localClientSettings cacheCookies="true" detectReplays="true" replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="10675199.02:48:05.4775807" replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00" sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true" timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="90" /> <localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00" maxStatefulNegotiations="1024" replayCacheSize="900000" maxClockSkew="00 :05:00" negotiationTimeout="00:02:00" replayWindow="00:05:00" inactivityTimeout="01:00:00" sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true" maxConcurrentSessions="1000" timestampValidityDuration="00:05:00" /> </security> <textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16" messageVersion="Default" writeEncoding="utf-8" /> </binding> </customBinding> </bindings> </system.serviceModel> </configuration>

  13. Next, open the code view for Form1.cs.

  14. Add the line ConsumerBankingCoreProxy proxy = new ConsumerBankingCoreProxy("CoreBanking"); to the Form1 class:

    public partial class Form1 : Form     {        ConsumerBankingCoreProxy proxy = new ConsumerBankingCoreProxy("CoreBanking");        public Form1()        {            InitializeComponent();        }

    Next, design the Windows Form that will comprise the user interface.

  15. Double-click on Form1.cs in Solution Explorer to modify the form in the designer.

  16. Add a label named lblBankAccountNumber.

  17. Set the text property for this label to "Bank Account Number".

  18. Add a label named lblAmount.

  19. Set the text property for this label to "Amount".

  20. Add a textbox named tbAccountNumber.

  21. Set the text property for this textbox to "12345".

  22. Add a textbox named tbAmount.

  23. Set the text property for this textbox to "25.00".

  24. Add a label named lblBankBalance.

  25. Set the text property for this label to "Current Bank Balance".

  26. Add a label named lblBalance.

  27. Set the text property for this label to "0".

  28. Add a button named "btnDeposit".

  29. Set the text property for this button to "Deposit".

  30. Add a button named "btnWithdraw".

  31. Set the text property for this button to "Withdrawal".

  32. Add a button named "btnSonWithdraw".

  33. Set the text property for this button to "Son Withdrawal".

  34. Arrange these controls to resemble what's shown in Figure 5.1.

    Figure 5.1. The designed form.

    Now add the code to execute a deposit.

  35. In the Windows Form designer double-click on the btnDeposit control.

  36. This will open the code view. Add the following code to the btnDeposit_Click event:

    [View full width]

    private void btnDeposit_Click(object sender, EventArgs e) { bool success = proxy.Deposit (Convert.ToInt32(tbAccountNumber.Text), Convert .ToDecimal(tbAmount.Text)); decimal balance = proxy.GetBalance(Convert.ToInt32(tbAccountNumber.Text)); if (success) { lblBalance.Text = balance.ToString(); } else { System.Windows.Forms.MessageBox.Show("Unable to make deposit"); } }

  37. In the Windows Form designer, double-click on the btnWithdraw control.

  38. This will open the code view. Add the following code to the btnWithdraw_Click event:

    [View full width]

    private void btnWithdraw_Click(object sender, EventArgs e) { bool success = proxy.Withdraw(Convert.ToInt32(tbAccountNumber.Text), Convert .ToDecimal(tbAmount.Text)); decimal balance = proxy.GetBalance(Convert.ToInt32(tbAccountNumber.Text)); if (success) { lblBalance.Text = balance.ToString(); } else { System.Windows.Forms.MessageBox.Show("Unable to make withdrawal"); } }

    You will now add the code that uses a second proxy that uses that same session:

  39. In the Windows Form designer, double-click on the btnSonWithdraw control.

    This will open the code view.

  40. Add the following code to the btnSonWithdraw_Click event:

    [View full width]

    private void btnSonWithdraw_Click(object sender, EventArgs e) { using (ConsumerBankingCoreProxy proxySon = new ConsumerBankingCoreProxy("CoreBanking")) { System.ServiceModel.EndpointAddress proxyAddress = proxy.InnerChannel .ResolveInstance(); proxySon.Endpoint.Address = proxyAddress; bool success = proxySon.Withdraw(Convert.ToInt32(tbAccountNumber.Text),25); decimal balance = proxySon.GetBalance(Convert.ToInt32(tbAccountNumber.Text)); if (success) { lblBalance.Text = balance.ToString(); } else { System.Windows.Forms.MessageBox.Show("Unable to make withdrawal"); } } }

You are now ready to test the application.

Test #1No Sessions EnabledPer Call Instancing

In this first test, we will run the client and service without the benefit of sessions.

  1. Run the Service.

  2. Run the Client.

  3. Click the Deposit and Withdraw buttons.

You will notice that there is no information being shared between calls. Each call starts with no shared state of the prior actions. There is no session. The expected outcome of this test is shown in Figure 5.2.

Figure 5.2. Screenshot of the resulting test.


Test #2Sessions EnabledPerSession Instancing

In this next test, we will enable sessions. This will be done by modifying the InstanceContextMode of the Service Behavior.

  1. Stop the client and service.

  2. Modify the service contract, commenting out the ServiceBehavior that specifies the InstanceContextMode of PerCall and uncommenting out the code for a ServiceBehavior of PerSession:

    // This will share the information per a single session [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] // This will share the information in a single session, across multiple // clients // [ServiceBehavior(InstanceContextMode = InstanceContextMode.Shareable)] // [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

  3. Run the Service.

  4. Run the Client.

  5. Click the Deposit and Withdraw buttons.

Note that when you perform deposits and withdrawals now, there is obvious knowledge of prior states.

The expected outcome of this test is shown in Figure 5.3.

Figure 5.3. Screenshot of the resulting test.


Test #3Sessions EnabledSharable Instancing

There will be scenarios where you wish to share the same session among multiple clients. As in the last test, this can be done by modifying the InstanceContextMode.

  1. Stop the client and service.

  2. Modify the service contract, commenting out the ServiceBehavior that specifies the InstanceContextMode. of PerSession and uncommenting out the code for a ServiceBehavior of Sharable:

    // This will share the information per a single session // [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] // This will share the information in a single session, across multiple // clients [ServiceBehavior(InstanceContextMode = InstanceContextMode.Shareable)] // [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

In this test, you will see that you can have multiple proxies that can share the same session:

  1. Run the Service.

  2. Run the Client.

  3. Click the Deposit and Withdraw buttons.

  4. Click the Son Withdraw button.

The code for the click event of the Son Withdraw button resolves the address of the first proxy. It creates an EndpointAddress object and assigns that to the second proxy:

[View full width]

System.ServiceModel.EndpointAddress proxyAddress = proxy.InnerChannel .ResolveInstance(); proxySon.Endpoint.Address = proxyAddress;


That proxy, SonProxy, can now share the same session as the main proxy. Both proxies can interact with the shared state information.




Presenting Microsoft Communication Foundation. Hands-on.
Microsoft Windows Communication Foundation: Hands-on
ISBN: 0672328771
EAN: 2147483647
Year: 2006
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net