20100525 学习记录:关于发布网站嵌套的bin文件夹 和 Could not create type....报错 = =+...


这还是上周的事情了,现在才总结。我的标题取的名字似乎也不准确 - =

 

事情缘由是我需要在我们网站下的根目录里放一个新的文件夹里面装webservice,并且这个webservice要用url可以独立访问(废话 - =)

结果我本地调试成功后放到服务器上部署时就是死活不好用,报错:

Could not create type 'Service'.

<%@ WebService Language="C#" CodeBehind="~/App_Code/Service.cs" class="Service" %>

......

 我检查了n遍确认我的codebehind木有写错,class也木有写错,因为我右键页面的.asmx文件→view code也能顺利的找到对应的.cs文件,所以应该不是这里找不到才对。但是手头上有一个好用但是代码超级简单的ws的例子放在服务器上就可以用 = =+ 我比对2者的区别之后,再加上搜索得来的信息判断错误就是页面找不到我的.cs文件导致的,因为我的程序跟他们最大的区别就是他们把代码直接写在.asmx文件中了 - = ......

可是我的指向明明也没有错,那是为什么呢?

 

先来总结一下,网络上搜索得来的关于这个报错的解决办法吧~ =v=

话说有这个错误的人真是不在少数,少部分幸运找到根源的都是一些低级错误(你以为你错误高级.... - =):

1.  页面里的class值不对,应该注意加上命名空间的名字

eg: 如果我的Service.cs文件里有个明明空间叫WS,那么class里面就应该写为WS.Service,嗯

2. codebehind就不用说了吧.... 其实这个一般都是默认生成的...

3. 又是万恶的IIS!!记得一定要用2.0发布,选1.0的8行!在IIS的asp.net页签里面设置

4. 发布文件夹在IIS中必须create成application,不然看不到

5. 居然也有在IIS中的Edit Configuration里,把Authentication改成none好用的.... 8理解....

6. 哦,对了,还有,这个webservice有专门new webservice project的选项... 切记...

7. 还有一个properties的设置。这个我的VS版本里没有这个功能,所以没法尝试,下面会给出具体说明,偶就不详细说了

8.........当然,上面这么多种方法仍然解决不了很多人的问题包括我 = = ,很多人最后放弃ws了 orz,但偶发挥小强精神最后终于找到了根源(少废话!((‵□′)) )

好吧,先给出第7条的详细解释,然后再解释我的.... =。=

 

 

How do I – Solve the “Could not create type WebService.Name” error when trying to deploying a web service?

OK, so you wrote a web service and you may even have tested it and everything worked fine. So the you did some "cleanup" and tried to deploy the web service. It compiles and deploys just fine, but when you try to invoke and hit the service you are presented with the following error:

Server Error in '/' Application.

Parser Error

Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.

Parser Error Message: Could not create type 'WebServices.Candidates'.

Source Error:

 

Line 1: <%@ WebService Language="C#" CodeBehind="Candidates.asmx.cs" Class="WebServices.Candidates" %>


Source File: /Candidates.asmx    Line: 1

 

So just how do you solve this problem?

