Oct 18 2007

Best Practices in Developing .NET Web services

Category:Bil@l @ 07:58

I have been researching for a while on the standards in developing ASP.NET Web services. I would like to share with you one of the practices that have shown to be a robust and organized one.

To start developing your Web service, you should start with:

1. Decide on the operations that are to be offered by your Web service:

For the sake of the Web service that I will be developing, it is a simple Web service that is called GetStudetRecord(). This method will return information about a student that is identified by a student ID. So in summary we have one Web method:

GetStudentRecord()

 

2. Design the messages (In/Out) for the operations offered:

Having decided on the operations to be offered, it is time to decide on the messages that will be exchanged by the Web service for each operation. In our example, we have to decide on the data type for the input parameter for the GetStudentRecord() method and its return data type.

For the input data type, we will have a parameter of type integer called StudRecID.

For the return data type, we should return an object of type StudRec.

It is better to show the above decisions in a UML simple diagram shown below in Figure 1:

 

You notice that I placed the method signature inside an interface called IStudentCatalog. This interface will be generated by code later on in this article. I will use this interface for both the Web service code-behind file to implement and the business component that will hold the real processing of the GetStudentRecord() method and other methods. This way, both the Web service and business component(s) will implement the same interface and hence the contract is clear between both of them.

 

3. Build the XSD Schema File for the In/Out messages of all operations:

I will be using the XSD Schema designer in VS 2005 to design the XSD file for the StudRec class and the input parameter StudRecID as follows:

xsd

The XSD code is as follows:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema
      id="StudentCatalog"
      targetNamespace="https://bhaidar.net/Schemas/StudentCatalog/"
      elementFormDefault="qualified"
      xmlns="https://bhaidar.net/Schemas/StudentCatalog/"
      xmlns:mstns="https://bhaidar.net/Schemas/StudentCatalog/"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      version="1.0">
  <xs:element name="StudRecID" type="xs:int" />
  <xs:element name="StudRec">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="StudRecID" type="xs:int" />
        <xs:element name="LastName" type="xs:string" />
        <xs:element name="FirstName" type="xs:string" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

 

You can notice the targetNamespace, xmlns, and xmlns:mstns are set to a custom URL, a virtual and not necessarily existing URL for the Schema file.

The XSD complexType is for the StudRec class and the element is for the input parameter StudRecID.

At this step, I created a new Web service project located at: http://localhost/StudentCatalogService/ and placed the above XSD file to the project.

 

4. Design the WSDL Document (Web Service Description Language Document):

Visual Studio can generate the WSDL document for you. But for better control and to make use of the above steps, you can use the following template for the WSDL document to generate your own WSDL document:

<?xml version="1.0" encoding="utf-8"?>
<!--
    1. Change targetNamespace and tns namespace.
       It's easiest if you set this targetNamespace to
       the same value you used for the schema targetNamespace.
