Search the Catalog
Programming .NET Web Services

Programming .NET Web Services

By Alex Ferrara, Matthew MacDonald
September 2002
0-596-00250-5, Order Number: 2505
414 pages, $39.95 US $61.95 CA

Chapter 2
Creating ASP.NET Web Services

Using the .NET Framework, it's easy to get a basic service up and running. In just a few minutes and fewer lines of code, you can put together a simple "Hello World" service without any understanding of HTTP, SOAP, WSDL or any of the several technologies that form the basis for web services. In fact, if you're a Microsoft Visual Studio .NET user, all you need to do to create a simple "Hello, World" service is to open a new Visual C# or Visual Basic ASP.NET Web Service project and uncomment the sample code provided by the template.

In this chapter, you'll learn about ASP.NET, the new Microsoft technology for building web applications and services, and how to use the .NET platform and Visual Studio .NET to create some simple web services. We'll also talk about some of the features of .NET that will get you on the road to developing well-documented scalable web service applications. By the end of this chapter, you'll have a solid understanding of how .NET supports web services and how to use the .NET platform to create them. We'll start with the ubiquitous "Hello, World" example exposed as a web service.

Creating a Web Service: "Hello, World"

In this section, you'll create a simple web service in the "Hello, World" tradition. Through this brief example, you'll see how easy it is to use ASP.NET to create a working web service (with a text editor or with VS.NET) and learn about the basic technologies behind .NET web service.

Creating a Web Service with Inline Code

While Visual Studio .NET provides a feature-rich integrated development environment for .NET development, it's not required to create .NET web services. Applications can also be created using your favorite text editor and the command-line tools that ship with the .NET Framework SDK. Here, we use Notepad as a text editor, but you should feel free to use whatever editor you're most comfortable with (Emacs or vi).

If you chose to develop with a text editor, you must place all of your code in one or more text files, assign them each the file extension .asmx and place them in an IIS folder on a server or workstation that has the .NET Framework installed. Once you save the code to a folder served by the IIS web server, it's ready to run--that's it! How you get the file to your web server is your business. If you're running IIS locally on your workstation (and you've installed the .NET Framework), this is as simple as saving the file to a suitable location on your local drive (e.g., c:\inetpub\wwwroot\). If you're using a remote server (in which case there's no need to have the .NET Framework installed locally), you might have to use FTP or a network share instead (more about this later).

Once you've chosen a text editor and file location, all that's left is to write the code.

Example 2-1 lists the code for a C# version of the ubiquitous "Hello, World" application; unlike the classic desktop version, this one delivers its familiar message over the Web through an exposed method called HelloWorld(). To identify the class and method as a web service to the compiler, this code uses some special notation. It also includes an ASP.NET directive at the head of the file.

To create a C# version of the HelloWorld web service, enter the code from Example 2-1 exactly as it appears, and save the file to your web server under the c:\inetpub\wwwroot folder (or whatever folder is the web root folder for your system) with the name HelloWorld.asmx.

Example 2-1. HelloWorld: C# web service

<%@ WebService Language="C#"
Class="ProgWS.Ch02.HelloWorldService" %>
using System.Web.Services;
namespace ProgWS.Ch02
{
  public class HelloWorldService: WebService 
  {
    [WebMethod]
    public string HelloWorld()
    {
      return "Hello World";
    }
  }
}

In the following sections, we'll explain the standard elements of this web service source file and then show you how to test it.

The WebService directive

Example 2-1 begins with a WebService directive, an ASP.NET statement declaring that the code that follows is a web service:

<%@ WebService Language="C#" Class="ProgWS.Ch02.HelloWorldService" %>

TIP: The WebService directive is similar to the Page directive that begins most .aspx pages.

For the HelloWorld web service to work, you must assign values to two WebService directive attributes: Language and Class.

The required Language attribute lets .NET know which programming language the class has been written in. As you might guess, the acceptable values for the language attribute are currently C#, VB, and JS for JScript.NET.

The Class attribute, also required, tells ASP.NET the name of the class to expose as a web service. Because a web service application can comprise multiple classes, some of which may not be web services, you must tell .NET which class to expose, a step analogous to declaring a Main() method to indicate the entry point of a .NET console application or component. Note that even if your web service contains only one class, setting this attribute is required.

The using directive: importing .NET namespaces

The next line in the example is a using statement that tells the compiler to alias the System.Web.Services namespace to the local namespace. For C#, this directive is:

using System.Web.Services;

This directive allows you to refer to objects in the System.Web.Services namespace without having to fully qualify the request. This statement is optional, but if it is not included, every reference to an object in this namespace must be fully qualified. An example is the next line, which is our class declaration. With the using statement, it looks as follows in C#:

using System.Web.Services;
public class HelloWorldService: WebService

Without the using statement, it would have to be written fully qualified:

public class HelloWorldService: System.Web.Services.WebService

Note: Importing a namespace does not give you access to any of the additional namespaces that appear to be nested in that namespace. In other words, if you were to import the System.Web namespace, you would not be able to refer to the System.Web.Services.WebService class as Services.WebService. While a namespace like System.Web.Services may "appear" to be nested in the System.Web namespace, that is not the case. They are implemented as two different assemblies that bear little relation to each other aside from a partial name sharing. The apparently hierarchical nature of the .NET Framework's namespaces exists in name only as an organizational convenience and has no bearing on class structure.

The namespace keyword

.NET allows you--and Microsoft encourages you--to put the classes of an application into a unique namespace. In C#, this is done with the namespace keyword and the following syntax:

namespace name
{
... type declaration ...
}

In Example 2-1, the HelloWorldService class is placed in the ProgWS.Ch02 namespace with the following statement:

namespace ProgWS.Ch02
{...
}

Namespaces can contain definitions for classes, interfaces, structs, enums, and delegates, as well as other namespaces. In addition, the source code for objects in a namespace does not have to be stored in the same file--it can span multiple files.

Note: For Java programmers: a namespace is similar to a package. However, unlike a package, in a namespace there are no directory structure requirements, because all of the source code is presumed to be in the same directory or a global assembly cache.

Namespaces provide a means of grouping pieces of code that might be written and maintained by other developers. When the class definitions of your web service exist within a namespace, you must specify the namespace along with the class name in your WebService directive as in Example 2-1:

<%@ WebService Language="C#" Class="ProgWS.Ch02.HelloWorldService" %>

This line tells ASP.NET to look for the class HelloWorldService in the namespace ProgWS.Ch02.

The WebService class

At the heart of Example 2-1 is a class called HelloWorldService. This class is a subclass of System.Web.Services.WebService. By inheriting from the WebService class, a web service gains direct access to the ASP.NET intrinsic objects, such as Application and Session, just like any other ASP.NET application.