Here's my checklist of things to check when having trouble deploying web services:

  1. Check that IIS is using ASP.NET 2.0.
    1. Begin by starting up the Internet Information Services manager.
    2. Expand "Web Sites".
    3. Expand your web site e.g. "Default Web Site".
    4. Locate the Virtual Directory to which the web service was deployed and right click it.

    1. On the popup menu, click "Properties".
    2. On the Properties window, select the "ASP.NET" tab.
    3. Ensure that the APS.NET Version is set to 2.0.x and not 1.1.x.
    4. If it is set to 1.1.x, set it to 2.0.x and retry your web service.
  2. Ensure your Visual Studio build properties are set correctly.
    1. Locate the .asmx file in your Solution Explorer pane and right click it.

    1. On the popup menu, click "Properties".
    2. Ensure that the Build Action is set to "Content".

    1. Locate the code behind (.cs or .vb) file in the Solution Explorer and right click it.

    1. On the popup menu, click "Properties".
    2. Ensure the Build Action is set to "Compile".

    1. If either of these weren't set correctly, make the correction, recompile, redeploy and retest.
  3. Ensure ASP.NET 2.0 is an Allowed web services extension.
    1. Open the IIS Manager.
    2. Expand your computer.
    3. Click the "Web Service Extensions" option.
    4. In the right hand pane, locate the "ASP.NET v2.0.x" entry and ensure that its Status is "Allowed". If it is not allowed, the "Allow" button on the left will be enabled. Click it to change the setting.

    5. If it was not allowed, correct the setting and retry your service.
  4. Check for the WebMethod attribute.
    1. Review your code and ensure that you have the [WebMethod] attribute set for all web methods in the service. This does not mean that all methods have to be web methods, but the ones you are trying to consume should have this attribute in its declaration.

  5. Ensure the .asmx and code behind file match definitions.
    1. Open your code behind (.cs or .vb) file.
    2. Look at the web service declaration at the top.

    1. In our example, ensure that #2 and #3 match. If they don't, correct the problem.
    2. Next note the namespace at #1.
    3. Now open the .asmx file. This can usually be done by double clicking it in the Solution Explorer, but if you're not able to get it to open through the IDE, open Windows Explorer, navigate to the file, right click it and select Open in Visual Studio to work around the problem.
    4. Now look at the code.

    1. Note the value of Class in this case is "WebServices.Candidates". The Class value should be the full namespace value as well as the class name. Given our code behind file's values, in this case, the Class value should have been "Crowe.PartnerNomination.WebServices.Candidates", but instead it is just "WebServices.Candidates". This is a common issue when reworking already written web services into a namespace hierarchy. For some reason the .asmx file does not always reflect the changes made which then causes the error message at the beginning of this post.
    2. Change the Class value, recompile, redeploy and retest.

Later
C

 From:http://www.cjvandyk.com/blog/Lists/Posts/Post.aspx?ID=133

 

这位狠人总结的相当全面了,赞!!!但是仍然解决不了我的。。。 = =

于是不废话了,偶当时受这本书启发《Programming .NET Web Services》 封面上一只奇怪的鸟... 这本书太赞了!!!!!!!!!搞的我都想买了 - =

是里面的一段话提示了我:

 

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.

 

 

于是偶瞬间想通,不就是差这个问题么,是页面找不到bin文件夹里的dll的原因!!!!!

为啥找不到?因为根目录下已经有一个bin文件夹了,我的ws默认去找了根目录的bin文件夹,结果当然找不到它要的dll.

其实如果没有重名的话,把bin目录合并就可以了,可是因为ws生成的dll是App_Code.dll ,根目录已经有一个重名的了,所以偶不能凑合把ws的扔到根目录。于是我剩下两条路:

1. 把ws的代码放入根目录的程序一起作为一个工程编译——根目录主要是asp开发的,有少量.net重写代码。不想把ws跟网站混在一起,此路不通

2.继续研究为啥页面不找自己的bin而找根目录。。。 (┬_┬)

 

还是这本英明无比的书,下面紧接着又写——

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

 

 

 

 默认是找自己的目录,找不到才找根目录的,可我的正相反,不找自己的找根目录的,而且我的ws目录也发布成application了。。。

在博问上提了问题,大家给出的建议:

1. 合并工程...

2. 作为作为一个application  相当于一个子站点发布?

3.单独发布网站,绑定一个子域名————完全没理解这位仁兄的意思 = =||||

 

可能是我没理解他们的意思,但是觉得虽然上面说的貌似不全中,但是指点了我,最后偶发现指定虚拟路径就可以了。不过我只是给ws文件夹了一个名字(大概就是所谓的子域名吧!)并没有作为网站发布,还是原来发布为application的状态(区别到底是什么 = =+)

这样,我的ws就能成功的找到自己文件夹下的bin了.....

 

唉,我想网上跟我犯同样错误的人一定n多..............

最后,列一下偶搜索的无数链接中有点用的几个链接,严重感谢《Programming .NET Web Services》!!!

 

http://www.cjvandyk.com/blog/Lists/Posts/Post.aspx?ID=133

http://social.msdn.microsoft.com/Forums/zh-TW/asmxandxml/thread/838706ac-6763-455b-95bd-1432a9ccc6be 

http://forums.asp.net/p/1328663/2659836.aspx

http://oreilly.com/catalog/prognetws/chapter/ch02.html (http://oreilly.com/catalog/prognetws/chapter/ch02.html#77068)

 

提的2个问题,非常感谢回答问题的大家 (┬_┬)

http://space.cnblogs.com/question/14455/

http://space.cnblogs.com/question/14467/ 



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.asaxCustomizable to handle application-level events (e.g., Application_OnStart).

