Writing web services in c. WebService attribute parameters


In these times of rapid development of the Internet, the problem of communication between data located in different parts of the globe on different platforms and in a variety of data sources arises more and more often. And this problem is increasingly increasing with the growth of companies using the Internet and web applications in their business. Microsoft .NET web services solve the problem of such communication.

Without going into the depths of the theory of web services and questions about how and why they work, this article is entirely devoted to the issue of creating web services. Over the next few pages, many aspects of creating web services will be discussed and a small application will be written that uses web services technology.

So, what does a web service look like for a developer? First, the web service file has the extension asmx. Second, creating a web service is not much different from creating a web form in the .NET Framework. Third, the web service file must begin with the WebService directive. Fourth, the web service class can (but should not) be a descendant of the System.Web.Services.Webservice class. Well, the last thing (for now) is that a method called via the web must have the WebMethod attribute.

Based on the above, let's start implementing a web service (all examples in this chapter are based on codebehind and made using Visual Studio.NET).

Let's create a new application in VS.NET and add the web service file nw.asmx to it (or open notepad and create 2 files - nw.asmx and nw.asmx.cs).

The nw.asmx file contains a single line - the WebService directive, which states that this file is indeed a web service. This file will not change, so you can look at it and forget it for now :).

All web service code will be located in the codebehind file nw.asmx.cs. Initially, this file (created in Visual Studion.NET) looks like this:

Using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Web; using System.Web.Services; namespace WebServicesExample ( /// /// Summary description for nw. /// public class nw: System.Web.Services.WebService ( public nw() ( //CODEGEN: This call is required by the ASP.NET Web Services Designer InitializeComponent(); ) #region Component Designer generated code //Required by the Web Services Designer private IContainer components = null; /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() ( ) /// /// Clean up any resources being used. /// protected override void Dispose(bool disposing) ( if(disposing && components != null) ( components. Dispose(); ) base.Dispose(disposing); ) #endregion // 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 // // public string HelloWorld() // ( // return "Hello World"; // ) ) )

As you can see, the guys from Microsoft immediately took care of novice programmers and put many generations of teachers out of work, who were terribly fond of starting their stories with the cry “Hello, World!” :). Now you can create this code yourself without any effort by simply commenting out the declaration of the HelloWorld() method :).

Well, let's do it (in vain, did the guys try? :) and launch, after compiling the project, our web service for execution (open the page http://localhost/WebServicesExample/nw.asmx in the browser). The following page will be drawn in the browser:


ASP.NET uses the DefaultWsdlHelpGenerator.aspx template file to display the web service, located in the %SYSTEM_ROOT%\Microsoft.NET\Framework\\CONFIG folder. On the displayed page of the web service there is the name of the web service (marked 1), a link to the description of the service (2) (this link will be of interest to us in the future when creating clients for the web service) and a list of web methods declared in the web service (3). The rest of the page is devoted to how bad it is to use the default namespace for a web service, and recommendations to urgently correct this omission :). No problem, and while this is still fresh in our minds, let’s do as recommended - add the WebService attribute with the Namespace parameter to the web service class:

So, let's move on to the SayHello web method description page (just click on the SayHello link on the web service description page).


As you can see, it also contains the name of the web service, a link to the first page of the web service, and the name of the web method. In addition, the page contains a form intended for call web method via a GET request (this rule is not followed if the web method cannot be called in this way) and example requests for calling this web method using SOAP, HTTP POST (if such a call is possible) and HTTP GET (if such a call is possible). Examples of responses for calling a web method are also provided.

If you wish, you can now test the method by clicking on the Invoke button (I no longer have such a desire :)). Let's move on to creating more useful web methods.

I thought for a long time which web method to offer first for study. Something simple that returns a single value, or something more complex with DataSets? And I decided to show as many capabilities of web services as possible in the first example.

So, the task is that a trading company that has a database with all the data it needs for work (well, how can we do without Northwind :)) opens a branch in another region/city/end of the globe. In this case, a natural need arises for branch employees to provide access to the company’s database. But there are only restrictions - the database is centralized and a copy cannot be created, and in the branch there are only a couple of computers that can only access the Internet. But they still need to work with the database somehow... :). At least be able to receive orders from specified clients.

The task has been set, now it is necessary to implement it. To begin with, we will create a web service that returns a DataSet with the orders of the specified client, and then we will write 2 clients for this web service, one in DHTML for IE, the second in ASP.NET (after a while the branch got rich and bought itself a computer for the web server :)).

To obtain the data we are interested in, we will use a slightly modified CustOrdersOrders stored procedure:

CREATE PROCEDURE CustOrdersOrdersDetails @CustomerID nchar(5) AS SELECT OrderID, OrderDate, RequiredDate, ShippedDate FROM Orders WHERE CustomerID = @CustomerID ORDER BY OrderID SELECT Products.ProductName, .UnitPrice, .Quantity, .Discount, .OrderID FROM INNER JOIN Products ON . ProductID = Products.ProductID where OrderID in (SELECT OrderID FROM Orders WHERE CustomerID = @CustomerID)

The web method that returns data for the selected client has the following form:

Public DataSet GetCustOrders(string CustomerID) ( SqlConnection myConn = new SqlConnection("server=localhost;database=Northwind;uid=sa;pwd=Manowar"); SqlDataAdapter myData = new SqlDataAdapter("CustOrdersOrdersDetails", myConn); myData.SelectCommand. CommandType = CommandType.StoredProcedure; myData.SelectCommand.Parameters.Add(new SqlParameter("@CustomerID", SqlDbType.Char, 5)); myData.SelectCommand.Parameters["@CustomerID"].Value = CustomerID; DataSet ds = new DataSet(); myData.Fill(ds); ds.Tables.TableName = "Orders"; ds.Tables.TableName = "OrderDetails"; ds.Relations.Add(ds.Tables.Columns["OrderID"], ds. Tables.Columns["OrderID"]); return ds; )

Nothing extraordinary - the DataSet is filled with the data obtained by calling the stored procedure we created, the relationship between the tables is added to it, and then the result is returned. Well, the natural WebMethod attribute for the method means that we can call this method from the web service.

Let's test our work using the web service page. Open the web service page in your browser (for me it is http://localhost/WebServicesExample/nw.asmx), click on GetCustOrders to go to the web method page, enter the client ID from the Northwind database (for example ALFKI) in the input field and click the Invoke button . Will open new page, containing XML. This is the result of calling our web method - the DataSet we need with the list of customer orders ALFKI. Below are excerpts from the results page.

… 10643 1997-08-25T00:00:00.0000000+03:00 1997-09-22T00:00:00.0000000+03:00 1997-09-02T00:00:00.0000000+03:00 10692 1997-10- 03T00:00: 00.0000000+03:00 1997-10-31T00:00:00.0000000+02:00 1997-10-13T00:00:00.0000000+03:00 … Rössle Sauerkraut 45.6 15 0.25 10643 Chartreuse verte 1 8 21 0.25 10643 …

Let's take a closer look at what the web method returned to us.

From the above code we can draw the following conclusions:

  • The returned result is of type DataSet (this can be seen both from the name of the root node and from the line in the schema description).
  • The returned DataSet contains 2 tables – Orders and OrderDetails.
  • In the schema, complete information about the tables is available, as well as a record of the relationship we created between the tables.

Of course, if to call a web method we had to go to its description page, manually set the parameters for calling the web method and call it, this would be of little use. As I already said, web methods can be called using HTTP GET, HTTP POST and SOAP requests.