TIP: While inheriting from the WebService class is a common approach for creating a .NET web service, it is by no means necessary. You can rewrite the previous examples without this inheritance, and your service will run just fine. However, if you need access to the Application and Session objects without inheriting from WebService, you'll need to use the System.Web.HttpContext object explicitly, as we'll explain in a later chapter.

The WebMethod attribute

The HelloWorldService class exposes a single method, the public method HelloWorld, which takes no arguments and returns a string containing the text "Hello World". To expose a method as a part of a web service, you must decorate it with the WebMethod attribute, which tells the compiler to treat it as such. Any method marked with the WebMethod attribute must be defined as public. Class methods exposed as web services follow the same object-oriented rules as any other class, and therefore methods marked private, protected, or internal are not accessible and will return an error if you attempt to expose them using the WebMethod attribute. For additional details, see "The WebMethod Attribute" later in this chapter.

The neat thing about this simple example is that you've created a full-blown web service out of an arbitrary method. You could just as easily have substituted a method that retrieves a record from a data store or a method that wraps a COM object. Additionally, you could have used any of the languages supported by the .NET Framework for this implementation and, then, as you will see later, used any .NET or non-.NET language in a client application. By inheriting from the System.Web.Services.WebService class, you are able to take advantage of an API that insulates you from the underlying SOAP/XML message exchanges.

To put this web service to work, all you need to do is copy it to the web server just as you would any other resource, whether it's an image, HTML file, ASP page, or another resource. Once you've done that, the web service is ready to be used by a consumer application, a process we'll look at in detail in Chapter 3. This ease of deployment is the main benefit of inline coding; perhaps the biggest drawback is that your presentation code and business logic are lumped into the same file, which can make working with large projects difficult to manage. Let's take a look at how Visual Studio .NET can be used to create and deploy this web service without stepping outside its Integrated Development Environment by using the so-called code-behind approach.

Assemblies

We said that a namespace is a container for types such as classes, interfaces, structs, and enums. We also said that the source code for objects in a namespace does not have to be stored in the same file, but can instead span multiple files. When the set of source code constituting a namespace is compiled into a library, this library is called a managed DLL, or, more commonly, an assembly. Assemblies are the building blocks of .NET applications and the fundamental unit of deployment. They comprise a collection of types and resources that provide the CLR (Common Language Runtime) with the information it needs to be aware of type implementations. Their contents can be referenced and used by other applications using Visual Studio .NET or a .NET command-line compiler.

Creating "Hello, World" with Visual Studio .NET

While Notepad is an adequate tool for creating simple services, Microsoft's new development environment, Visual Studio .NET (VS.NET), provides a world of features to aid you in creating complex web services. Visual Studio .NET also provides the quickest path to getting a web service up and running, apart from the time it takes to install all or part of the more than 1.8 GB (compressed) of installation files required to run Visual Studio .NET. This section takes you through the process of creating the "Hello, World" service using Visual Studio .NET.

Setting up VS.NET for the web service project

To make use of the automation in VS.NET, you must first configure it to communicate with your web server. You can use either FrontPage Extensions or Universal Naming Convention (UNC) file shares. To keep things simple, we'll assume you have installed IIS on your local workstation. Here's what you need to do to set up VS.NET for your first web service. We go into detail on FrontPage Extensions and UNC file shares later in this chapter (see "Deploying a Web Service.")

Microsoft FrontPage Server Extensions are the easiest to configure and a good choice for the simple web services in the next two chapters. FrontPage Extensions can be installed as a part of IIS, or alternatively downloaded for free from the MSDN site at http://msdn.microsoft.com. For this example, we're using a Windows 2000 workstation, IIS 5, and FrontPage 2000 Server Extensions, version 4.0.2.4426. While any version of the Extensions will work, the configuration process varies greatly among them and the steps outlined here may not work with your version.

Once you've installed FrontPage Server Extensions on your local workstation (i.e., the workstation hosting IIS), open the Internet Services Manager from the Start Programs Administrative Tools menu so that you can configure a FrontPage web. Right-click on Default Web Site and select All Tasks Configure Server Extensions from the dialog box. You will be taken through a brief configuration wizard that asks you configuration questions. Once the server extensions have been installed, you're ready to create a web service project in Visual Studio .NET.

TIP: With Windows XP, you reach Administrative Tools and the IIS Manager through he Control Panel.

Creating a C# web service project

Visual Studio 6.0 users will find the layout of Visual Studio .NET familiar enough that they can get working without much assistance. We'll help users who are new to Visual Studio. Users new to Visual Studio .NET can also rely on its extensive built-in Help feature.

To create a new web service, fire up Visual Studio .NET and either select the New Project button on the default Start Page or click File New Project on the main Visual Studio .NET menu bar. The Visual Studio project model is the same as earlier versions, in that a file can be part of a project, and a project part of a solution. A solution is the outermost container, containing zero or more projects. After selecting an option to create a new project, you'll see the screen in Figure 2-1.

Figure 2-1. Creating a new Visual Studio project

 

Here you have the option to create a variety of project types from templates. Under Visual C# Projects, one template option creates an ASP.NET web service, while our examples use the C# language, the same option also available as a Visual Basic project, and similar options for Managed C++ exist as well. In addition to selecting a project language and template, you must specify a project name and location. The location fior the HelloWorldService should be the URL of the IIS web server you just configured to work with FrontPage Extensions (e.g., http://localhost). For this example, we'll use the project name "HelloWorldService."

Once you click OK, the IDE (Integrated Development Environment) creates a new solution and project and automatically populate the project with several files. The IDE will also create a virtual folder under IIS with the same name as the project name, which, in this case, is HelloWorldService.

Exploring the solution and project

The contents of your new project are displayed in the Solution Explorer window, which should appear on the right side of the VS.NET IDE, as shown in Figure 2-2.

Figure 2-2. The Visual Studio .NET Solution Explorer

 

If the Solution Explorer is not visible, you can open it by selecting Solution Explorer from the View menu (or pressing Ctrl-Alt-L).

When you create a new project without specifying the name of an existing solution, VS.NET creates a new solution whose name is the same as the one you chose for your project. You can see in Figure 2-2 that, in this case, a solution named HelloWorldService has been created; it contains one project, also called HelloWorldService.

Visual Studio .NET also automatically creates several assembly references and files, which are also displayed in the Solution Explorer, as shown in Figure 2-3. In this example, VS.NET has included assembly references to the System, System.Data, System.Web, System.Web.Services, and System.XML namespaces. (The System.Data and System.XML assembly references are not necessary for this example, so you can remove them if you'd like, but there's no real benefit to doing so other than simplicity.)