HelloWorldService.vsdiscoAn 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.configAn 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

DescriptionAdds 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:

  • Description

MessageName

EnableSession

CacheDuration

TransactionOption

BufferResponse

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:

  • Disabled

NotSupported

Supported

Required

RequiresNew

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.

Figure 2-12. The IIS Management Console

 

Right-click the folder and select Properties.

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.)

Figure 2-13. Configuring the virtual directory

 

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

 

 

 

Web Service开发指南

 

 

 开发说明:
1. 创建Web Service,并编译:
开发方法与普通的动态库的开发一样,只是方法前加说明行性的属性,如:[WebMethod(Description="插入数据")]
public string InsertData(string strName){
……函数功能
}
2. 通过IE进行测试:
直接在IE里通过URL调用即可,如http://localhost/DBOperWS/DBOper.asmx
   如果正确,则显示如下界面,列出web服务对外提供的接口,以及说明,单击相应的函数,则可以进行功能测试
·
3. 建立一个Web Service的客户,并保存wsdl文件:
建立一个Web Service的客户,让它得到你提供的这些服务,保存wsdl文件用以在开发时显示智能化的帮助,通过下面的方式,进入.net的dos界面,键入命令语句: ,
 语法:disco /o: wsdl文件存放路径 服务的URL,如
disco /o: D:\DBOper.wsdl  //localhost/WebService1/Service1.asmx?WSDL
4. 生成代理类cs文件
同样在Dos下执行如
wsdl /out:D:\myWebService1.cs http://localhost/WebService1/Service1.asmx
的语句完成
5. 编译代理类,生成dll动态库
执行类似如下语句可完成
csc /out:D:\myWebService1.dll /t:library /r:System.XML.dll /r:System.Web.Services.dll myWebService1.cs
6. 服务发布:
将以上生成的服务dll,wsdl,discomap三个文件放在要引用的某个虚拟目录下即可。
7. 示例:详见示例工程DBOperWS
使用说明:
VS.Net调用服务
1. 添加引用:
添加web引用,在网络上找到要引用的服务,并给定名字,如"MyDBService",添加成功后,服务就自动具有了本地类的namespace,如TestWebService.MyDBService
 TestWebService是我们的测试工程namespace。
2. 调用:
代码中的调用和普通的dll调用没有任何区别,就象是在使用本地类一样。如:
MyDBService.DBOper m_dbo = new TestWebService.MyDBService.DBOper();
Result.Text = m_dbo.GetName(this.TextBox1.Text,this.TextBox2.Text);
3. 示例:详见示例工程TestWebService  

 

 

 

 

将多个WEB应用程序放在同一个虚拟目录中的办法 

买了一个空间:http://www.beinet.cn/blog/
却不支持自建虚拟目录,那么只能放置一个WEB应用程序了,那怎么能行?
试验了一下,终于想出一个好办法:
为每个应用程序新建一个目录,除了bin目录、web.config、Global.asax等初始化文件外,其它的文件全部放入这个目录

BIN目录里的文件放入根目录的BIN目录,注意不同应用程序的DLL文件不要重名啊。
多个应用程序的web.config、Global.asax文件进行组合,如果有冲突的地方自行想办法修改成不冲突,也保存到根目录中

经过上面的处理,应该没有问题了,在我这里已经测试成功了,哈哈。

http://blog.csdn.net/youbl/archive/2006/11/20/1399605.aspx 


 

 

指定虚拟目录的方法....(偷懒用别人写好的 = =)

 

1.在你的IIS中选中指向d:\\a的虚拟目录(下文我们称之为站点a),你的设置应该是服务器的根目录指向d:\\a的吧!

2.反正都一样,选中站点a后点右键,选中“新建”>>“虚拟目录”,弹出的对话框中,虚拟目录名就设成b
(即与网站b指向的目录d:\\a\\b的目录名一样,实际上此时网站b的文件夹不一定要放在d:\\a中,为了避免混淆我也建议你不要放在d:\\a中,
放成d:\\b的目录反而更好更安全)。新的虚拟目录指向网站b的目录就行了。

3.这时你网站a的目录下面会有一个名字为b的虚拟目录出现了,访问的时候和访问正常目录一样,但服务器是把http://websit_a/b目录当成一个站点来看待的。
 

 

转载于:https://www.cnblogs.com/neru/archive/2010/05/25/1743238.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值