Developing Web Services: Part 2

Hi Folks!

Introduction

I hope you guys enjoyed Developing Web Services: Part 1, in this blog we going to develop a consumer for the web service we made in Part 1. Remember in Part 1 we created two types of web methods, one accepted a simple .Net Type and the other accepts a composite or custom .Net Object type. I mentioned that simple types can be used directly by HTTP-Get and HTTP-Post and that composite web methods need to use SOAP only and therefore any consumer application calling a composite web method will need a proxy class, and this is exactly what we going to do today!

This is my own definition:
A composite web method is any web method that takes input parameters that are not Simple .Net Types

Return values of the web method will not affect the protocol you use to call them, since they always return a serialized objected, which is in XML format. So the only condition is that return values of web methods are all serializable.

One more thing, if you can keep a web methods parameters as simple types, the better! Keep that in mind. So on many occasions when developing a web service you don’t need to write a custom class for the input parameters, unless absolutely necessary. I always write custom response objects, since in them I imbed my error messages and other information that a consumer can use for decision making and exception handling.

For the BizTalk geeks, this is especially true for soap send ports to call a web service, if they use simple types, then there is no need to create a BizTalk proxy class.

I include to screen shots below of a BizTalk SOAP send port, consuming a  composite web method without the use of a Orchestration.

Composite Call:

image

In part 3 of this blog article, I will discuss consuming web services from BizTalk.

Ok enough chit chat, lets get moving.

Overview