Figure 2-3. Displaying all files in VS.NET Solution Explorer

 

The five other files that appear in Figure 2-3 are AssemblyInfo.cs, Global.asax, HelloWorldService.vsdisco, Service1.asmx, and Web.config. The only file you really need to create the web service is the .asmx file, which we'll discuss in the next section. The four other files provide additional features and functionality that will help you as you build more complex services, but none of them are necessary for this example. In fact, you can delete all of the non-.asmx files and the service will run just fine (we don't recommend this). Here's a brief explanation of of each of these.

AssemblyInfo.cs
An information file that provides the compiler with metadata (name, version, etc.) about the assemblies in the project.

Global.asax
Customizable to handle application-level events (e.g., Application_OnStart).

HelloWorldService.vsdisco
An XML file used for dynamic discovery of web services. The DISCO specification has been superseded by WS-Inspection and is discussed in Chapter 10.

Web.config
An XML file containing configuration information for the application.

Exploring the .asmx file and service design view

The most important file in our example is the sample service page named Service1.asmx. If you open the page by double-clicking it, Visual Studio .NET displays a blank design page in its main window. If we were dealing with an .aspx ASP.NET web application, this design page could be used to design the user interface for the page, but since we're developing an .asmx web service that will be consumed by a machine rather than a person, this design view is not as useful to us. If you try to add a Windows form component, you'll get an error ("Object reference not set to an instance of an object"), because the web service design view doesn't know what to do with the component. Unlike an ASP.NET web form project, an ASP.NET web service project doesn't include the plumbing to support Windows form components.

You can use the design view to add preprogrammed components to your service from the Visual Studio .NET Toolbox, but you can't do much beyond adding these items, which is just as easily done directly through the code view page (Service1.asmx.cs). Perhaps Microsoft or another vendor will provide more powerful support for drag-and-drop web service design using business-logic components at some point, but as of today, the design view is not very useful. Instead, you can view the source code of your service by right-clicking on the Service1.asmx file in Solution Explorer and selecting View Code. At this point, you'll also want to rename the Service1.asmx file to something more appropriate to the project. You can do this by right-clicking the file in Solution Explorer and selecting Rename from the menu. Change the name to HelloWorldService.asmx.

Displaying all files in Solution Explorer