Now we will look at the possibilities of working with the created web service using HTTP GET (or HTTP POST) from the Internet Explorer browser (the same case when employees of a branch of our hypothetical company have nothing but a computer with Internet access), as well as a SOAP call with using a small program written in C#.

How is this done? Let's use the Microsoft.XMLHTTP object, which allows us to send and receive data using GET or POST requests. We create a request to the corresponding web method of our web service, pass (if necessary) parameters and display the XML code received in response on the page using a small xsl file.

Below is the code for orders.xsl (intended to display the result) and DhtmlClient.htm (the main file).

Order:
Date:
Ship:
Product:Price:Quantity:Discount:
var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); var objStyle = new ActiveXObject("MSXML.DOMDocument"); objStyle.async = false; objStyle.load("orders.xsl"); var SOAPRequest = new ActiveXObject("MSXML.DOMDocument"); SOAPRequest.async = false; var SOAPResponse = new ActiveXObject("MSXML.DOMDocument"); SOAPResponse.async = false; function getOrders() ( // xmlhttp.Open("GET", "http://localhost/WebServicesExample/nw.asmx/GetCustOrders?CustomerID=" + // document.all.client.value, false); xmlhttp.Open ("POST", "http://localhost/WebServicesExample/nw.asmx/GetCustOrders", false); xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xmlhttp.send ("CustomerID=" + document.all.client.value); SOAPResponse.loadXML(xmlhttp.responseXML.xml); document.all.orders.innerHTML = SOAPResponse.transformNode(objStyle.documentElement); )
Client

Open the DhtmlClient.html file in your browser, enter the client code in the input field (ALFKI works just fine) and click the “Orders” button. The JavaScript getOrders() method will route the request via HTTP POST to the web method and then transform the returned result using the orders.xsl stylesheet and output it to the page (if you want to test calling the web method via HTTP GET - comment out the first line of the method and comment out the next three ). This will give you a page that looks like this:


Now let's look at calling a web method from a .NET application. To call web services, a .NET application uses a proxy class generated either using the wsdl command line utility or using Web additions Reference to a Visual Studio .NET project. The proxy class generated this way contains quite a lot of code. But what is valuable to us is that it contains methods for calling the web methods that interest us.

Let's write a small Windows Forms application that calls the GetCustOrders method of our web service. In Visual Studio.NET we will create Windows application. Let’s add a link to the web service to the created application (menu Project – Add Web Reference…). In the address bar of the window that opens, enter the address of our web service (http://localhost/WebServicesExample/nw.asmx):


After clicking the Add Reference button, Visual Studio.NET will add a reference to the web service to the project and automatically generate a proxy class for calling web methods.

For those who do not use Visual Studio.NET, creating a class proxy is also easy. For this, as I already said, the wsdl command line utility is used. Full description The use of this utility can be found in MSDN, but here I will only show the call to this utility to generate a proxy class for our web service.

Wsdl /l:cs http://localhost/WebServicesExample/nw.asmx

This will create a nw.cs file containing the proxy class we need.

Let's continue creating a Windows client for the forum. Let's place on the form an input field for entering the client code, a DataGrid for displaying the received data and, naturally, an “Orders” button. In order for the data we are interested in to be displayed in the DataGrid, we need to insert only 2 lines into the OnClick handler of the button:

Private void btnOrders_Click(object sender, System.EventArgs e) ( localhost.nw orders = new localhost.nw(); dgMain.DataSource = orders.GetCustOrders(txtClient.Text); )

Launch the created application, enter ALFKI in the input field and click the "Orders" button. The DataGrid will display the DataSet obtained as a result of the call with the data we are interested in:


As you can see, creating and using web services in .NET is not such a difficult task.

Now let's look at the structure of a web service, as they say, step by step.

In the first (and only, if you write using codebehind technology) line of the asmx file, as in the case of an aspx file, there is an ASP.NET directive indicating the type of this file, the language in which the code is written, and the name of the class for file. For example, the line for the web service we wrote is as follows:

where the WebService directive indicates that this file is a web service, and the attributes Language=”c#” and Class=”WebServicesExample.nw” indicate that the web service class is written in C# and the full class name is WebServicesExample.nw.

A web service can consist of many classes. However, only one class in a web service can have methods marked with the WebMethod attribute (which can be called via SOAP requests).

The WebMethod attribute has six properties that affect the operation of the web method. Let's look at them:

Description

This property serves for a general description of the web method. You can assign any text string to this property. The value of the Description property is displayed on the web service description page. Returning to the example discussed earlier, we will describe the getAuthors web method as follows:

Public DataSet GetCustOrders(string CustomerID)

Let’s compile our project and now take a look at the web service description page:


As you can see, its description is now displayed under the GetCustOrders method.

EnableSession

This property allows you to enable session support. By default, support for sessions in web services is disabled. To enable it, define a web method like this:

If, when declaring a web service, you derived it from the System.Web.Services.WebService class, then you automatically get access to the public Application, Context, Session, Server and User properties, which have the same meaning as similar ASP.NET web properties forms If you created the web service class in some other way, that’s okay. You can still access the above properties using the corresponding properties of the static HttpContext.Current.

Let's look at working with Application and Session objects using an example. Let's write a small web service with two web methods - setSessionVar (takes 2 string parameters - the name of the session variable and its value, and sets the session variable) and getSessionVar (takes a string parameter - the name of the session, and returns the value of the session variable):

Public void setSessionVar(string name, string val) ( Session = val; ) public string getSessionVar(string name) ( return (string) Session; )

Don't forget that ASP.NET identifies a session by the session ID stored in the cookie. So the above example will work successfully from the web service page, but if you try to call the methods of this web service from a .NET application through a proxy class, you will be surprised to find that calling the getSessionVar method does not return any value, since the use web services using a proxy class by default does not use cookies to save information.

In order for a .NET application to work with a session using a web service, it is necessary to add cookies to the code that calls the web service methods. And it's not as difficult as it seems at first glance :).

Let's create a Windows application, add a Web Reference to the previously created web service and add an interface for setting session variables using the setSessionVar method and getting the value of the session variable using getSessionVar. Let's also declare a private cookie variable of type CookieContainer into the class (the CookieContainer class is described in the System.Net module). Let's initialize this variable in the class constructor. Now, in order for calls to web service methods to be made in the same session, you just need to assign the cookie value to the CookieContainer property of the web service class before calling the web method.

The complete code for calling web methods using cookies is presented below (the proxy class generated for the web service is named localhost1.testService1):

Private CookieContainer cookie; public Form1() ( InitializeComponent(); cookie = new CookieContainer(); ) private void btnSetValue_Click(object sender, System.EventArgs e) ( localhost.session session = new localhost.session(); session.CookieContainer = cookie; session. setSessionVar(txtSessionName.Text, txtSessionValue.Text); ) private void btnGetValue_Click(object sender, System.EventArgs e) ( localhost.session session = new localhost.session(); session.CookieContainer = cookie; txtSessionValue.Text = session.getSessionVar (txtSessionName.Text); )

MessageName

The MessageName property allows you to assign a name to a web method that is different from the one that was assigned to it when the web service class was written.

It is possible to create web methods with the same names in a web service. But when you try to view the page of such a web service, an error will be generated. The MessageName property is used precisely in these cases.

Suppose, in addition to the GetCustOrders web method with one parameter (client code), we have declared another GetCustOrders method, which, in addition to the client code, also accepts a date fork and returns a DataSet with information about orders whose date is between the specified dates

Public DataSet GetCustOrders(string CustomerID) ( ... ) public DataSet GetCustOrders(string CustomerID, DateTime startDate, DateTime endDate) ( ... )

Now, even though both web methods have the same name, it is still possible to use the web service page. In this case, in the proxy class, both methods will naturally be defined with the name GetCustOrders.

TransactionOption

Web services have limited support for transactions. You can use the TransactionOption property to control how your method uses transactions. This property can take the following values:

The word “restricted” means that a web service can originate a transaction, but cannot be a participant in another transaction. If a web method is called with TransactionOption set to Required or RequiresNew, and another web method is called in it with the same settings, each of these methods initiates its own transaction.

By default, the TransactionOption property is set to Required.

When the method completes normally, the transaction is considered completed. To abort a transaction, throw an exception. In the web method there is no need to call the SetComplete and SetAbort methods.

CacheDuration

To say that caching web services would simply be disingenuous. Caching web services is not easy, but very simple. In short, all that is needed to enable caching of a web service is to use the CacheDuration parameter of the WebMethod attribute indicating the period of time in seconds for which the web service is cached.

Below is an example declaration that caches the return value of the GetCustOrders method for 10 minutes.

Public DataSet GetCustOrders(string CustomerID)

BufferResponse

The BufferResponse property allows you to control the buffering of the web method response. By default, the execution result is buffered and sent to the client only after it is fully formed. However, if your web method takes a very long time to execute, it might make sense to disable result buffering.

To disable result buffering, use the following web method declaration:

Public DataSet GetCustOrders(string CustomerID)

WebService attribute parameters

A Web service also has three properties that affect its operation. Two of them, Description and Name, work exactly the same as the similar Description and MessageName properties of a web method. The third property, Namespace, allows you to control the namespace in the SOAP message. Let's consider the use of all three properties using the wsauthors web service as an example.

Let's change the web service declaration to the following:

Public class nw: System.Web.Services.WebService

then we’ll compile the web service and look at the description page:


A description of the web service entered in the Description property was added to the page, and the name of the web service was changed. Please note that you now need to access the web service by a new name (you will need to regenerate the proxy class for the web service, and this proxy class will have a new name).

And finally, let’s consider the issue of data types that a web method can take as parameters and return.

Web methods can take as parameters and return as a result any meaningful data types, arrays of these types and structures and classes consisting of these types. To put it simply, a web service can work with any type of data that can be represented in the form of an XDR schema.

Consider the GetCustomer web method, which returns a Customer structure containing information about the customer. First, let's define the Customer class

Public class Customer ( private string id; private string companyName; private string address; public Customer() ( ) public Customer (string id, string companyName, string address) ( this.id = id; this.companyName = companyName; this.address = address; ) public string ID ( get ( return id; ) set ( id = value; ) ) public string CompanyName ( get ( return companyName; ) set ( companyName = value; ) ) public string Address ( get ( return address; ) set (address = value; ) ) )

In principle, nothing complicated - private variables, public properties of a simple type and a couple of constructors. Don't be surprised by the presence of a parameterless constructor, even though it doesn't really do anything, but having a public default constructor is a requirement for serializable classes. In general, our class fully satisfies the requirements imposed on types for use in web services.

Now let's write a web method that returns a variable of this type.

Public Customer GetCustomer(string CustomerID) ( SqlConnection myConn = new SqlConnection("server=localhost;database=Northwind;uid=sa;pwd=Manowar"); SqlCommand myCmd = new SqlCommand("select CustomerID, CompanyName, Address from Customers " + "where CustomerID = "" + CustomerID + """, myConn); myConn.Open(); SqlDataReader reader = myCmd.ExecuteReader(); Customer customer; if(reader.Read()) customer = new Customer(reader.GetString (0), reader.GetString(1), reader.GetString(2)); else customer = new Customer(); reader.Close(); myConn.Close(); return customer; )

Calling this web method on the long-suffering ALFKI client will return the following XML.

ALFKI Alfreds Futterkiste Obere Str. 57

Another question related to returning data from a web service concerns the type of XML code returned by the web method. As can be seen from the previous example, the web method returns data in the form of XML elements with names corresponding to the names that were described in the class description. You can change both the names of the XML elements and return some (or all) of the data as XML attributes.

Let's change the description of the Customer structure a little to illustrate what has been said. Now the CustomerID field will be returned as an ID attribute, and the CompanyName field will change its name to Company.

Public class Customer ( ... public string ID ... public string CompanyName ... )

Now, as a result of executing the previous web method through the web interface, the following XML will be received:

Alfreds Futterkiste Obere Str. 57

Conclusion

Web services are a new type of web applications for creating a level of business logic and connecting heterogeneous applications using common standards - HTTP, XML and SOAP. There are virtually no restrictions on the areas where web services can be used: you can create web services to communicate between different applications or to provide data to your clients. The possibilities for using web services are theoretically limited only by your imagination.

The text of examples of this article can be downloaded

This article opens a course of lessons on WCF technology and is intended primarily for beginners in programming web services.

In this lesson we will create a simple WCF calculator service that implements four basic arithmetic operations, learn how to host the service on IIS and publish it to the server. In addition, we will talk about how to connect to a service from another application in C# or using the free SoapUI program, and also add functionality for calling the service via the web (for example, from a browser or Ajax).

The lesson is designed for beginner C# programmers who have decided to master WCF technology. Experienced developers may find the information in the section on creating endpoints for Ajax useful.

2. Creating a service project

We use Visual Studio 2013 Professional, framework version 4.5.1. Note: With some minor exceptions, there are differences between versions 4.0. and 4.5.1 no, but using the latter is preferable, because adds a useful feature for generating WSDL in one file, but more on that below.

So, let's launch the studio and create a project of the WCF Service Application type in the appropriate section, calling it SampleService.

After creating the project, let's look at the structure of the solution in Solution Explorer:

1. IService1.cs contains a description of the service interface, i.e. a set of methods that our service provides.
2. Service1.svc consists of two parts - service implementation (Service1.svc.cs) and markup (Markup), available in the click menu right click mice.
3. Web.config— service configuration.
4. Folder App_Data We don’t need it yet - we delete it.

First, let's rename the service and its interface, giving them the names Calculator and ICalculator, respectively, and also change the line in the service markup (Calculator.svc file):

Now we will describe the interface of our calculator itself. Let's declare standard arithmetic operations, such as addition (Addition), subtraction (Subtraction), multiplication (Multiplication) and division (Division). We will also add additional method TestConnection returning a string. Using this method, clients will be able to verify that the service is functioning, because... WCF does not provide standard “ping”. All interface methods must be marked with the attribute, otherwise they will not be visible to clients.

As a result, the interface will look like this:

ICalculator.cs

using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; namespace SampleService ( public interface ICalculator ( #region Common Methods /// /// OK string TestConnection(); #endregion #region Arithmetic /// /// addition /// /// Addend 1 /// Addend 2 // / sum double Addition(double a, double b); /// /// subtraction /// /// Reducible /// Subtrahend /// difference double Subtraction(double a, double b); /// /// multiplication /// /// Multiplier 1 /// Multiplier 2 /// product double Multiplication(double a, double b); /// /// division /// /// Dividend /// Divisor /// quotient double Division(double a, double b); #endregion ) )

Now let's implement the interface in the service class:

Calculator.svc.cs

using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; namespace SampleService ( public class Calculator: ICalculator ( #region Common Methods /// /// connection test /// /// OK public string TestConnection() ( return "OK"; ) #endregion #region Arithmetic /// // / addition /// /// Addend 1 /// Addend 2 /// sum public double Addition(double a, double b) ( return a + b; ) /// /// subtraction /// /// Minuend /// Subtrahend /// difference public double Subtraction(double a, double b) ( return a - b; ) /// /// multiplication /// /// Multiplier 1 /// Multiplier 2 /// product public double Multiplication(double a, double b) ( return a * b; ) /// /// division /// /// Dividend /// Divisor /// quotient public double Division(double a, double b) ( return a / b; ) #endregion ) )

The logic of the service has been described; now you need to host it.

The service itself represents a library (in our case, the SampleService.dll file), and to run it as a service you must use one of the methods provided by WCF:

  • 1. Hosting on IIS.
  • 2. Run as a Windows service.
  • 3. Self hosting (the service is designed as a console application that launches the service).

There is no fundamental difference in these methods, so we will choose the simplest option - hosting on IIS. To do this, open the project configuration and select the “Web” tab. You can see the default parameters for yourself, but this is what the settings for our service look like:

The Start Action section determines what will happen when the project is launched in the studio:

  • Current Page (default) – launches the last page opened in the browser. Our service does not yet have configured method urls, so this option is not suitable.
  • Specific Page – launch a specific page.
  • Start External program – launch the specified executable file, which initiates a service, for example, will call a method that needs debugging.
  • Start URL – opens the address specified in the URL field in the browser.
  • Don"t open a page - do not open anything, but wait for a request from a third-party application.

In all cases, the service “starts” in debug mode and behaves like a normal application in the studio, i.e. responds to control points. The last option is convenient because nothing opens in the browser, because... Debugging using a browser is not the best option for a WCF service, but more on that below.

The Servers section determines where the service will be hosted. By default, IIS Express is selected (the version of IIS built into the studio), but we will be advanced and host the service on normal IIS. Of course, for this you need to install IIS in the control panel and enable the necessary components (ASP .NET, Basic authorization and others).

Below the spoiler is indicated one of the options for a set of components for the operation of services.

IIS Components


After specifying the address in the settings, you must click the “Create Virtual Directory” button. You can then compile the project and run IIS Manager. Our application should already appear in the list of applications on the site by default (Default Web Site), and it should also have a pool assigned to it (DefaultAppPool). It is recommended to create a separate pool for your services, specifying .NET 4.0 as the platform:

After creating the pool, assign it to your application (Default Web Site > Lesson1 > Advanced Settings > Application Pool).

The final step is to test your application. To do this, open the line specified in the project configuration in the browser, adding the service name at the end, in our case it is Calculator.svc: http://localhost/Lesson1/Calculator.svc. The result should be something like this:

Attention! If you chose .NET 4.0 as the platform and .NET 4.0 is installed on the machine hosting the service, there will be no link to the WSDL in one file (http://localhost/Lesson1/Calculator.svc?singleWsdl). Therefore, it is recommended to install a framework version of at least 4.5 on the server, even if the service itself is compiled on .NET 4.0. This is a rather funny feature, but it is the framework on the server that is responsible for this link, and not the one for which the service was compiled. This is perhaps the only significant difference between .NET 4.0 and .NET 4.5 from the point of view of the service interface.

Publishing a service means compiling it for further uploading of the assembly to the server. Let's look at a specific example, putting the server on the company's demo server.

First, you need to create a publishing profile; to do this, right-click on the project name and select Publish...:

The wizard will offer us several publishing options, select Custom, and name the profile Demo.
Then select the publishing method File System and indicate the path where our assembly will be saved:

The project is ready for publication, but it is advisable to go to the next tab (Settings) and check the box “Delete all existing files prior to publish” and select the configuration.

Let's publish and see what happens in the end:

To host the service on your site, copy the folder to the server and connect it to IIS as an application, as if it were a regular site (Default Web Site > Add Application...)

Ready! The service is located at http://dszss.proitr.ru/WCFLesson1/Calculator.svc.

In this section, we will look at three ways to use our service: calling through a C# application, calling through SoapUI, and requesting via URL (WebInvoke).

First, let's consider accessing our service through a client in C#. Since WCF is integrated into Visual Studio, creating a client is easy. All we need to know is the WSDL address of the service we want to connect to.

Let's create another project of the Console Application type in our solution and call it TestClient. Let's assign it as executable and add a link to the service:

In the window that opens, enter the local service address, optionally specify the namespace name and additional settings. Here you can see what methods our service provides:

After creating a link to the service, the “Service References” folder will appear in the project, in which the generated client will be located. If you wish, you can look at its code yourself, you just need to enable the display of hidden files or go to F12 inside the client code.

Now let's write the code to connect to the service and call the arithmetic operations provided by it:

Test client

Program.cs

using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; // reference to the service namespace using TestClient.RemoteService; namespace TestClient ( class Program ( static void Main(string args) ( // console output assistant ConsoleWriter writer = new ConsoleWriter(); // create a service client CalculatorClient client = new CalculatorClient("BasicHttpBinding_ICalculator"); try ( // check the connection writer.Write("Testing connection to the service..."); if (!string.Equals(client.TestConnection(), "OK", StringComparison.InvariantCultureIgnoreCase)) ( throw new Exception("Testing connection failed"); ) writer.WriteLineSuccess(); writer.WriteLine(); // lambda function for checking the method var CheckArithmeticOperation = new Action ((operation, operationName, arg1, arg2, expectedResult) => ( writer.Write("Checking the operation "") ; writer.Write(ConsoleColor.White, operation.Method.Name); writer.Write("", (0) (1) (2) = ", arg1.ToString(CultureInfo.InvariantCulture), operationName, arg2.ToString( CultureInfo.InvariantCulture)); double result = operation(arg1, arg2); if (result == expectedResult) ( // check passed writer.Write("(0) ", result.ToString(CultureInfo.InvariantCulture)); writer.WriteLineSuccess(); ) else ( // error throw new Exception(string.Format("Error checking method "(0)": (1) (2) (3) != (4)", operation.Method.Name, arg1.ToString( CultureInfo.InvariantCulture), operationName, arg2.ToString(CultureInfo.InvariantCulture), expectedResult.ToString(CultureInfo.InvariantCulture))); ) )); // checking the Addition method CheckArithmeticOperation(client.Addition, "+", 2.5, 5, 2.5 + 5); // checking the Subtraction method CheckArithmeticOperation(client.Subtraction, "-", 2.5, 5, 2.5 - 5); // checking the Multiplication method CheckArithmeticOperation(client.Multiplication, "*", 2.5, 5, 2.5 * 5); // checking the Division method CheckArithmeticOperation(client.Division, "/", 2.5, 5, 2.5 / 5); // at the end of the work, close the client client.Close(); ) catch (Exception ex) ( // in case of an error, you must force close the client using the Abort() method client.Abort(); // display information about the error writer.WriteLine(); writer.WriteLineError("Error: (0)", ex.Message); ) Console.WriteLine(); Console.WriteLine("Press any key to continue..."); Console.ReadKey(); ) ) )


ConsoleWriter.cs

using System; namespace TestClient ( /// /// console writer /// public class ConsoleWriter ( #region Declarations private ConsoleColor _successColor; // message color for successful operations private ConsoleColor _errorColor; // error message color private ConsoleColor _warningColor; // message color -warnings private string _successText; // text of messages for successful operations private string _errorText; // text of error messages private string _warningText; // text of warning messages #endregion #region Properties /// /// color of messages for successful operations / // public ConsoleColor SuccessColor ( get ( return _successColor; ) set ( _successColor = value; ) ) /// /// error message color /// public ConsoleColor ErrorColor ( get ( return _errorColor; ) set ( _errorColor = value; ) ) /// /// color of warning messages /// public ConsoleColor WarningColor ( get ( return _warningColor; ) set ( _warningColor = value; ) ) /// /// message text for successful operations /// public string SuccessText ( get ( return _successText; ) set ( _successText = value; ) ) /// /// text of error messages /// public string ErrorText ( get ( return _errorText; ) set ( _errorText = value; ) ) /// /// text of warning messages /// public string WarningText ( get ( return _warningText; ) set ( _warningText = value; ) ) /// /// text color /// public ConsoleColor ForegroundColor ( get ( return Console.ForegroundColor; ) set ( Console.ForegroundColor = value; ) ) /// /// background color /// public ConsoleColor BackgroundColor ( get ( return Console.BackgroundColor; ) set ( Console.BackgroundColor = value; ) ) #endregion #region Constructors /// /// constructor / // public ConsoleWriter() ( _successColor = ConsoleColor.Green; _errorColor = ConsoleColor.Red; _warningColor = ConsoleColor.Blue; _successText = "OK"; _errorText = "ERROR"; _warningText = "WARNING"; ) #endregion #region Private methods #endregion #region Protected methods #endregion #region Public methods #region Write | WriteLine /// /// Message public void Write(string value) ( ​​Console.Write(value); ) /// /// write a message to the console /// /// Message color /// Message public void Write( ConsoleColor color, string value) ( ​​ConsoleColor oldColor = Console.ForegroundColor; Console.ForegroundColor = color; Console.Write(value); Console.ForegroundColor = oldColor; ) /// /// write a message to the console /// /// Format string /// Arguments public void Write(string format, params object args) ( Console. Write(string.Format(format, args)); ) /// /// write a message to the console /// /// Message color /// Format string /// Arguments public void Write(ConsoleColor color, string format, params object args) ( ConsoleColor oldColor = Console.ForegroundColor; Console.ForegroundColor = color; Console.Write(string.Format(format, args)); Console.ForegroundColor = oldColor; ) /// /// write the newline to the console /// public void WriteLine() ( Console.WriteLine (); ) /// /// write a message to the console /// /// Message public void WriteLine(string value) ( ​​Console.WriteLine(value); ) /// /// write a message to the console /// /// Message color /// Message public void WriteLine(ConsoleColor color, string value) ( ​​ConsoleColor oldColor = Console.ForegroundColor; Console.ForegroundColor = color; Console.WriteLine(value); Console.ForegroundColor = oldColor; ) /// /// write a message to the console /// /// Format string /// Arguments public void WriteLine(string format, params object args) ( Console.WriteLine(string.Format(format, args)); ) /// /// write a message to the console /// /// Message color /// Format string /// Arguments public void WriteLine(ConsoleColor color, string format, params object args) ( ConsoleColor oldColor = Console.ForegroundColor; Console.ForegroundColor = color; Console.WriteLine(string.Format(format, args)); Console.ForegroundColor = oldColor; ) #endregion #region WriteSuccess | WriteLineSuccess /// /// write a message to the console /// public void WriteSuccess() ( Write(_successColor, _successText); ) /// /// write a message to the console /// /// Message public void WriteSuccess(string value) ( ​​Write(_successColor, value); ) /// /// write a message to the console /// /// Format string /// Arguments public void WriteSuccess(string format, params object args) ( Write(_successColor, string .Format(format, args)); ) /// /// write a message to the console /// public void WriteLineSuccess() ( WriteLine(_successColor, _successText); ) /// /// write a message to the console /// /// Message public void WriteLineSuccess(string value) ( ​​WriteLine(_successColor, value); ) /// /// write a message to the console /// /// Format string /// Arguments public void WriteLineSuccess(string format, params object args) ( WriteLine(_successColor, string.Format(format, args)); ) #endregion #region WriteError | WriteLineError /// /// write a message to the console /// public void WriteError() ( Write(_errorColor, _errorText); ) /// /// write a message to the console /// /// Message public void WriteError(string value) ( ​​Write(_errorColor, value); ) /// /// write a message to the console /// /// Format string /// Arguments public void WriteError(string format, params object args) ( Write(_errorColor, string . Format(format, args)); ) /// /// write a message to the console /// public void WriteLineError() ( WriteLine(_errorColor, _errorText); ) /// /// write a message to the console /// /// Message public void WriteLineError(string value) ( ​​WriteLine(_errorColor, value); ) /// /// write a message to the console /// /// Format string /// Arguments public void WriteLineError(string format, params object args) ( WriteLine(_errorColor, string .Format(format, args)); ) #endregion #region WriteWarning | WriteLineWarning /// /// write a message to the console /// public void WriteWarning() ( Write(_warningColor, _warningText); ) /// /// write a message to the console /// /// Message public void WriteWarning(string value) ( ​​Write(_warningColor, value); ) /// /// write a message to the console /// /// Format string /// Arguments public void WriteWarning(string format, params object args) ( Write(_warningColor, string .Format(format, args)); ) /// /// write a message to the console /// public void WriteLineWarning() ( WriteLine(_warningColor, _warningText); ) /// /// write a message to the console /// /// Message public void WriteLineWarning(string value) ( ​​WriteLine(_warningColor, value); ) /// /// write the message to the console /// /// Format string /// Arguments public void WriteLineWarning(string format, params object args) ( WriteLine(_warningColor, string.Format(format, args)); ) #endregion #endregion ) )


Execution result:

In general, calling service methods is no different from calling methods of a regular C# interface, and since the client and service are within the same solution, you can put breakpoints in the service methods that will fire when they are called. You can also run a separate service project while waiting for a request from a third-party application ().

Technically, when accessing a service, the client generates a Soap message (plain XML), which is transmitted over an HTTP channel and can be intercepted by a sniffer. Of course, WCF has other transmission methods, as well as the ability to encrypt and/or sign messages, but this is a topic for another lesson.

Let's move on to another way to call the service.

This topic pertains to a legacy technology. XML Web services and XML Web service clients should now be created using Windows Communication Foundation.

In addition to letting you create Web page s, Microsoft Visual Studio also lets you create Web services that use ASP.NET XML. Creating a Web service in Visual Studio is similar to creating a Web page. You can also use the Microsoft Visual Web Developer Web development tool to reference and use Web services that are in a Visual Web Developer solution, on your local computer or in a local or external UDDI directory. In this walkthrough, you will create the Web service in one solution and use it in another.

Tasks illustrated in this walkthrough include:

    Creating a simple XML Web service in Visual Web Developer.

    Creating a separate Web site that uses the Web service.

Prerequisites

In order to complete this walkthrough, you will need:

    Microsoft Internet Information Services (IIS) installed locally on your computer.

    NET Framework version 3.5 or higher.

Creating a Web Service Under the IIS Root

Create a new Web service and page by following these steps.

You must use an IIS Web site for this walkthrough.

To create a Web service

Open Visual Web Developer.

On the File menu, click New Web Site.

The New Web Site dialog box appears.

Under, click ASP.NET Web Service.

Click Browse.

Click Local IIS.

Click Default Web Site.

Click Create New Web Application.

Type the name TemperatureWebService.

Click Open.

The New Web Site dialog box appears, with the name of the new Web site in the rightmost Location list. The location includes the protocol (http://) and location (localhost). This indicates that you are working with a local IIS Web site.

In the Language

The programming language that you choose will be the default for the Web site. However, you can use more than one language in the same Web application by creating pages and components in different programming languages. For more information about how to create components using different languages, see Shared Code Folders in ASP.NET Web Site Projects.

Click OK.

Visual Web Developer creates the new Web service and opens a new class named Service, which is the default Web service. However, in the following procedure you will create a new Web service with a specified name and you will not use the Service class.

Close the Service class.

Creating the Web Service

You will create a Web service that converts temperature from Fahrenheit to Celsius and vice versa.

To create the Web service

In Solution Explorer, right-click the Web site name (http://localhost/TemperatureWebService), and then click Add New Item .

Under Visual Studio installed templates , click Web Service , and then in the Name box, type Convert.

Make sure that the Place code in separate file check box is selected, and then click Add .

Visual Web Developer creates a new Web service that is made up of two files. The Convert.asmx file is the file that can be invoked to call Web service methods, and it points to the code for the Web service. The code itself is in a class file (Convert.vb, Convert.cs, or Convert.jsl, depending on the programming language) in the App_Code folder. The code file contains a template for a Web service. The code file includes some code for a Web service method.

You will create two methods in the Web service. The first method converts Fahrenheit temperatures to Celsius, and the second method converts Celsius temperatures to Fahrenheit.

To create the conversion methods

Add the following code inside the class, after the HelloWorld method:

_ Public Function FahrenheitToCelsius(ByVal Fahrenheit As Double) _ As Double Return ((Fahrenheit - 32) * 5) / 9 End Function _ Public Function CelsiusToFahrenheit(ByVal Celsius As Double) _ As Double Return ((Celsius * 9) / 5) + 32 End Function public double FahrenheitToCelsius(double Fahrenheit) ( return ((Fahrenheit - 32) * 5) / 9; ) public double CelsiusToFahrenheit(double Celsius) ( return ((Celsius * 9) / 5) + 32; )

Notice that the function names are preceded with an attribute ( or ) as part of the function declaration.

After you have entered the functions, save the file.

Now, you can test the Web service in Visual Web Developer.

To test the Web service

In Solution Explorer, click Convert.asmx, and then press CTRL+F5.

The Web service is invoked and a page appears in the browser that shows the methods that are exposed by the Web service.

Click CelsiusToFahrenheit , which invokes that method.

A page appears that prompts you for parameter values ​​for the CelsiusToFahrenheit method.

In the Celsius box, type 100, and then click Invoke .

A new window appears that displays the XML that the Web service returns when the CelsiusToFahrenheit method is invoked. The value 212 appears in the XML.

Close the browser that contains the method results.

In the original browser, click Back to return to the list of methods.

Click FahrenheitToCelsius and test to make sure that the method is returning the results that you expect.

If you type 212, the FahrenheitToCelsius method will return 100 .

Close the browser.

You have finished creating the Web service; the next step is to use it.

Using the Web Service

Now that you have a Web service, you will create a Web site where you will reference and use the Web service that you created. For the walkthrough, you will create a separate Web site that has a page where you start the Web service methods that you just created.

To create a Web site to use the Web service

On the File menu, click New Web Site.

Under Visual Studio installed templates, click ASP.NET Web Site.

Click Browse.

Click Local IIS.

Click Default Web Site.

Click Create New Web Application.

Visual Web Developer creates a new IIS Web application.

Type the name TemperatureWeb.

Click Open.

In the Language list, click the programming language that you prefer to work in.

Click OK.

Visual Web Developer creates a new local IIS Web site and a new page named Default.aspx.

Adding the Web Service as a Component

The Web service is a component that you can reference in your application. Therefore, you must create a reference to it.

To create a reference to the Web service

If the server name for the Web service contains characters that cannot be used for a class name, such as a hyphen (-), Visual Web Developer converts those characters to an underscore character (_). Therefore, the namespace in Visual Web Developer for the Web service might not match the server name exactly.

You can now use the Web service. In this walkthrough, you will add controls to Default.aspx, and then program the controls to convert a specified temperature to both Fahrenheit and Celsius. When the page is running, it will look something like the following illustration.

Temperature conversion page

To call the Web service methods

Open the Default.aspx page and switch to Design view.

From the Standard group in the Toolbox, drag the following controls onto the page and set their properties as indicated:

Properties

ID : TemperatureTextbox

Text: (empty)

ID: ConvertButton

Text : Convert

ID: FahrenheitLabel

Text: (empty)

ID: CelsiusLabel

Text: (empty)

  • Optionally, add text to the page for captions.

    For this walkthrough, the layout of the page is not important.

    Double-click ConvertButton to create an event handler for its Click event.

    Make sure your event handler code matches the code in the following example.

    Dim wsConvert As New localhost.Convert() Dim temperature As Double temperature = System.Convert.ToDouble(TemperatureTextbox.Text) FahrenheitLabel.Text = "Fahrenheit To Celsius = " & _ wsConvert.FahrenheitToCelsius(temperature).ToString() CelsiusLabel.Text = "Celsius To Fahrenheit = " & _ wsConvert.CelsiusToFahrenheit(temperature).ToString() protected void ConvertButton_Click(object sender, EventArgs e) ( localhost.Convert wsConvert = new localhost.Convert(); double temperature = System.Convert.ToDouble (TemperatureTextbox.Text); FahrenheitLabel.Text = "Fahrenheit To Celsius = " + wsConvert.FahrenheitToCelsius(temperature).ToString(); CelsiusLabel.Text = "Celsius To Fahrenheit = " + wsConvert.CelsiusToFahrenheit(temperature).ToString(); )

    Press CTRL+F5 to run the page.

    In the text box, type a value, such as 100, and then click Convert .

    The page displays the result of converting the temperature value into both Fahrenheit and Celsius.

    Debugging the Web Service

    You can debug a Web service in the same way that you debug Web pages.

    Visual Web Developer Express and Visual Studio Standard do not support stepping into a Web service from a page that references it. If you are using Visual Web Developer Express or Visual Studio Standard, skip this section and the ones following. For more information about how to debug Web sites, see Walkthrough: Debugging Web Pages in Visual Web Developer.

    To start, you must configure the Web site that contains the Web service to enable debugging.

    To enable debugging in the Web services Web site

    On the File menu, click Open Web Site.

    Click Local IIS.

    Click TemperatureWebService, and then click Open .

    On the Website menu, click ASP.NET Configuration

    Click Application , and then click Application Configuration .

    Under Debugging and Tracing, click.

    Select the Enable debugging check box.

    The Web Site Administration Tool creates a Web.config file for the Web site and sets a configuration option to enable debugging.

    To see the Web.config file in Solution Explorer, click the Web site name and then, on the Solution Explorer toolbar, click Refresh .

    You must now enable debugging for the Web site that uses the Web service.

    To enable debugging in the Web site

    Open the TemperatureWeb site.

    On the Website menu, click ASP.NET Configuration to open the Web Site Administration Tool.

    Click Application , click Application Configuration , under Debugging and Tracing , click Configure debugging and tracing , and then select the Enable debugging check box .

    Close the Web Site Administration Tool.

    To see the Web.config file in Solution Explorer, select the Web site name and then, on the Solution Explorer toolbar, click Refresh .

    In Solution Explorer, right-click Default.aspx, and then click View Code .

    Visual Web Developer opens the code file for the page.

    Position the pointer in the following line:

    Temperature = System.Convert.ToDouble(TemperatureTextbox.Text) double temperature = System.Convert.ToDouble(TemperatureTextbox.Text);

    Press F9 to set a breakpoint on the line.

    Testing Debugging

    Both the Web site and the Web service are configured for debugging, so that you can now try debugging. You will start in the Default.aspx page and step through the code until the code invokes the Web service. The debugger will switch to the Web service and continue stepping through the code.

    To debug the page and Web service

    Press F5 to run the Default.aspx page with debugging.

    The page appears in the browser.

    In the box, type a value, such as 100, and then click Convert .

    Visual Web Developer starts running the code for the page, but stops and highlights the line with the breakpoint on it.

    Press F11 to step to the next line.

    Press F11 again.

    Because the next line invokes the Web service, the debugger steps into the Web service, stopping on the first line of the FahrenheitToCelsius method.

    Continue pressing F11.

    The debugger steps through the rest of the method, and then returns to the calling page. If you continue stepping, the debugger will step back into the Web service and into the CelsiusToFahrenheit method.

    Close the browser, which also closes the debugger.

    Next Steps

    This walkthrough has illustrated the basic principles of creating a very simple Web service and using it in an ASP.NET application. You might want to experiment with additional, more complex Web service features. For more information, see.

    These restrictions do not prevent the ASP.NET AJAX callback function from being used for its intended purpose - as a mechanism for a page to perform tasks in a server application. If you previously had to use web services to expose server-side functionality to fat clients, third party developers and applications on non-.NET platforms, you will find that using web services in ASP.NET AJAX is somewhat simpler.

    There are a number of ways to work around these restrictions. For example, in your web application, you can call a web method, which in turn calls a web method that exists in another domain. This handshake method works because the web server code does not have the browser's inherent restriction - it is free to make cross-domain calls to other web services.

    Creating a Web Service

    Web services used with ASP.NET AJAX consist of two parts: a .asmx file, which acts as the web service endpoint, and a .cs file, which contains the actual C# code. These files must be added to a website that contains an ASP.NET AJAX page that will use the web service.

    The fastest way to create a web service in Visual Studio is to select Website --> Add New Item, specify the Web Service template, assign a name to the file (in following example- TerritoriesService) and click on the Add button. When creating a website without a project, the .asmx file will be placed in the web application directory and the corresponding .cs file will be placed in the App_Code folder for automatic compilation.

    For web services to be used with ASP.NET AJAX, the web application does not need to be hosted in an IIS virtual directory. Instead, you can use Visual Studio's built-in web server to test your application. This is possible because the script code that automatically calls the web service uses a relative path. As a result, regardless of the port chosen by the Visual Studio web server, the web page will be able to generate the correct URL.

    The .asmx file is not particularly interesting - if you open it, you will find a single line with a WebService directive, which specifies the code language, the location of the code-behind file, and the name of the class:

    This example creates the TerritoriesService.asmx web service with the code-behind file TerritoriesService.cs. The code-behind file defines a TerritoriesService class that looks like this:

    Public class TerritoriesService: System.Web.Services.WebService ( // ... )

    By default, the ScriptService attribute is commented out. To create a web service that can be called from an ASP.NET AJAX page, be sure to remove the comment characters.

    This class derives from System.Web.Services.WebService, which serves as the traditional base class for web services. However, this approach is chosen for convenience only and is not mandatory. Inheriting from WebService provides access to a number of built-in objects (such as Application, Server, Session, and User) without having to access the static HttpContext.Current property.

    Note also that the web service class declaration contains three attributes. The first two—WebService (sets the XML namespace used in Web service messages) and WebServiceBinding (specifies the level of standards compliance supported by the Web service)—apply only when calling a Web service using SOAP messages and have no meaning in ASP pages. NET AJAX. However, the third attribute - ScriptService - is much more important. It configures the web service by allowing JSON calls from JavaScript clients. Without this, the web service could not be used in an ASP.NET AJAX page.

    Creating a Web Method

    After completing the steps described, you can start writing code for your web service. Every web service contains one or more methods that are marked with the WebMethod attribute. This attribute makes the method available to be called remotely. If you add a method that does not contain a web method attribute, server code will be able to use it, but client JavaScript code will not be able to call it directly.

    Public class TerritoriesService: System.Web.Services.WebService ( public string HelloWorld() ( return "Hello World"; ) )

    It is not necessary to make a method public (as in this example), but it is usually done according to accepted conventions. Web methods are subject to certain restrictions. The data types used for parameter values ​​and return values ​​must be those described in the table below:

    Valid data types of web service parameters and return values Data type Description
    Basic types

    Basic C# data types such as integers (short, int, long), unsigned integers (ushort, uint, ulong), non-integer numeric types (float, double, decimal) and a number of other mixed types (bool, string, char, byte, DateTime)

    Transfers

    Enum types (defined in C# using the enum keyword) are supported. However, the web service uses the string name of the enum value (rather than the underlying integer)

    Special objects

    You can pass any object created from a special class or structure. The only restrictions are that only public data members and properties are passed, and all public members and properties must be one of the supported data types. If you use a class that includes special methods, these methods will not be passed to the client and will not be available to it

    Arrays and Collections

    You can use arrays of any supported type. ArrayList (which simply converts to an array) is also allowed, but more specialized collections such as Hashtable are not allowed. You can use basic collections. In all these cases, the objects in the collection must also be serializable

    XmlNode

    Objects based on System.Xml.XmlNode are representations of part of an XML document. They can be used to send arbitrary XML text

    DataSet and DataTable

    DataSet and DataTable can be used to return information from a relational database. Other ADO.NET data objects, such as DataColumns and DataRows, are not supported. The applied DataSet or DataTable object is automatically converted into an XML fragment, similar to what happens when using the GetXml() or WriteXml() methods

    Session state in a web service

    The WebMethod attribute accepts a number of parameters, most of which carry some weight in the ASP.NET page. One exception is the property EnableSession, which defaults to false, causing the rendering session state to be unavailable to the web service. This default makes sense in a traditional web service that does not use ASP.NET AJAX, since any session information may not exist and the client may not support the session cookie at all. But in the case of an ASP.NET AJAX web service, web service calls are always made from the context of an ASP.NET web page, which is running in the context of the current user of the web application, and that user has a valid session and a session cookie automatically passed along with the web service call.

    The following is an example of providing a web method with access to a Session object:

    Public void DoSomething() ( if (Session["myObject"] != null) ( // (Use the object in session state.) ) else ( // (Create a new object and save it in session state.) ) )

    For the dropdown example, the web service must provide a way to get the regions located in a given territory. Below is the code for a web service that contains a GetTerritoriesInRegion() web method that retrieves regions:

    Using System; using System.Collections.Generic; using System.Web; using System.Web.Services; using System.Data; using System.Data.SqlClient; using System.Web.Configuration; public class TerritoriesService: System.Web.Services.WebService ( public List GetTerritoriesInRegion(int regionID) ( SqlConnection con = new SqlConnection(WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString); SqlCommand cmd = new SqlCommand("SELECT * FROM Territories WHERE RegionID=@RegionID", con); cmd.Parameters.Add(new SqlParameter("@RegionID", SqlDbType.Int, 4)); cmd.Parameters["@RegionID"].Value = regionID; List territories = new List (); try ( con.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) ( territories.Add(new Territory(reader["TerritoryID"].ToString(), reader[" TerritoryDescription"].ToString())); ) reader.Close(); ) catch ( // Hide errors throw new ApplicationException("Data Error"); ) finally ( con.Close(); ) return territories; ) )

    The code for the GetTerritoriesInRegion() method is similar to the code that was used previously to serve the client callback. However, this code has a major difference - instead of returning a single long string of results, it returns information using a strongly typed list of Territory objects. This is a much more rigorous approach that prevents accidental errors.

    The Territory class covers two pieces of string information. It defines public member variables rather than properties, since it is intended to act solely as a data container that transports information across the network:

    Public class Territory ( public string ID; public string Description; public Territory(string id, string description) ( this.ID = id; this.Description = description; ) public Territory() ( ) )

    This class definition can be placed in the same code file as the web service, or in a separate file within the App_Code directory.

    Call a web service

    Now that the desired web service has been created, we need to configure the page so that it knows about the TerritoriesService. To do this, you need to add a ScriptManager control to the page. You will then need to add a section to the control's handle.

    The ServiceReference elements in this section list all the services used by the page and their locations. Adding a link to the previously provided TerritoriesService .asmx file is done as follows:

    When the page is rendered on the server, ScriptManager will generate a JavaScript proxy object. In client code, you can use this JavaScript proxy object to make calls. Below is the code for two lists placed in a web form:

    The first list is populated through normal ASP.NET data binding using the SqlDataSource data source control. Of more interest is that it uses the onchange attribute to bind to the client event handler. As a result, when the user selects a new territory, the GetTerritories() JavaScript function is run and the current value of the list is passed as an argument.

    Formally, all the code for the GetTerritories() function could be placed directly in the onchange event attribute, thereby reducing the number of JavaScript functions created. However, separating the code that calls a web service improves the readability of the code and makes it easier to maintain.

    The GetTerritories() JavaScript function code looks like this:

    function GetTerritories(regionID) ( TerritoriesService.GetTerritoriesInRegion(regionID, OnRequestComplete, OnError); )

    If you have previously programmed using ASP.NET Web services, you will notice that the syntax of the client code for calling an ASP.NET AJAX Web service is different from the .NET syntax. In a .NET application, you must first create a proxy object and then call the web service on that object. An ASP.NET AJAX page uses a pre-built proxy object with the same name as the web service class.

    Client-side calls to a web service are asynchronous, so along with the original parameters of the web method, you should always provide one additional parameter identifying the client-side JavaScript function that should be called after receiving the result. (In this example, this is the OnRequestComplete function.) Optionally, you can add another reference pointing to the function that should be used when an error occurs. (IN in this example this is the OnError function.)

    To complete the example, we need to provide a client function that handles the response. In this example, this is the OnRequestComplete() function. It takes the return value in a single parameter and then adds the information to a second drop-down list on the web page:

    Function OnRequestComplete(result) ( var lstTerritories = document.getElementById("lstTerritories"); lstTerritories.innerHTML = ""; for (var n = 0; n

    The notable feature of this code is that it is able to work with the result returned from the web method without performing any additional deserialization steps. What's even more impressive is that the web method returns a generic list of Territory objects, which obviously has no equivalent in JavaScript code. Instead, ASP.NET AJAX creates a definition for the Territory object and returns the complete list in an array. This allows JavaScript code to loop through the array and check the ID and Description properties of each element.

    In this case, you can use one small trick. Instead of the document.getElementById() method, you can use the $get alias from ASP.NET AJAX, which performs the same function and looks like this:

    Var lstTerritories = $get("lstTerritories");

    This technique is a common convention used in ASP.NET AJAX pages.

    Now this example works exactly the same as the client callback version described earlier. The difference between the two is that this version uses a strongly typed web method without the cumbersome string serialization code. Additionally, you don't need to add any server code to dynamically receive the callback link and insert it. Instead, you can use a simple proxy object that provides access to the web service.

    As a final touch, you can set a time limit and error handling functions, for example:

    Function OnError(result) ( var lbl = document.getElementById("lblInfo"); lbl.innerHTML = "" + result.get_message() + "
    "; lbl.innerHTML += result.get_stackTrace(); )

    The OnError() function receives an error object containing a method get_message(), which retrieves the error text, and the method get_stackTrace(), which returns a detailed call stack indicating where the error occurred. The figure below shows what happens when a web method fails to connect to the database and throws a standard ApplicationException:

    This example demonstrates the ASP.NET AJAX version of the client callback model. Although it uses the same internal mechanisms as the ASP.NET client callback function, the ASP.NET AJAX version provides a stronger foundation built on top of web services. However, both approaches have one common feature- Regardless of the approach used, you will have to write your own JavaScript code to update the page.

    Putting a web method on a page

    In most cases, it makes sense to create a separate web service to handle ASP.NET AJAX callbacks. This approach typically results in cleaner pages and makes it easier to debug and improve your code. However, in some situations there may be one or more web methods that are clearly intended to be used on a single page and would not really be used in other parts of the application. In this case, you can create a dedicated web service for each page, or you can move the web service code into the page.

    Placing web method code on a page is easy - in fact, it's as simple as drag and drop. To begin, copy your web method (complete with the WebMethod attribute) into the page's code-behind class. Then change it to static method and add the System.Web.Script.Services.ScriptMethod attribute. Below is an example of placing a web method (GetTerritoriesInRegion) in a web page:

    Public partial class _Default: System.Web.UI.Page ( public static List GetTerritoriesInRegion(int regionID) ( // Pass the work to the web service class TerritoriesService service = new TerritoriesService(); return service.GetTerritoriesInRegion(regionID); ) )

    Set the ScriptManager.EnablePageMethods property to true and remove the reference in the ScriptManager code section (assuming you don't intend to use any web services not built into the page):

    Finally, modify your JavaScript code to call the method through the PageMethods object, as shown in the following example:

    Function GetTerritories(regionID) ( PageMethods.GetTerritoriesInRegion(regionID, OnRequestComplete, OnError); )

    The PageMethods object represents all the web methods added to the current web page.

    One of the benefits of putting a web method into a page is that. that the method is no longer exposed via the .asmx file. As a result, it is not considered part of the public web service and is difficult for anyone to discover. This circumstance is a compelling argument if it is desirable to hide web services from prying eyes.

    Another possible reason to code web methods directly in the page class is to read values ​​from the state of the view or controls located on the page. When a page method is called, a simplified version of the page's lifecycle is triggered, as was the case when using the ASP.NET client callback function. Of course, attempting to modify page details makes no sense since the page is not rendered and therefore any changes made will simply be discarded.

    From an application security perspective, it makes no difference whether the web methods are hosted in a page or in a dedicated web service. Placing a web method on a page can hide it from casual users, but a real attacker will start by looking at the page's HTML, which includes a reference to a JavaScript proxy object. Attackers can easily use a JavaScript proxy object to make forged web method calls. To protect against such threats, web methods should always implement the same security measures that are used in web pages. For example, any input accepted must be validated, code must refuse to return sensitive information to unauthenticated users, and parameterized commands must be used when accessing the database to prevent SQL injection attacks.





  • 

    2024 gtavrl.ru.