-->
<wsdl:definitions
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    xmlns:s="http://www.w3.org/2001/XMLSchema"
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="https://bhaidar.net/Schemas/StudentCatalog/"
    xmlns:tns="https://bhaidar.net/Schemas/StudentCatalog/">

  <!--
    2. change the namespace and location to point to your schema
     -->
  <wsdl:import
      namespace="your schema target namespace here"
      location="URL to your schema" />
  <wsdl:types />

  <!--
        3. change message names, be sure to change the corresponding message
           names inside the operations.
        4. Change part names and element names. Element names must
           correspond to elements declared in your schema.
  -->
  <wsdl:message name="OperationNameSoapIn">
    <wsdl:part name="OperationNameSoapInPart1" element="tns:name-of-the-element-in-the-schema" />
  </wsdl:message>
  <wsdl:message name="OperationNameSoapOut">
    <wsdl:part name="OperationNameSoapOutPart1" element="tns:name-of-the-element-in-the-schema" />
  </wsdl:message>

  <!--
         5. Change the port type name.
         6. Change the operation name. This becomes the
            Webmethod's name. Add more operations as needed.
         7. Change the message names here to match the message names above
   -->
  <wsdl:portType name="ServiceNameSoap">
    <wsdl:operation name="OperationName">
      <wsdl:input message="tns:OperationNameSoapIn" />
      <wsdl:output message="tns:OperationNameSoapOut" />
    </wsdl:operation>
  </wsdl:portType>
  <!--
    6. Changes the bdining name to reflect the service name together with the port type name to reflect
        the port type name above.
    7. Change the operations' names
    8. Change the SoapAction to reflect the operation name
     -->
  <wsdl:binding name="ServiceNameSoap" type="tns:ServiceNameSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="OperationName">
      <soap:operation soapAction="https://bhaidar.net/Schemas/StudentCatalog/OperationName" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="ServiceNameSoap12" type="tns:ServiceNameSoap">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="OperationName">
      <soap12:operation soapAction="https://bhaidar.net/Schemas/StudentCatalog/OperationName" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <!--
    9. Change the service name
    10. Change the port names and binding names to reflect the above names
    11. Change the location of the Web service to reflect its real URL
     -->
  <wsdl:service name="ServiceName">
    <wsdl:port name="ServiceNameSoap" binding="tns:ServiceNameSoap">
      <soap:address location="Location-of-service" />
    </wsdl:port>
    <wsdl:port name="ServiceNameSoap12" binding="tns:ServiceNameSoap12">
      <soap12:address location="Location-of-service" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

 

The above is a WSDL document template generated by Visual Studio 2005. You can follow the comments to know what to change inside the template. Here is a customized version of the above template to fit our needs:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    xmlns:s="http://www.w3.org/2001/XMLSchema"
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="https://bhaidar.net/Schemas/StudentCatalog/"
    xmlns:tns="https://bhaidar.net/Schemas/StudentCatalog/">
  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="https://bhaidar.net/Schemas/StudentCatalog/">
      <s:element name="StudRecID" type="s:int" />
      <s:element name="StudRec">
        <s:complexType>
          <s:sequence>
            <s:element name="ID" type="s:int" />
            <s:element name="LastName" type="s:string" />
            <s:element name="FirstName" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
  </wsdl:types>
  <wsdl:message name="GetStudentRecordSoapIn">
    <wsdl:part name="GetStudentRecordSoapInPart1" element="tns:StudRecID" />
  </wsdl:message>
  <wsdl:message name="GetStudentRecordSoapOut">
    <wsdl:part name="GetStudentRecordSoapOutPart1" element="tns:StudRec" />
  </wsdl:message>
  <wsdl:portType name="StudentCatalogSoap">
    <wsdl:operation name="GetStudentRecord">
      <wsdl:input message="tns:GetStudentRecordSoapIn" />
      <wsdl:output message="tns:GetStudentRecordSoapOut" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="StudentCatalogSoap" type="tns:StudentCatalogSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="GetStudentRecord">
      <soap:operation soapAction="https://bhaidar.net/GetStudentRecord" style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="StudentCatalogSoap12" type="tns:StudentCatalogSoap">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:operation name="GetStudentRecord">
      <soap12:operation soapAction="https://bhaidar.net/GetStudentRecord" style="document" />
      <wsdl:input>
        <soap12:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="StudentCatalog">
    <wsdl:port name="StudentCatalogSoap" binding="tns:StudentCatalogSoap">
      <soap:address location="http://localhost/StudentCatalogService/StudentCatalog.asmx" />
    </wsdl:port>
    <wsdl:port name="StudentCatalogSoap12" binding="tns:StudentCatalogSoap12">
      <soap12:address location="http://localhost/StudentCatalogService/StudentCatalog.asmx" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

 

It took me less than a minute to customize the WSDL Document for my needs. This is just to tell you how easy it is to configure the template, but off course when you get more operation, it will take some more time. Add the above WSDL document to the Web service project, and hence its path will be something as:

http://localhost/StudentCatalogService/StudentCatalog.wsdl

 

5. Generating the data type objects and Interface contract:

Now that you have the WSDL Document created, it is time to create a new assembly that holds an object representation for the data types created above inside the XML Schema section. In addition, I will create an interface that contains the method signatures to be implemented by the Web service and the business components. To do so, I will use a utility called WSDL.EXE that ships with the .NET framework.

Now, run the Visual Studio Command  Line with the following:

C:\>wsdl.exe /si  /namespace:StudentCatalogTypes /o:StudentCatalog.cs http://localhost/StudentCatalogService/StudentCatalog.wsdl

 

The above line shall generate a new C# object called StudentCatalog that holds an interface (IStudentCatalogSoap) and an object representing the StudRec object as follows:

namespace StudentCatalogTypes {

    using System.Diagnostics;
    using System.Web.Services;
    using System.ComponentModel;
    using System.Web.Services.Protocols;
    using System;
    using System.Xml.Serialization;

    public interface IStudentCatalogSoap {
        [return: System.Xml.Serialization.XmlElementAttribute("StudRec", Namespace="https://bhaidar.net/Schemas/StudentCatalog/")]
        StudRec GetStudentRecord([System.Xml.Serialization.XmlElementAttribute(Namespace="https://bhaidar.net/Schemas/StudentCatalog/")] int StudRecID);
    }

    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="https://bhaidar.net/Schemas/StudentCatalog/")]
    public partial class StudRec {
        private int idField;
        private string lastNameField;
        private string firstNameField;
        /// <remarks/>
        public int ID {
            get {
                return this.idField;
            }
            set {
                this.idField = value;
            }
        }
        /// <remarks/>
        public string LastName {
            get {
                return this.lastNameField;
            }
            set {
                this.lastNameField = value;
            }
        }
        /// <remarks/>
        public string FirstName {
            get {
                return this.firstNameField;
            }
            set {
                this.firstNameField = value;
            }
        }
    }
}

 

Now that a new interface has been created together with a C# object for the StudRec XML Schema.

Add a new Class Library (StudentCatalogTypes) project and place this class inside it. Now build the Class Library and now you got a new assembly (StudentCatalogTypes.dll) that contains the data types for all the messages interchanged and an interface that dictates the methods to be implemented by the Web service.

 

6. Create a new assembly to hold the business components:

The business component to be created in this section shall implement the interface created above and hence provide the real processing and implementation for the methods to be provided by the Web service. For the sake of this article, I will have a single method to be implemented in this assembly:

using System;
using System.Collections.Generic;
using System.Text;

namespace StudentCatalogBusiness
{
    public class StudentCatalogBusiness : StudentCatalogTypes.IStudentCatalogSoap
    {
        #region IStudentCatalogSoap Members

        /// <summary>
        /// Create a new StudentRecord
        /// </summary>
        /// <param name="StudRecID">Student Record ID</param>
        /// <returns>An object of type StudRec</returns>
        public StudentCatalogTypes.StudRec GetStudentRecord(int StudRecID)
        {
            StudentCatalogTypes.StudRec studentRec = new StudentCatalogTypes.StudRec();
            studentRec.ID = 1;
            studentRec.FirstName = "Bilal";
            studentRec.LastName = "Haidar";

            return studentRec;
        }

        #endregion
    }
}

 

After completing this step, we have two assemblies: StudentCatalogTypes and StudentCatalogBusiness. Now as you can see, the functionality has been created through these two assemblies. A new Web application or Windows application can be created to access that functionality. This is very important, you can see that we can live without the Web service. What is left now is to create the Web service.

 

7. Create a new Web service and implement the contract interface:

I will add a new Web service called: StudentCatalog.asmx. In the code-behind file I will implement the IStudentCatalogSoap interface:

using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;

using StudentCatalogTypes;
using StudentCatalogBusiness;

