Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Invoking a Web Service Without Web Reference

4.53/5 (35 votes)
27 Jun 20068 min read 1   3.7K  
How to support loosely coupled integration by invoking Web Services dynamically, without setting a Web Reference.

Introduction

This article describes how to call a .NET Web Service without having to use the Visual Studio .NET 2005 IDE to set a Web Reference to the Web service.

Background

This is a fair enough requirement that you might come across in multiple scenarios. Here are some situations, that come to my mind, where this approach might come handy:

  • Loosely coupled integration in Application Service Provider Model - Application Service Provider Model is a model where a single web application can support users from multiple clients. In this scenario, there is often a need to allow the application to call different web services depending on the client, and it may not always be a good idea to do a web reference to each and every one of those web services, specially when they have exactly the same specification.
  • Dynamically invoking different Web Services during runtime - There are two or more completely different web services with the same WSDL specification but different implementation inside functions and business logic. If the application needs to decide which web service to invoke depending on the flow / business logic, during runtime, then it may be a good idea to take up this approach.

Basically, I wrote this article because I found that some of the methods that I found in CodeProject and the Web were too simple and not accurately correct, while others were a little more complicated and elegant, which were highly useful for more complex scenarios, and more often than not they were either of the two scenarios I describe in the bulleted list above or variations of them thereof that might motivate developers to call a web service dynamically without manually setting a web reference to it.

The Example

For the sake of simplicity, let's keep this example very simple. We will avoid all database interaction code and try to focus on solving our problem here - which is to call a web service without setting a web reference in the Visual Studio .NET 2005 IDE. So, let's assume that a hypothetical application called "WelcomeUser" wants to follow the Application Service Provider Model, and wants to allow users of two different companies, "Foo" and "XFoo", to sign on to the application.

However, the real complication here is that the WelcomeUser web application wants to let the companies Foo and XFoo decide the welcome message they want to display to their users, by invoking a web service which both Foo and XFoo host and maintain independently in their infrastructure environment. In other words, the development team of the WelcomeUser Web application does not want to be responsible for the maintenance, deployment, and implementation of web services for each client, and yet wants to support loosely coupled integration with these web services.

Even though the whole idea of both these companies writing web services just to display a welcome message sounds overly simplistic and stupid, let us just assume that the welcome message is driven by complex logic which is based on different databases which are hosted in the environments of Foo and XFoo.

Design the WSDL, Distribute to Clients, They Implement Their Own Web Services

Since the WelcomeUser application needs to call completely different web services depending on which company the current user belongs to, the WelcomeUser application development team needs to decide the WSDL specifications that both Foo and XFoo need to follow when they are writing their web services. Even though this analogy is not fully correct, for now, it would be safe to say that this WSDL that the development team of the WelcomeUser application decides will act as a contract for this loosely coupled integration, something like an Interface in the object oriented world, if you will.

In order to create this WSDL, contact the programmers of the WelcomeUser application, decide to write a Web Service which they will call "WelcomeMessageStub", which will have a welcome method called "GetWelcomeMessage()". The following code illustrates this:

C#
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WelcomeMessageStub : System.Web.Services.WebService
{
    public WelcomeMessageStub () { }
    [WebMethod]
    public string GetWelcomeMessage() {
        return "The Welcome Message That You Need To Return";
    }
}

Once this is done, we use the WSDL specifications of this web service by visiting "[URL Of the Web Service]/WelcomeMessageStub.asmx?wsdl", and publish the WSDL specifications to all clients including Foo and xFoo.

I should point out here that there are multiple tools that allow you to generate WSDL directly without having to code a stub Web service. So, coding the stub Web Service to get a WSDL is just a quick and dirty way of doing this. I do this here because I want to keep the focus on the primary problem which is to invoke multiple web services without setting the web reference to these web services.

Now, let us assume that developers at Foo write the following implementation of our WSDL specification and write a web service WelcomeMessageFoo:

C#
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WelcomeMessageFoo : System.Web.Services.WebService
{
    public WelcomeMessageFoo () { }
    [WebMethod]
    public string GetWelcomeMessage() {
        return "Welcome to Foo!";
    }
}

xFoo, however, takes the WSDL and writes a completely different implementation of the Web Service:

C#
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WelcomeMessageXFoo : System.Web.Services.WebService
{
    public WelcomeMessageXFoo () { }
    [WebMethod]
    public string GetWelcomeMessage() {
        return "Welcome to XFoo User!";
    }
}

