Krzysztof Mossakowski
For Students
  • Creating simple XML Web Service
    • Create a new XML Web Service project using Visual Studio (File / New / Web Site / ASP.NET Web Service)
      • Take a look at the Service.asmx file
        <%@ WebService Language="C#" CodeBehind="~/App_Code/Service.cs" Class="Service" %>
        
        • The @ WebService directive is required at the top.
        • The presence of the .asmx file and the @ WebService directive correlate the URL address of the Web service with its implementation.
        • The Web service class you define can be included directly in the .asmx file, or in a separate file. If you use a separate file, it must be compiled into an assembly.
      • See the source code generated in the Service.cs file
        using System;
        using System.Web;
        using System.Web.Services;
        using System.Web.Services.Protocols;
        
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        public class Service : System.Web.Services.WebService
        {
            public Service () {
        
                //Uncomment the following line if using designed components 
                //InitializeComponent(); 
            }
        
            [WebMethod]
            public string HelloWorld() {
                return "Hello World";
            }
            
        }
        
        • By applying the optional WebService attribute to a class that implements a Web service, you can set the default XML namespace for the Web service along with a string to describe the Web service.
          • It is highly recommended that this default namespace, which originally is http://tempuri.org, be changed before the Web service is made publicly consumable.
          • The Web service must be distinguished from other Web services that might inadvertently use the namespace as the default (<http://tempuri.org/>).
        • Classes that implement a Web service created using ASP.NET can optionally derive from the WebService class to gain access to the common ASP.NET objects, such as Application, Session, User, and Context (the same as in ASP.NET Web applications).
        • The WebMethod attribute must be applied to a method to give it the ability to receive Web service requests and send back responses.
      • Compile and run the project
        • Note that the ASP.NET Development Server has been run.
        • The page displayed in the browser is generated by the Web server. It is not a part of the Web Service.
        • Click the 'Service Description' link.
          • The WSDL (Web Service Description Language) document is displayed.
          • This is the definition of the Web service which allows all clients (also non-.NET) to be able to use the service.
          • All Web methods (i.e. methods with the WebMethod attribute) have very strict definition of parameters and output value.
        • Click the 'HelloWorld' link
          • This place allows you to test your Web method.
          • If the method has standard parameters, textboxes appear to enable to write values for input parameters.
          • The 'Invoke' button invokes the Web method, as a result you can see the XML document with a value returned by the method.
          • Below the 'Invoke' button you can see bodies of SOAP (originally Simple Object Access Protocol) messages used to transport input parameters and the return value.
    • Add two new methods to the Service class to calculate the minimum value of values passed as parameters (the first method takes 3 parameters, the second method takesn an array of parameters).
      private double GetMinInternal(params double[] d)
      {
          double min = double.MaxValue;
          for (int i = 0; i < d.Length; i++) {
              if (d[i] < min) {
                  min = d[i];
              }
          }
          return min;
      }
      
      [WebMethod]
      public double GetMin(double[] d)
      {
          return GetMinInternal(d);
      }
      
      [WebMethod]
      public double GetMin3(double d1, double d2, double d3)
      {
          return GetMinInternal(d1, d2, d3);
      }
      
      • See the WSDL document for the Web service (run the project and click the 'Service Description' link).
        • Note definitions of these methods and their parameters (in particular the definition of the ArrayOfDouble type created for the parameter of the GetMin method).
    • Add a new Web method which splits a string using a space.
      • [WebMethod]
        public List<string> SplitBySpace(string s)
        {
            string[] words = s.Split(' ');
            List<string> wordsList = new List<string>(words);
            return wordsList;
        }
        
      • Check how the C# generic collection is represented in the WSDL document.
      • Test the Web method using the page generated by the Web server.


  • Consuming created Web service
    • Open a new instance of Visual Studio (closing the project closes also the ASP.NET Development Server, so we would need the IIS to serve our web service).
    • Create a new Windows Forms project.
    • Add a Web reference to the project
      • Right click on the project in the Solution Explorer window and choose the 'Add Web Reference' option.
      • Paste the URL of your Web service (i.e. address of the .asmx file, something like: http://localhost:1312/01/Service.asmx).
      • Let the tool find the Web service.
      • Set the Web reference name (e.g. 'MyFirstWebService').
      • Click the 'Add Reference' button.
      • Note the new reference added in the group 'Web References' in the Solution Explorer window.
      • Right click on the new Web reference and note the 'Update Web Reference' option - crucial when the Web service has been changed.
      • Double click the new Web reference and see the content of the reference in the 'Object Browser' window
      • Double click any of listed types included in the reference and see the source code generated for you by Visual Studio (more precisely: by the wsdl.exe tool).
        • Note that for each Web method, 4 methods were generated:
          [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/SplitBySpace", 
                          RequestNamespace="http://tempuri.org/", 
                          ResponseNamespace="http://tempuri.org/", 
                          Use=System.Web.Services.Description.SoapBindingUse.Literal, 
                          ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
          public string[] SplitBySpace(string s) {
              object[] results = this.Invoke("SplitBySpace", new object[] {s});
              return ((string[])(results[0]));
          }
          
          /// <remarks/>
          public void SplitBySpaceAsync(string s) {
              this.SplitBySpaceAsync(s, null);
          }
          
          /// <remarks/>
          public void SplitBySpaceAsync(string s, object userState) {
              if ((this.SplitBySpaceOperationCompleted == null)) {
                  this.SplitBySpaceOperationCompleted = new System.Threading.SendOrPostCallback(
                      this.OnSplitBySpaceOperationCompleted);
              }
              this.InvokeAsync("SplitBySpace", new object[] {
                          s}, this.SplitBySpaceOperationCompleted, userState);
          }
          
          private void OnSplitBySpaceOperationCompleted(object arg) {
              if ((this.SplitBySpaceCompleted != null)) {
                  System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = 
                      ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg));
                  this.SplitBySpaceCompleted(this, new SplitBySpaceCompletedEventArgs(
                      InvokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState));
              }
          }
          
        • The method with a name of the original Web method can be used for synchronous calling the Web method, the 3 others are useful for asynchronous calling.
      • Add controls (a Button and a TextBox) to the Windows Forms application to demonstrate consuming a Web method.
        • Add the following code to the event handler of clicking the button:
          MyFirstWebService.Service myWebService = new MyFirstWebService.Service();
          resultTextBox.Lines = myWebService.SplitBySpace(
              "Lorem ipsum dolor sit amet consectetuer vel dolor Quisque hendrerit nibh");
          
        • Run the project and click the button. Note that calling the SplitBySpace method is synchronous, i.e. it hangs the user interface.


  • Drawing barcodes - synchronous and asynchronous calls of Web methods
    • Close all projects and create new Windows Forms project.
      • Add controls to the form (5 TextBoxes, a Button, and a PictureBox).
      • Add a Web reference to the Web service
        https://premier.ccs-inc.com/webservices/BarcodeMaker/BarcodeSvc.asmx
        • You can test the Web service here
      • Add the following code to the handler of clicking the button ('barcode' is the name of Web reference)
        barcode.BarcodeSvc service = new barcode.BarcodeSvc();
        byte[] buffer = service.CreateBarcode(10, 10, 10, 10,
            "Super Title", 10, true,
            textBox1.Text, textBox2.Text, textBox3.Text, textBox4.Text, textBox5.Text,
            24, 8, true, "gif");
        MemoryStream stream = new MemoryStream(buffer);
        Bitmap bmp = new Bitmap(stream);
        pictureBox.Width = bmp.Width;
        pictureBox.Height = bmp.Height;
        pictureBox.Image = bmp;
        
      • Compile, run, and test the application.
        • Note, that after clicking the button application hangs, because the Web method is called synchronous.
      • Make the call asynchronous.
        • Take a look at code generated for you as a Web reference, note the existence of CreateBarcodeAsync and OnCreateBarcodeOperationCompleted methods and of CreateBarcodeCompletedEventHandler event handler.
        • Modify the code:
          private void callButton_Click(object sender, EventArgs e)
          {
              barcode.BarcodeSvc service = new barcode.BarcodeSvc();
              service.CreateBarcodeCompleted += new barcode.CreateBarcodeCompletedEventHandler(BarcodeCompleted);
              service.CreateBarcodeAsync(10, 10, 10, 10,
                  "Super Title", 10, true,
                  textBox1.Text, textBox2.Text, textBox3.Text, textBox4.Text, textBox5.Text,
                  24, 8, true, "gif");
          }
          
          void BarcodeCompleted(object sender, barcode.CreateBarcodeCompletedEventArgs e)
          {
              byte[] buffer = e.Result;
              MemoryStream stream = new MemoryStream(buffer);
              Bitmap bmp = new Bitmap(stream);
              pictureBox.Width = bmp.Width;
              pictureBox.Height = bmp.Height;
              pictureBox.Image = bmp;
          }
          
        • Run and test the application, note that the application do not stop responding now.