If you remember from part 1, this is the steps we going to take to develop a consumer application for the Audit Web Service.

  1. UI (Display the results of the web service response.
  2. Generate web proxy reference
  3. Call the web service
  4. Capture the response

We going to write a simple windows based application that calls the web service and displays the result. We will call the AuditComplex web method.

Prerequisites

I assume the web method we developed in part 1 is deployed to IIS. If you did not deploy it as a web service to IIS, follow these steps.

  1. Ensure IIS is installed on your machine
  2. Ensure iis_regaspnet has been run, so that IIS uses the ASP.Net engine
  3. image
  4. image
  5. image
  6. Open the Solution file
  7. Right click the project Romiko.Audit.WebServices and select properties
  8. Click the web link.
  9. image
  10. Once you are in here you can then click use IIS Web server
  11. Click the button ‘Create Virtual Directory’
  12. image
  13. Close the project properties
  14. Check in IIS if a virtual directory is created and check it is associated with Asp.NET 2.0
  15. image
  16. image
  17. Test the web service by browsing to it.
  18. image

Now when we build the web service it will work from IIS. The URL above is the URL the consuming application will use.

Application Pools for Servers (Optional)

Before we get moving, you remember in my last article in Part 1, I chatted about Application Pools, we this is where you can use them, I like my web services to run under a service account which is restricted, then I never have user name and passwords in the web.config (I hate that!). What you do is create a Application Pool and set it to run under the service account, give the service account access to the SQL database etc. Lets do this now!

Warning: This is for Windows Servers! Due to IIS on servers supporting application pools

  1. Create IIS app pool for our web service
  2. image
  3. Give the application pool a name
  4. image
  5. Go to the properties of the application pool and click identity
  6. image
  7. Notice that the pool will run under network service, this is where you can choose a Domain Service Account.
  8. I created one in my test domain
  9. image
  10. All I do is use this for the identity of the application pool
  11. image
  12. Another nice with application pools is recycling the memory used, since the web service will be isolated from other application processes. So you can recycle it to release memory.
  13. In this case, at 4 am I recycle the memory
  14. image
  15. Now we give the service account access to the database and WSS_WPG group
  16. image
  17. And in SQL
  18. image
  19. image
  20. The last part is then to point the virtual directory used by the web service to the new application pool!
  21. image

This is the nice way to do it. What you can do as well is give the WSS_WPG group access to

  1. C:\windows\Temp
  2. image
  3. Also to to the framework temp folder, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files
  4. image
  5. If you did something wrong, like type the incorrect password for the identity, then when you browse the web service, you will get this error:
  6. image
  7. So ensure all the steps are correct and ensure the application pool is started and the account is in the WSS_WOG group.

This security model solves all problems with permissions running ASP.NET and I hope you use it in production! NO USER NAMES AND PASSWORDS in the web.config

Ok we diverted a bit here, lets get moving, but at least we now have a clean web.config, this makes deployments much easier.

Creating the solution for the consumer

First thing we going to do is create the client project. I have decided to go for a typical Win32 application.

image

First, we going to design the interface, based on the inputs.

image

The next step is to add a web reference to the project. Visual Studio will then generate the PROXY class for you, which you can then interface with.

image

You can then choose a web service. I chose the one running on my local machine.

image

Give the Web reference a name. Mine is AuditWS. Then click Add Reference.

Click show all files.

image

Then you can browse the files that the reference created, we will not alter them, however, keep in mind if you ever deploy a new version of the web service, then the proxy class may need to be updated, which is easy, just right click the reference and click update.

Reference.cs contains the proxy class.

image

Notice that the proxy class has the default URL, in reality we will store the URL is the app.config for this application. Also, you probably have different URL’s for different environments.

Now we need to write two methods, the one method calls the simple web method and the other will call the composite web method, both web methods do the exact same thing, the only difference is the simple supports http/soap posts where is the composite supports only soap.

We will keep this consumer simple with no BOL or DAL layers, in this case the DAL layer would have been the web service reference, up to if you need this for complex consumer apps.

So the first thing is we add the following directive.

using AuditConsumer.AuditWS;

Then we can access the request and response objects.

Note: I added a ForexPurchase class to the project, so that the consuming application can emulate serializing a Forex object and auditing the object in the database for us.

using System;
using System.Configuration;
using System.Windows.Forms;
using AuditConsumer.AuditWS;

namespace AuditConsumer
{
    public partial class Form1 : Form
    {
        private string url;
        AuditWebService ws = new AuditWebService();

        public Form1()
        {
            InitializeComponent();

            switch (ConfigurationManager.AppSettings["Environment"])
            {
                case "Url_Development":
                    url = ConfigurationManager.AppSettings["Url_Development"];
                    break;
                case "Url_Test":
                    url = ConfigurationManager.AppSettings["Url_Test"];
                    break;
                case "Url_PreProduction":
                    url = ConfigurationManager.AppSettings["Url_PreProduction"];
                    break;
                case "Url_Production":
                    url = ConfigurationManager.AppSettings["Url_Production"];
                    break;
            }

            ws.Url = url;
        }

        /// <summary>
        ///
        /// You can test this using a web browser instead of texecuting this code, since it is all simple data types!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSimple_Click(object sender, EventArgs e)
        {
            string resp =  ws.AuditSimple(Guid.NewGuid().ToString(), txtSource.Text, txtStage.Text, txtStatus.Text, txtMessage.Text, SimulateBusinessTransaction());
            txtResponse.Text = resp + Environment.NewLine + SimulateBusinessTransaction();
        }

        /// <summary>
        /// This can not be executed by a web browser, since it had a composite data type:  AuditRequest
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnComposite_Click(object sender, EventArgs e)
        {
            AuditRequest r = BuildRequest();
            AuditResponse resp = ws.AuditComplex(r);
            txtResponse.Text = resp.Message + Environment.NewLine + resp.Status + Environment.NewLine + r.SerializedObject;
        }

        private AuditRequest BuildRequest()
        {
            AuditRequest r = new AuditRequest();
            r.Id = Guid.NewGuid();
            r.Source = txtSource.Text;
            r.Stage = txtStage.Text;
            r.Status = txtStatus.Text;
            r.Message = txtMessage.Text;
            r.SerializedObject = SimulateBusinessTransaction();
            return r;
        }

        /// <summary>
        /// This would be some BOL layer or even another web service call!
        /// </summary>
        private string SimulateBusinessTransaction()
        {
            ForexPurchase f = new ForexPurchase();
            f.Amount = 200;
            f.Authorised = true;
            f.FromCurreny = ForexPurchase.Currency.EUR;
            f.ToCurrency = ForexPurchase.Currency.ZAR;
            return f.Serialize().InnerXml;
        }

    }
}

Lets run it and see what happens! Set the project as the startup project and run in debug mode:

image

I get the following response when using simple:

image

I get the following response when using composite:

 image

This is a great test, we can see the error handling is being returned in the response object, now let us resolve the Database Access problems and then run it again. I think the problem is the application pool, it is using the incorrect identity, so i will fix that quickly.

image

Now, we run it again.

Click Simple:

image

Click complex:

image

Well, that wraps up consuming applications. In order for it to support connecting to other URL’s, add the following to the app.config:

<appSettings>
    <add key="Environment" value="Url_Development"/>
    <add key="Url_Development"  value="http://localhost/Romiko.Audit.WebServices/AuditWebService.asmx"/>
    <add key="Url_Test" value="http://localhost/Romiko.Audit.WebServices/AuditWebService.asmx"/>
    <add key="Url_PreProduction" value="http://localhost/Romiko.Audit.WebServices/AuditWebService.asmx"/>
    <add key="Url_Production" value="http://localhost/Romiko.Audit.WebServices/AuditWebService.asmx"/>
</appSettings>

Download Source Code

 

Conclusion

I hope you enjoyed this article. In the next article I will discuss consuming web services from a Microsoft BizTalk Soap Send Port.

Advertisements
Uncategorized

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s