Assuming that both the different web services are hosted at completely different URLs, the WelcomeUser Web application which follows the Application Service Provider Model needs to be able to invoke different web services from different URLs depending on the user who is signing in. In other words, if the user signing in belongs to company Foo, the application needs to reach out to the URL of the WelcomeMessageFoo service and call its GetWelcomeMessage, where else if the user belongs to company XFoo, the applications needs to reach out to the WelcomeMessageXFoo Web service and call its GetWelcomeMessage method.

Even though this example sounds really simplistic, this approach becomes important because there may be multiple clients in the future and it may not be always possible to set a web reference to thousands of clients separately. In fact, setting the Web Reference for hundreds of different clients separately may not be such a good idea. The sections that follow in the article explain.

Writing the Application Service Provider Application, WelcomeUser

Before we get started, we need to understand some basics of how web services work and the basics of what happens when you set a web reference using the Visual Studio .NET 2005 IDE. When you set a web reference to a Web Service using the Visual Studio .NET 2005 IDE, the IDE actually creates proxy classes for you, based on the WSDL specifications, which represent the Web Service classes on the remote server.

If you've ever wondered how you get Intellisense with Web services, and why the Intellisense is not accurate till you update your web reference each time you change your web service, it is because these proxy classes are being used by Visual Studio to offer you Intellisense. In fact, when you invoke a Web method through a client, all you are doing is invoking a method in one of these proxy classes which are just local to your project. These classes, in turn, are capable of invoking the remote methods on the Web Service URL.

So, every time the web service is updated, these proxy classes need to be regenerated by clicking Update Web Reference. However, the proxy classes do not always have to be generated from the IDE, .NET also gives us the WSDL.exe utility to manually generate these proxy classes and include them in your project.

So after this long story of what Visual Studio .NET does and the fundamentals of how Web Services work, let's get back to what we were doing, which is to start writing our WelcomeUser Web application. The first thing that we will need to do is to create a proxy class for our WelcomeMessageStub web service. We will then use this proxy class to invoke web services that Foo and xFoo have written independently at completely different URLs.

To create the proxy class for the WelcomeMessageStub Web Service, let's use the WSDL.exe utility and fire the following command at the command prompt:

Image 1

Notice that WSDL.exe creates a proxy class, WelcomeMessageStub.cs, for me based on the WSDL specifications. With this done, lets quickly create a new website for the WelcomeUser Web application and place the code in the App_Code folder of this site.

Now that this is done, it might be a good idea to dissect the generated proxy class code. To keep this article focused on the problem, we start off from the first place, and let's just look at the relevant parts of the generated proxy class. Illustrated below is the code generated for the default constructor of the generated proxy class:

C#
public WelcomeMessageStub<CODE>()</CODE> {
    this.Url = "http://localhost/WelcomeMessageStub/WelcomeMessageStub.asmx";
}

It's worth noting here, that the default constructor of this class contains the URL of the asmx file where the web service is hosted. However, the URL property of this class is both public and read/write, which means that it can be modified during runtime.

The code snippet below illustrates how the web services of the clients Foo and xFoo can be invoked dynamically during runtime, using the proxy class:

C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        // We Can use Database or other Mechanisms to select which company
        // the user belongs to. Once this
        // is done we can have a small IF construct
        // to invoke the right web service from the right URL.
        // Without going into those complications the below code displays how we 
        // can call two different Web Services using the same proxy Class.
        WelcomeMessageStub welcomeMessageStub = new WelcomeMessageStub();

        // IF the User Belongs to Foo - Lets Hit Foo's Web Service URL to Invoke
        // the right Web Method on the fly.
        welcomeMessageStub.Url = 
           "http://localhost/WelcomeMessageStub/WelcomeMessageFoo.asmx";
        Response.Write(welcomeMessageStub.GetWelcomeMessage());

        Response.Write("<br/>");

        // However IF we found out that the user Belongs
        // too xFoo we could Hit xFoo's Web Service
        // URL to Invoke the right Web Method on the fly.
        // The URLs can be COMPLETELY different as
        // long as they are reachable.
        welcomeMessageStub.Url = 
          "http://localhost/WelcomeMessageStub/WelcomeMessagexFoo.asmx";
        Response.Write(welcomeMessageStub.GetWelcomeMessage());
    }
}

Next Steps

This article describes how multiple web services with the same WSDL specifications can be invoked dynamically without requiring to set a web reference to each and every web service individually. In this article, we used WSDL as a contract between the Web Service provider and the consuming application. In the next article, we will discuss how we can use XSD to have better contracts between the Web Service provider and the consumer.

History

  • Saturday, June 24, 2006 - Initial version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here