The .asmx.cs file is not displayed by default in Solution Explorer. To see it, select Show All Files from the Project menu tab (there's also an icon at the top of Solution Explorer to do this). The Solution Explorer view will change to look like Figure 2-3.

This new view displays all of the files associated with the HelloWorldService project. Notice that the Service1.asmx file now has a tree expander icon to the left of it. Click on the icon, and you'll see another file beneath the Service1.asmx file called Service1.asmx.cs. Elsewhere, you'll also notice a folder called \bin, which is used to store the project's compiled assemblies generated by Visual Studio .NET.

Understanding the autogenerated service code

When you create a new ASP.NET web service project, Visual Studio .NET generates some boilerplate code to get you started. The contents of the source file HelloWorldService.asmx.cs should resemble that reproduced in Figure 2-4.

Figure 2-4. Visual Studio .NET boilerplate code

 

This boilerplate code begins by importing several namespaces generally required for web services and by automatically generating namespace and class definitions. In this example, the namespace and class definitions are HelloWorldService and Service1, respectively.

The namespace definition is generated based on the project name, but you will probably want to change to something more suitable (in this case, we're going to continue to use ProgWS.Ch02) depending on your application. The service name is always autogenerated as Service1. Change this to something more appropriate for your application (in this case, we're using HelloWorldService), but you should also remember to change the name of the .asmx page to mirror your service name. Your service will run just fine if the names don't match up, but keeping the naming consistent can help make managing your service easier, particularly if you have a project with a large number of services.

The imported namespaces at the beginning of the code are provided as a convenience, and some of them are unnecessary. Specifically, the System.Data, System.Collections, and System.Diagnostics namespaces are not used at all. The classes of the System.ComponentModel namespace are used only by the web service designer methods, InitializeComponent() and Dispose(), which work in conjunction with a private member variable of type IContainer called components. To see these methods, you need to expand the Component Designer Generated Code region. Since you're most likely not going to need the (limited) features of the web service design view, you can clean house by deleting the entire region. You will be left with code that looks like the following (some comments have been removed to shorten the listing).

using System;
using System.Web;
using System.Web.Services;
 
namespace ProgWS.Ch02
{
  public class HelloWorldService : System.Web.Services.WebService
  {
    public HelloWorldService() {}
    // WEB SERVICE EXAMPLE
    // The HelloWorld() example service returns the string Hello World
    // To build, uncomment the following lines, then save and build the project
    // To test this web service, press F5
 
    //[WebMethod]
    //public string HelloWorld()
    //{
    //return "Hello World";
    //}
}
}

This code should look familiar since it is nearly identical to the code shown in Example 2-1. All you need to do to make it look like the earlier example is to remove the comments in front of the HelloWorld() method and [WebMethod] attribute.

Notice, however, that the WebService directive that was present in the inline code example is missing:

<%@ WebService Language="C#" Class="ProgWS.Ch02.HelloWorldService" %>

Recall that this directive is required to tell the compiler which class file to use as the entry point for the web service. So where is it? When you wrote the inline code example, you included both the directive and the source code for the HelloWorld class in the same file. By contrast, when Visual Studio .NET creates web service code, it separates the WebService directive and the source code using an approach known to ASP.NET developers as code-behind.

Understanding the code-behind model

The code-behind approach to programming web services (as well as ASP.NET web applications) involves separating the WebService directive from the supporting C# code. In this model, the .asmx page contains only one line, the WebService directive, while the supporting source code is placed on its own page, which, in the case of C#, has the file extension .asmx.cs, as in the preceding example. This page must be compiled into an assembly and placed in the \bin directory of your web service before the service can be used. Visual Studio .NET takes care of this process for you automatically when you build your project.

When you send a request to your web service for the first time, ASP.NET reads the WebService directive to find out the name of the class file containing its supporting logic. ASP.NET knows to look for the compiled class in an assembly in the \bin directory of the project. If there are multiple assemblies in the \bin directory, ASP.NET will look through each of them until it finds the appropriate class.

One of the advantages to storing your code in a compiled form is that source code is not left lying around on your production web servers. A malicious user who gains access to the server hosting your application will not easily be able to steal your code (we say "easily" because there are tools for decompiling MSIL). The disadvantage to using the code-behind model is that deployment requires an additional step--compiling the source code--which is not necessary for inline code.

The CodeBehind Attribute

If you find and view the .asmx page that VS.NET automatically generates and places on your server, you'll notice that the WebService directive includes an additional attribute called CodeBehind. (Unfortunately, you cannot view this .asmx page from Visual Studio .NET; instead, you'll need to look at the file placed on your web server in the c:\inetpub\wwwroot\HelloWorldService folder). In our example, it looks like this (except it's all on a single line):

<%@ WebService Language="c#"
    Codebehind="HelloWorldService.asmx.cs"
    Class="ProgWS.Ch02.HelloWorldService" %>

This unfortunate choice for an attribute name often confuses developers new to ASP.NET, who often assume that it is used in some way by ASP.NET to locate the code-behind file (indeed, the Microsoft Visual Studio documentation would lead you to believe this to be the case). In fact, this is not the case. This attribute is a Visual Studio .NET-specific attribute and is used by VS.NET to match the .asmx page to the associated source code file. This attribute has nothing to do with ASP.NET. In fact, ASP.NET completely ignores this attribute when processing a page request.

TIP: Visual Studio .NET is not designed to support the inline coding model. It's possible for you to use it, but we certainly do not recommend it: you cannot directly create an inline web service in Visual Studio .NET, because when you create a new web service, by default, Visual Studio .NET creates separate .asmx and class files.

To create an inline service using VS.NET, you must create a new text file and change its extension to .asmx. Creating an .asmx page in this manner forces you to write your code in the Visual Studio .NET HTML editor, not the code editor, which does not provide support for color coding, Intellisense, or many of the debugging features. In addition, because the code in the page is not compiled into the project assembly, compile-time errors are not caught until the page is run.

Building the service

Because Visual Studio .NET uses the code-behind model, simply posting the source pages to the server as in the inline example will not work. If you do so, you will get an error when you try to access the service. Instead, it's necessary to save your .asmx page to the server and compile your source code, saving it to the project's \bin directory. VS.NET automates this process for you through its build feature. Once your application is complete, select Build Solution from the Build menu (or press Ctrl-Shift-B) and VS.NET will compile your web service and transfer the .asmx page and associated compiled assembly to the web server for you. If any errors result from the compile, VS.NET will display them in a panel labeled Output at the bottom of the IDE. Once you have successfully built the web service, it's ready to be used.

Testing the Service

Unlike Active Server Pages, web services are not designed to be viewed in a browser. Instead, web services are consumed by a client application using protocols such as HTTP GET/POST, SMTP, or SOAP over HTTP (see Chapter 3 for more information on consuming web services). Some of these protocols, such as SOAP, are more appropriate for server-to-server communication, while others, such as HTTP GET, are more frequently associated with the model of traditional web page access.

A web service that uses HTTP GET as a transport protocol can be accessed in much the same way as a regular web page. All that is necessary to access such a page is to point a web browser to the service endpoint. In our example, the endpoint comes is an .asmx page. But how do you know which protocols HelloWorldService will support, since there is no mention of HTTP or SOAP in the example code? The answer is that, by default, all .NET web services try to support HTTP GET, HTTP POST, and SOAP. We say "try," because in many cases the web service may be too complex for HTTP GET support. Additionally, because web services are applications that expose functionality to web service clients, and as a result have no required graphical user interface, .NET provides a canned web service test page that is displayed when you point your browser to an .asmx page. If you open a browser and type in the URL of the .asmx web service you just created, you'll see the IE test page shown in Figure 2-5.

Figure 2-5. The HelloWorldService test page

 

The page in Figure 2-5 is generated by the .NET HTTP runtime each time it receives a request for an .asmx page. The page template is itself an ASP.NET .aspx page named DefaultWsdlHelpGenerator.aspx and is stored in the \WINNT\Microsoft.NET\Framework\[version]\Config directory on the server that hosts the web service. This page operates just like any other .aspx page (remember that this is the extension for ASP.NET pages) and can be easily customized.

The test page displays the HelloWorldService service name along with the HelloWorld() method and a link to the service description. The service name and any additional information about this service are retrieved through a process called reflection, which uses the System.Reflection namespace to reveal information about existing types via metadata. In fact, if you look at the Page_Load function for the DefaultWsdlHelpGenerator.aspx page (again, in the \WINNT\Microsoft.NET\Framework\[version]\Config directory on the hosting server), you'll see how this process works. If our service contained additional methods that were callable via HTTP, they would be listed as links here as well.

Viewing the Service Description

The runtime also automatically creates a service description from the .asmx page, an XML document that conforms to a specification called Web Service Description Language, or WSDL (pronounced "Wiz-Duhl"). If you click the service description link, you'll see the WSDL page. This page can also be viewed in a browser by appending ?WSDL to the page URL, as in HelloWorldService.cs.asmx?WSDL. The service description for our service is shown in Figure 2-6.

Figure 2-6. The HelloWorldService description

 

You can see that the WSDL document includes information about the service namespaces, protocols supported, data types used, and web methods exposed in an XML-based format. This type of information is particularly important for an application looking to use our service, as you'll see in the next chapter.

The WSDL specification is a linchpin of sorts for the various web service development platforms. As you'll see in Chapter 11, where you'll learn about web service interoperability, web service development platforms must all abide by the same version of WSDL as well as the same version of SOAP if they are to work together (actually, WSDL is not an absolute requirement, but it is necessary for automatic proxy generation, as you'll see in Chapter 3). The version of WSDL we discuss in this book, 1.1, is currently supported by .NET and most other web service implementations (e.g., SOAP::Lite, Apache Axis).[1] The .NET Framework currently implements SOAP 1.1.

Getting back to the service test page: if you mouse over the HelloWorld link, you'll see the destination URL:

http://localhost/HelloWorldService.cs.asmx?op=HelloWorld

By clicking this link, you call the .asmx page, passing a parameter called op (standing presumably for operation) along with the name of the service. This action is the same as calling the HelloWorld web method of the web service using HTTP GET. The output page is shown in Figure 2-7.

Figure 2-7. The HelloWorldService invocation page

 

Here you'll see the name of the service and method along with a button to test the service. Through reflection, the logic in the DefaultWsdlHelpGenerator.aspx test page is able to determine the signature of our HelloWorld method. Because our web method takes no arguments, the page need provide only a button for invocation. If our method had a different signature--for example, if it reads a string of text--the .aspx help page would also provide a text box to capture this string and pass it, using HTTP GET, to the web method when the form was submitted. This text box method works fine for simple data type arguments, but if the web method were to require an object, this approach would not work.

Beneath the Invoke button, there are also sample service interactions for SOAP, HTTP GET, and HTTP POST. We'll talk about some of the other methods of consuming web services in Chapter 3, but for now, note that on the source, the page is still using HTTP GET to invoke our service.

<form 
 action='http://localhost/HelloWorldService/HelloWorldService.cs.asmx/HelloWorld' 
 method="GET">                        
...
</form>

Invoking the Web Method

You can invoke the web method using the IE test page by opening a web browser and navigating to the service's URL. You will see a page listing the service's operation, which should be HelloWorld. Click the HelloWorld operation to navigate to the web method invocation page. This is a page that allows you to test the operation by clicking a button labeled Invoke. Click the button to invoke the service.

Invoking the example service produces the results shown in Figure 2-8.

Figure 2-8. HelloWorldService output

 

You know that web services are a means of communicating between servers using XML, so it should come as no surprise that the output of our service is nothing more than an XML document--and a short one at that! Had you used SOAP to access the service, you would have received a message in SOAP format; however, since IE isn't designed to either write or read SOAP messages by itself, you're limited to using HTTP GET and POST.

The response document begins with the following XML declaration:

<?xml version="1.0" encoding="utf-8" ?>

which identifies the document as an XML document and identifies the encoding of the document to be UTF-8 Unicode. While the encoding type may vary, all XML processors are required to support UTF-8 and UTF-16 Unicode encodings.

The first and only element in the output document is an element called string, which contains the output of our method and has one attribute called xmlns:

xmlns="http://tempuri.org"

This namespace declaration specifies that all unprefixed elements in this document come from the namespace tempuri.org.

The WebService Attribute

One of the features missing from our HelloWorld web service is information about what it does. To tell a client about the functionality provided by our service, we need some mechanism for documenting it. .NET provides an attribute for this purpose, WebServiceAttribute (a member of the System.Web.Services namespace), which you can use to let clients know where to find information about a web service. As with other attribute types, the WebServiceAttribute class inherits from System.Attribute. For convenience, the compiler will let you omit the Attribute part of the class name in most usage contexts, allowing you to use just WebService instead (not to be confused with the WebService directive in an .asmx page). For simplicity, we'll leave off the Attribute part as well throughout this text. The WebService attribute has two properties, described next.

Namespace
Sets the XML namespace for the service

Description
Adds a text/HTML description of the service that becomes part of the service description (WSDL) document

As discussed earlier, XML namespaces are important in the XML world for uniquely identifying the elements and attributes of an XML document. XML namespaces have nothing to do with the .NET's namespaces, which are used to organize classes.

Example 2-2 uses the Namespace and Description properties of the WebService attribute to document a web service named DNSLookUpService, which we introduce here for the first time. DNSLookUpService takes a hostname as a string argument and uses a class called Dns from the System.Net namespace to resolve and return the associated IP address.

Example 2-2: DNS LookupService

using System.Web.Services;
using System.Net;
[WebService(Namespace="http://www.bostontechnical.com/webservices/",
    Description="<b>A web service which performs Domain Name Lookups.</b>")]
public class DNSLookupService : System.Web.Services.WebService
{
         [WebMethod]
         public string getIPforHostname(string strHostname)
         {
                 IPHostEntry hostInfo = Dns.GetHostByName(strHostname);
                 return hostInfo.AddressList[0].ToString();
         }
}

In Example 2-2, the namespace for our web service is set to http://www.bostontechnical.com/webservice/. The web service will use this namespace as the source for definitions for all of the XML documents it returns in response to calls to its method. Remember that the purpose of XML namespaces is to avoid naming collisions among XML elements and attributes. Namespace URIs such as this one are commonly used because the domain name (e.g., www.bostontechnical.com) is guaranteed to be unique by a registration authority (e.g., Network Solutions). It is then the organization's responsibility (in this case, the owner of www.bostontechnical.com) to ensure uniqueness among the elements /webservice domain of the namespace.

We've also added a description for our service. As you can see, HTML tags are permitted in the service description, making the resulting IE test page appear as shown in Figure 2-9.

Figure 2-9. Adding a service description

 

The namespace and description are also included in the WSDL page for programmatic access, as shown in Figure 2-10.

Figure 2-10. WSDL with custom service name

 

The XML output in Figure 2-10 has been collapsed to improve readability, but notice the <service> element that appears toward the bottom of the listing and which contains our customized service name. Because the WSDL page is the contract for all web service consumers, the custom name is now available as part of the service identification.

The WebMethod Attribute

The WebMethod attribute, first used in Example 2-1, tells .NET that a particular public method should be exposed as a web-callable method. The WebMethod attribute has six associated properties to document and change the behavior of your web method. They are:

The first two properties are used to document a web method, while the others affect its behavior. In the following sections, we'll introduce each briefly. Each property is described in greater detail in a later chapter.

The Description and MessageName Properties

To avoid forcing your consumers to guess at what a web method does based on its name, include a description for each of your web methods, just as you should for the service itself. This is particularly necessary when a web service contains overloaded web methods. For example, the following code fragment declares two methods named Add(), one that accepts parameters of type Integer and one that accepts parameters of type Floating:

...
[WebMethod]
public int Add(int a, int b)
{
  return a + b;
}
[WebMethod]
public float Add(float a, float b)
{
return a + b;
}
...

In fact, if you try to access a web service containing two methods with the same name but different method signatures (an overloaded method) through the IE test page, you get a runtime exception when you view the page. The error for the previous example is as follows: "Both Single Add(Single, Single) and Int32 Add(Int32, Int32) use the message name "Add". Use the MessageName property of the WebMethod custom attribute to specify unique message names for the methods."

The procedure for commenting web methods is very similar to that for commenting a service. Start each method declaration with a WebMethod attribute. Use its Description property to add a description of your web method and its MessageName property to change its name:

[WebMethod(MessageName="<name>", Description="<desc>")]

In our DNSLookupService example, the descriptive code would look like this:

[WebService(Namespace="http://www.bostontechnical.com/webservices/",
   Description="<b>A web service which performs Domain Name Lookups.</b>")]
public class DNSLookupService : System.Web.Services.WebService
{
  [WebMethod(MessageName="LookupDNS", 
             Description="Get an IP address for a given hostname string")]
  public string GetIPForHostname(string strHostname)
  {
    IPHostEntry hostInfo = Dns.GetHostByName(strHostname);
    return hostInfo.AddressList[0].ToString();
  }
}

The WSDL service description reflects these changes, as shown in Figure 2-11.

Figure 2-11. WSDL with namespace and documented web methods

 

Notice that the WSDL document includes a <portType> tag for each of the supported access protocols (POST/HTTP GET and SOAP). Each of the <portType> tags contains an additional XML documentation element, which itself contains the textual explanation for the web method. In addition, the name attribute of each of the input and output elements now contains the value of the names that we've assigned to the method: getIPForHostname. Because this documentation is now part of the WSDL page, it is programmatically accessible to a calling application. You will see why this documentation is particularly useful to the consumer in the next chapter when we talk about .NET proxy classes.

The EnableSession Property

ASP.NET web services (classes that derive from System.Web.Services.WebService) exist within the context of an ASP.NET application and therefore have access to the Application and Session objects of the ASP.NET application within which they reside. While an ASP.NET application has only one Application object, it can have multiple session objects, which can be used to store data on a per-client basis. This state management mechanism is disabled by default and can be enabled by setting the EnableSession property to true. Enabling session management can decrease performance, so leave it disabled if you don't plan on using it.

If session state is enabled, the server manages client state using a unique HttpSessionState object for each client. In order to differentiate between each client's Session, a unique identifier is assigned to each Session object when the client first interacts with the server. On subsequent interactions, the client must present its unique identifier in order for the server to retrieve any client-specific data that has been stored in session state. The unique identifier can be stored in a cookie on the client or can be included as part of the URL. In a typical ASP.NET application, which is accessed via a web browser, this state management system occurs behind the scenes. If cookies are enabled on the web browser, it will automatically present the appropriate cookie to the server along with each request. Because a web service is not accessed in the same manner, if you choose to enable session management, you must programmatically set the cookie each time you call your web service. (You'll learn more about this and other state management approaches in Chapter 5.)

The CacheDuration Property

Implementing proper caching in your web services can increase scalability and performance. One of the easiest ways to implement caching systems is with the CacheDuration property of the WebMethod attribute. .NET implements this type of caching, called output caching, by system by storing matching pairs of requests and responses in a hashtable in memory for the specified amount of time. During this time, any incoming request that matches a request already in cache forces the server to output the cached response. Use the CacheDuration property to set the number of seconds (integer) a request/response pair will be held in cache. The default is 0, meaning that the response is not cached.

This caching mechanism is often ideal for web methods that involve processor-intensive or other expensive queries where the results change infrequently. An example of this type of functionality is a web method that queries a database for news headlines that change daily. For a system like this, we might set the CacheDuration property for our web method to five minutes or more to reduce the number of round-trips to the database. Because the caching system is based on request/response pairs, it uses few server resources in situations like this in which the web method's range of expected input parameters is small. If, however, you have a wide range of expected input parameters (and therefore request strings), the cache hashtable can quickly grow to consume a great deal of memory or can cause valuable items to be deleted from the cache. This can be further aggravated if the output of your method (which is stored in cache) is sizable. An example of a web method that would not lend itself well to caching with CacheDuration is the GetIPForHostname method of our DNSLookupService. It meets the first part of the requirement, in that it involves a fairly expensive network operation to retrieve a reasonably static small result; however, this type of service receives a wide range of inputs. Using a high cache duration setting for this method would cause the hashtable to grow in memory as unique lookup requests were made to the service.

We discuss output caching in detail in Chapter 7, along with data caching.

The TransactionOption Property

If you've ever programmed MTS or COM+ components, you're probably comfortable with the idea of developing transaction-based services. A transaction can be thought of as any set of procedures (e.g., events, function calls) that collectively result in a change of state such as a success or failure. One example is a credit card processing system that authenticates a credit card number, charges the card, and triggers a fulfillment process. If any of these three steps fails (e.g., the card is declined), the transaction as a whole will fail, and each of the individual processes must be returned to its original state (e.g., cancel a fulfillment process if it has been started). All three steps are part of a transaction.

Microsoft includes support in the .NET platform for MTS or COM+ style transactions through the System.EnterpriseServices namespace. We're not going to get into the details of developing transacted services in this book; however, it is important to understand the difference between .NET-style transactions and what we'll call distributed web service transactions.

.NET transaction support is set through the TransactionOption property of the WebMethod attribute. The five possible settings for this property are:

By default, transactions are disabled. If you decide to use .NET transactions, your web method will be able to participate only as the root object in a transaction. This means that your web method may call other transaction-enabled objects, but may not itself be called as part of a transaction started by another object. This limitation is due to the stateless nature of the HTTP protocol. As a result, the Required and RequiresNew values for TransactionOption are equivalent (and both declare a RequiresNew method that will start a new transaction). Disabled, NotSupported, and Supported all disable transactions for the web method, despite what their names imply.

We discuss the TransactionOption property in more detail in Chapter 5.

The BufferedResponse Property

The default behavior for a web method is to store a response in a memory buffer until either the buffer is full or the response is complete. This storage process is called serialization. In most scenarios, this behavior is preferred, because buffering results in improved performance by reducing the number of transmissions to the client. However, if your web method returns a large amount of data or takes a long time to run, you might want to disable buffering by setting the BufferResponse property to false. This setting causes .NET to send the response back to the client as it is serialized, but can reduce performance for smaller result sets.

For all practical purposes, there's no reason that you should ever need to change this property's value. For an .aspx page, the output of which is meant to be displayed to a user, it can make sense to disable buffering for long-running pages such as a search page, so that the user can start viewing the data before it's completely returned. Because web services are designed for host-to-host communication, this type of scenario rarely occurs. and the default value for this setting does not need to be changed.

Deploying a Web Service

The process you use to deploy your web services will vary depending on whether you use inline coding or code behind to write them and whether you use an IDE like Visual Studio .NET. As you've seen, deployment for web services written using the inline approach is a snap. Once you have written and tested a web service on your development machine, all you have to do is to save the raw source to a server running the .NET SDK and IIS 5.0 or later. .NET compiles the service and caches a copy of the compiled class for you. If the source page changes, .NET will automatically recompile and cache the new page. This process is handled by .NET using some of the classes found in the System.Web.Caching namespace. You'll learn more about these classes in Chapter 7.

If you're using the code-behind approach, the deployment process is more involved. Let's take a closer look at what you need to do in order to be able to deploy your web services using the code-behind approach, first with and then without the help of Visual Studio .NET.

Deploying a Web Service with VS.NET

The deployment process in Visual Studio .NET is as simple as choosing the Build Solution option from the Build menu item (or pressing Ctrl-Shift-B). But, in order to take advantage of this two-click deployment, you first need to properly configure Visual Studio .NET to be able to deploy to your instance of IIS. Earlier we mentioned that there are two ways for Visual Studio .NET to communicate with IIS: Microsoft FrontPage Server Extensions, and UNC file shares. In the earlier example, we used FrontPage Extensions because they are easier to configure (or at least easier to explain). Let's take a closer look at the differences between Frontpage Extensions and UNC.

FrontPage Extensions and UNC

Visual Studio .NET offers you two methods of connecting to the web server. You can use either FrontPage Extensions or UNC. FrontPage Extensions is a technology that allows Visual Studio .NET to transfer files to and from the web server over HTTP. In order to use this method of file transfer, you must install and configure the FrontPage Server Extensions to the web server as we discussed in the earlier "Creating "Hello, World" with Visual Studio .NET" section.

The other way Visual Studio .NET can communicate with the web server is via UNC, or Universal Naming Convention file or folder shares. A file or folder share is just a file or folder on the network that is configured to be shared by one or more users. UNC provides a naming convention for identifying network resources, in this case the web server. UNC names consist of three parts: a server name, a share name, and a file path, separated by backslashes (\) as follows:

\\servername\share\file_path

This format is called a UNC path. The server name portion of the UNC path is either a network address (IP address) or a hostname that can be mapped to a network address using a naming service like DNS. The share can be either a custom share configured by a system administrator or one of several built-in shares. An example of a built-in share is the admin$ share, which typically maps to c:\winnt\, or the c$ share, which maps to c:\. The file path allows you to specify the subdirectory below the specific share. For example, the following path:

\\myserver\c$\inetpub

points to the c:\inetpub folder on a server called myserver.

If you choose UNC access for your project, it's important to make sure that the UNC path corresponds to the URL specified in the creation dialog box; otherwise, VS.NET will return an error.

Locally and remotely hosted projects

There are no configuration differences between web service projects hosted locally (i.e., on your workstation) or remotely (i.e., on a remote web server). Regardless of whether your projects are hosted locally or remotely, you should still use either FrontPage or UNC access. Of course, if you choose to use UNC access for your projects, you must make sure to configure a share to the appropriate IIS folder so that VS.NET can transfer files. For local workstation development, VS.NET takes care of some of the work for you automatically.

VS.NET UNC support

When VS.NET is installed, it creates an empty "VS Developers" user group and a share on the \inetpub\wwwroot folder called wwwroot$ (which we'll discuss shortly). VS.NET then grants the newly created group read and write permissions on that share. This VS Developers group is created without any members, so unless your user account has administrative privileges on your workstation, you will need to add yourself to this group.

By default, Visual Studio .NET is configured to use UNC access for projects. When you specify the URL for a new project, such as http://ws.uinspire.com/HelloWorldService in the earlier example, Visual Studio .NET attempts to create the project using the UNC path:

\\ws.uinspire.com\wwwroot$\HelloWorldService

If Visual Studio .NET is unable to connect using this UNC path, you get an error message asking you either to retry using a different UNC path or to try to open the project using FrontPage Server Extensions. If you are hosting your project on your local workstation, the fact that Visual Studio .NET automatically creates the wwwroot$ share upon install can make your life easier (assuming you've added yourself to the VS Developers group). However, if you want to host your project on a remote server, you will need to make sure this wwwroot$ share is properly configured or manually specify another path. You also have the option of installing the Visual Studio .NET Server Components to the remote server on which you wish to do your development.

FrontPage and UNC performance

UNC is the preferred access method primarily because it performs much better than FrontPage Extension's access. This shouldn't come as much of a surprise considering that FrontPage file transfers are done over the slower HTTP. As a result, if you have a choice between using UNC and FrontPage Extensions, it's preferable to use UNC. Another reason to choose UNC is that FrontPage Extensions have traditionally had security problems. If, however, you need to change Visual Studio .NET's default access method, you can do so. This option can be changed via Tools Options Projects Web Settings, then setting the Preferred Access Method to FrontPage.

TIP: While you have the option to use either a UNC file share or FrontPage Extensions for your project, FrontPage Extension's access is slower.

Even if you intend to use Visual Studio .NET (which does much of the deployment automatically) for web service development, it's still important to understand how this process works so that you can troubleshoot your web services. Let's start by taking a closer look at how IIS must be configured to support ASP.NET web services.

Deploying a Web Service Directly to IIS

An ASP.NET web service consists of a collection of resources (.asmx web services, global.asax, configuration information, compiled components stored in the \bin directory, and so on) that run as a so-called IIS virtual application. IIS allows you to divide an instance of a web server into multiple separate virtual applications. Each of these virtual applications has its own set of application mappings, debugging options, and configuration options like script timeout duration and session state timeout. This separation, particularly separation of the application mappings, makes virtual directories good containers for ASP.NET applications. When you create a web service project using VS.NET, this virtual application configuration can be done automatically, but if you're developing without VS.NET, you'll need tools like the Microsoft Management Console (MMC) snap-in or the command-line scripts included with IIS, as explained next.

The most common way to create a new virtual application is to create a new instance of a web site in IIS. By default, the root folder of the new web site will be configured as a virtual application, known as the application root, which can contain other virtual applications.

Another way to create an application root is to mark a folder (virtual or physical) within an IIS web site as an application. This will define the folder as the root of an application.

The most common way to create a virtual application in IIS is through the Internet Services Manager, a snap-in for the Microsoft Management Console. To create a virtual application from an existing directory, follow these steps:

  1. Locate the folder you wish to convert in the Internet Services Manager snap-in. We used a folder called DNSService in Figure 2-12.
  2. Figure 2-12. The IIS Management Console

     

  3. Right-click the folder and select Properties.
  4. Mark the folder as an application by clicking on the Create button of the Directory tab of the folder's Property dialog. (See Figure 2-13.)
  5. Figure 2-13. Configuring the virtual directory

     

  6. Click OK to accept the change.

The folder is now configured as an IIS virtual application. You can now manually add a \bin directory.

The \bin directory is the first place that .NET looks for compiled assemblies, and so every ASP.NET web service should have a \bin directory located directly beneath the application root folder. If one is not automatically created for you by a tool like VS.NET, you can create one manually by using Windows Explorer to navigate to the application's root folder (called DNSService in the previous example) and creating a new folder called root.

Remember that the location of the \bin directory is always relative to the virtual application root. Because IIS allows you to have nested virtual applications, sometime figuring out which \bin directory goes with which application can be confusing. For example, consider Figure 2-14, and let's assume a code-behind .asmx page resides in the folder named dir2. If the virtual directory named store is configured as a virtual application, then .NET will attempt to find the associated code-behind assembly in the \bin directory associated with the store virtual application (www.yyz.com\store\bin). If, however, the store virtual directory is not configured as a virtual application, .NET will look in the \bin directory located at www.yyz.com\bin.

.NET always looks for the \bin directory located directly underneath the application root. If you start seeing .NET error messages like "Could not create type `xxx'", it's probably due to a problem with the way you've configured your virtual application.

Figure 2-14. \bin directory locations

 

Example deployment

To take advantage of the compiled code model for our DNSLookupService example, create an .asmx page with the following single line:

<%@ WebService Language="C#" Class="DNSLookupService"%>

and save it as DNSLookupService.asmx. When this page is accessed, .NET looks through the assemblies in the \bin subdirectory of the virtual application for one containing the class DNSLookupService. If an application makes use of multiple assemblies in the \bin directory, you need to specify the assembly that contains the DNSLookupService by adding its name to the Class attribute value as follows:

<%@ WebService Language="C#" Class="DNSLookupService, MyAssembly"%>

This line tells .NET to search the assembly MyAssembly for the class DNSLookupService. This .asmx page will return an error, however, until you compile the assembly and copy it to the \bin directory. Do this by putting the C# code into another file; for this example, call it DNSLooupService.asmx.cs, using the same naming convention that Visual Studio uses by default. We can then compile this source code from the command line using a command like the following:

csc.exe /out:bin\DNSLookupService.dll /target:library /r:System.Web.Services.dll DNSLookupService.asmx.cs

Using the .NET Compilers

If you develop your web service code as inline code, you will eventually need to compile it. The .NET SDK comes with a command-line compiler for each of the .NET languages that ships with the SDK. The .NET compilers, located in the \WINNT\Microsoft.NET\Framework\[version] directory, where [version] is the version number of your instance of the .NET Framework (mine is v1.0.3705), are listed in the following table.

.NET Language

Compiler

C#

csc.exe

VB.NET

vbc.exe

JSCRIPT.NET

Jsc.exe

There are several options for compiling a C# program into an assembly. If you're using Visual Studio, select "Build Solution" from the Build menu or use the shortcut Ctrl-Shift-B. Visual Studio .NET will compile your application into an assembly and place it into the \bin directory, usually under a subdirectory called debug or release depending on your settings. If you're compiling from the command line, use the csc.exe compiler to create your assembly, as shown in the following command:

csc.exe /out:bin\DNSLookupService.dll /target:library /r:System.Web.Services.dll DNSLookupService.asmx.cs

TIP: This command assumes that you are running the compiler from the directory on your web server that contains your C# source file, and that you have created a \bin subdirectory. For this command to work properly from any folder, include the compiler in your PATH environmental variable. In Windows 2000, this is done via Control Panel System Properties Advanced tab Environment Variables System Variables, and adding \WINNT\Microsoft.NET\Framework\[version] to your PATH variable. Alternatively, if you have Visual Studio .NET installed, there is a menu option under Start Programs Visual Studio .NET Visual Studio .NET Tools called Visual Studio .NET Command Prompt, which will open a command prompt window with the proper variables set for running the VS.NET tools.

The output from the previous command is shown in Figure 2-15.

Figure 2-15. Compiling from the command line

The compilation command tells the compiler to compile our source file DNSLookupService.asmx.cs into an assembly called DNSLookupService.dll. The /out: switch allows you to specify the output name and location for the compiled assembly. The /target: switch (which can be abbreviated as /t:) allows you to specify whether the output should be a console executable, Windows executable, library (DLL), or module. In our example, we want to build a DLL, so we've specified the library option, which forces the compiler to build our assembly to the \bin subdirectory (as specified with the /out switch).

The .NET compilers have a number of command-line switches. Some of the more useful ones are listed Table 2-1.

 
Table 2-1: .NET command-line compiler switches

Switch

Description

/out:<file>

Specifies the name and location for the output file. The default action is for the compiler to derive the output name from the source filename.

/target:<type>

The target switch (short form, /t:) specifies the type of output file (types include exe, winexe, library, module).

/define:<symbol list>

Defines conditional compilation symbols; similar to using the #define xx statement in your program.

/doc:<file>

Specifies the output XML documentation that is created using any XML comments in your source code.

/recurse:<wildcard>

Specifies the names and locations of files to compile. For example, /recurse:dir1\dir2\*.cs compiles any files in and below dir2.

/reference:<file list>

The reference switch (short form, /r: ) specifies a list of assemblies (which must contain assembly manifests), separated by commas or semicolons, which will be made available for use at compile time. If you reference a file that itself references another file, both files must be included in the reference file list. This is also true for assemblies that contain classes that inherit from classes in other assemblies.

To import metadata from a file that does not contain an assembly manifest, such as a module, use the /addmodule switch.

/addmodule:<file list>

Same as /reference, but used for modules. Modules do not contain assembly manifests.

/win32res:<file>

Adds a Win32 resource file to your output file. A Win32 resource can contain version information that helps to identify your application to the Windows Explorer.

/win32icon:<file>

Allows you to specify an icon to be used by the Windows Explorer for the output file.

/debug[+|-] or:

/debug:[full|pdbonly]

Specifying + forces the compiler to write debugging information to a program database (.pdb) file. Specifying - causes no debug information to be written.

The /debug:full switch enables attaching a debugger to the running program. The /debug:pdbonly switch displays the assembler only when the program is attached to the debugger.

/optimize[+|-]

The optimize option (short form, /o) enables or disables compiler optimization for smaller and faster code. By default, optimization is enabled.

/incremental[+|-]

The incremental option (short form, /incr), incremental compilation compiles only those methods that have been modified since the last incremental compile. Information about the state of the previous compilation is stored in the <output_file_name>.dbg and <output_file_name>.incr files. These files are created the first time this option is used and henceforth are used for incremental builds.

In an incremental build, the /doc option is ignored.

Output files created with the incremental option may be larger than those created without.

Like most Windows command-line tools, the .NET compilers display a complete list of available options with the following command:

csc.exe /?

Once the source code has been compiled into an assembly and copied to the \bin directory, it's ready to be used by .NET. Unlike COM objects, which must be registered using regsvr32.exe before they can be used, .NET requires no such explicit registration.

In the next chapter, we cover some of the different ways of consuming web services using .NET applications.


1. If you're interested in learning more about WSDL, you can view the current spec at http://www.w3.org/TR/wsdl.html. Be forewarned that reading this document, while an excellent way to learn the intricacies of WSDL, is a sure cure for insomnia. Alternatively, you can read Chapter 3, in which we discuss the parts of the WSDL specification.

Back to: Programming .NET Web Services


oreilly.com Home | O'Reilly Bookstores | How to Order | O'Reilly Contacts
International | About O'Reilly | Affiliated Companies | Privacy Policy

© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com