[WebService(Namespace = "https://bhaidar.net/Schemas/StudentCatalog/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class StudentCatalog : System.Web.Services.WebService, IStudentCatalogSoap
{

    #region IStudentCatalogSoap Members

    [WebMethodAttribute()]
    [SoapDocumentMethodAttribute("https://bhaidar.net/Schemas/StudentCatalog/GetStudentRecord", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
    [return: System.Xml.Serialization.XmlElementAttribute("StudRec", Namespace = "https://bhaidar.net/Schemas/StudentCatalog/")]
    public StudRec GetStudentRecord(int StudRecID)
    {
        StudentCatalogBusiness.StudentCatalogBusiness studCatBus = new StudentCatalogBusiness.StudentCatalogBusiness();
        StudRec studentRecord = studCatBus.GetStudentRecord(StudRecID);

        return studentRecord;
    }

    #endregion
}

 

As you can see, I implemented the IStudentCatalogSoap interface and provided implementation for the single method found in that interface. Look at the code inside the GetStudentRecord and you will notice that the Web service itself didn't do any work. It delegated the work for the Business component!

Notice the return attribute that has been added to the method which specifies the XML Schema element type to be returned as an XmlElementAttribute and providing the same namesapce for the Web service and the XML Schema.

 

That's it. Now you are ready to consume your Web service from any client application you need.

You can download the complete code of this article from here.

Here is a schematic for the entire process and how the components are interacting with each other:

diagram

 

I truly hope you enjoyed the article and learned some techniques that you can use to improve your work!

Regards

Tags:

Oct 13 2007

XML Schema Designer in VS 2008

Category:Bil@l @ 09:52

I have been trying to find the XML Schema Designer in VS 2008 but couldn't locate it. Is it still there or has been removed?

 

Thanks

Tags:

Oct 11 2007

SP1 for Telerik Controls Released - October Release

Category:Bil@l @ 22:00

Telerik just released an SP1 for the September Q2 release. If you have a licensed copy of Telerik controls or free trials, you can download the new SP1 enhancements from their web site @ www.telerik.com

 

Regards

Tags:

Oct 10 2007

Language translator from Live.com

Category:Bil@l @ 07:58

I would like to point you to a new language translator from live.com. It is still in its Beta version, but not bad up to this point.

I did some trials to translate English to Arabic (my native language) and any person who understands Arabic can make sense of what is being translated!!

 

Check it here: http://translator.live.com/Default.aspx

Regards

Tags:

Oct 9 2007

Creating Custom Web Validation Textbox Series

Category:Bil@l @ 11:17

I would like to point you to a series of articles on creating a Custom Web Validation Textbook control in ASP.NET 2.0. Check the link:

http://www.themastech.net/Tutorials/ValidationTextBox/Part1.aspx

Regards

Tags:

Oct 5 2007

New Videos on www.asp.net

Category:Bil@l @ 19:45

I would like to inform you that there are 3 new videos published on the www.asp.net website:

 

Hope you enjoy them!
Regards 

 

Tags:

Oct 4 2007

Inline-Edit Control Using ASP.NET 2.0 AJAX 1.0 Extensions

Category:Bil@l @ 07:36

I kindly invite you to check my latest article on the www.aspalliance.com.

 

In this article Bilal Haidar will show you how to develop a Microsoft ASP.NET AJAX 1.0 Inline-Edit control that can be used to provide on-the-spot text editing for specific areas on a web form.

http://aspalliance.com/1444

 

Hope you enjoy it!

Regards

Tags:

Oct 3 2007

ASP.NET 2.0 AJAX InlineEditLabel Control

Category: AJAX-ATLASBil@l @ 21:10

Today, I will have a new article on inline-edit control using ASP.NET 2.0 AJAX Extensions published on www.aspalliance.com. That script I wrote was based on a script written by native AJAX. It was simply an ASP.NET 2.0 AJAX Component and not a real control.

I have created lately a new ASP.NET 2.0 AJAX Control called InlineEditLabel control. This is simply an ASP.NET 2.0 AJAX Custom Server Control that you can add to your toolbox and drag it to the ASPX page whenever you need to provide an inline-edit area(s) on your pages.

The idea of this control is that, initially the control displays normal text. When you click on the text, then the text displayed will be now placed inside a textarea  with two buttons: Update and Cancel buttons.

Clicking on the update button, fires a client side event handler that allows developer to handle processing the entered text and the cancel button will put the control back to its original state.

inline-edit

All what you need is download this sample application which contains the InlineEditLabel.dll and a sample page that shows how to use the control. This control runs under .NET 3.5 and VS 2008 Beta 2.

To explain a bit about the control, let us check this sample:

<cc1:InlineEditLabel
    ID="InlineEditLabel1"
    runat="server"
    Text="This is a default text to be changed during the demo!!"
    ToolTip="Click here to edit"
    CssClass=""
    CssHoverClass="hover"
    UpdateButtonText="Update"
    CancelButtonText="Cancel"
    UpdateEvent="OnUpdate"
/>

As you can see, the custom control is called InlineEditLabel. It has the following properties:

ID: ID of the control

Text: This is the text to be shown when the control is to be rendered.

Tooltip: This is the text that is displayed when the mouse gets over the editable text.

CssClass: This is a css class to apply to the editable label represented by "div" element.

CsshoverClass: This is a css class that is applied to the control when the mouse gets over its content.

UpdateButtonText: This is the text shown on the update button that is called to update the entered text.

CancelButtonText: This is the text shown on the cancel button that is used to cancel an update.

In addition, there is one client side event that you need to implement which is UpdateEvent. This event handler is fired when you press the update button to process the entered text.

Now let us add some implementation on the UpdateEvent:

<script language="javascript">
    function OnUpdate(sender, args)
    {
        alert(args.get_data());
        $find('<%= InlineEditLabel1.ClientID %>').set_originalText(args.get_data() + " -- ");
        $find('<%= InlineEditLabel1.ClientID %>')._renderOriginalContents();
    }
</script>

As you can see in the handler above, the args parameters holds the text entered into the textarea. You can grab that text, either perform:

. WebRequest
. Call page method
. Call Webservice method

to reflect the changes on the server.

When the control is in the processing state, it shows a message "saving ...". So it is recommended that you reset the text you want in the control after processing the text entered on the server. This can be easily done by setting the originalText property and calling the _renderOriginalContents() method.

Hope you enjoyed this new control, if you have any questions, please let me know.

Regards

Tags:

Oct 3 2007

Releasing Source Code for the .NET Framework Libraries

Category:Bil@l @ 20:17

I was surprised to read a post on Scott Guthrie's blog that the .NET Framework Libraries have been released for public!!! You can now debug code and enter directly to the .NET Framework code, that is so cool from Microsoft!!!

 

Can we call the Microsoft .NET Framework now, Microsoft Open Source .NET Framework :)

 

Have a look at this post by Scott: http://weblogs.asp.net/scottgu/archive/2007/10/03/releasing-the-source-code-for-the-net-framework-libraries.aspx

 

Hope this helps,
Regards

Tags:

Oct 3 2007

Private Field initialization in ASP.NET AJAX

Category:Bil@l @ 14:10

I will be publishing my first version of the Inline-Edit control on October 4, 2007 on www.aspalliance.com. That control is based on another non-ASP.NET AJAX control. So two days ago I started working on a new version of the Inline-Edit control that is purely an ASP.NET AJAX Control.

I noticed something very nice to share:

When you define private fields in AJAX inside the class constructor and add to it the set/get methods, as properties, then if you don't provide values for these two properties when you use the $create method to create a new instance of that control, the set methods are never called.

 

However, sometimes you might need to give some initialization values for those private fields, so where is the best place to do so? I thought of using the getters and setters but as I explained above, it doesn't help.

What you can do is simply provide the initialization data inside the constructor as the following:

Bhaidar.AJAX.Controls.InlineEditLabel = function(element) {
    Bhaidar.AJAX.Controls.InlineEditLabel.initializeBase(this, [element]);
    this._toolTip= '';
    this._updateButtonText = 'Update';
}

The above sample code is part of the new inline-edit control I am developing. So now, even if the developer didn't provide some text to the updateButonText, she will be able to show the default text specified in the constructor.

 

Hope this helps,

Regards

Tags: