HTTP Handlers and HTTP Modules in ASP.NET

By Mansoor Ahmed Siddiqui

Rating: 4.4 out of 5
Rate this article


  • print this article

  • email this article to a colleague

  • suggest an article
  • Introduction

    flex

    accessunit

    In the Internet world, Web servers serve resources that have been put
    on the Internet and provide other services like security, logging, etc.

    At the beginning of the Internet era, clients’ needs were very
    limited; .htm files were often satisfactory. As time passed, however,
    clients’ requirements extended beyond the functionality contained in
    .htm files or static files.

    Developers needed a way to extend or complement the functionality of
    Web servers. Web server vendors devised different solutions, but they
    all followed a common theme: "Plug some component into the Web server".
    All Web server complement technologies allowed developers to create and
    plug in components for enhancing Web server functionality. Microsoft
    came up with ISAPI (Internet Server API); Netscape came up with NSAPI
    (Netscape Server API), etc.

    ISAPI is an important technology that allows us to enhance the
    capabilities of an ISAPI-compliant Web server (IIS is an
    ISAPI-compliant Web server). The following components serve this
    purpose:

    • ISAPI Extensions
    • ISAPI Filters

    ISAPI extensions are implemented by using Win32 DLLs. You can think
    of an ISAPI extension as a normal application. ISAPI extensions are the
    target of http requests. That means you must call them to activate
    them. For example, the following URL calls the store.dll ISAPI
    extension and passes two values to it:

    http://www.myownwebsite.com/Store.dll?sitename=15seconds&location=USA

    Think of an ISAPI filter as just that: a filter. It sits between
    your Web server and the client. Every time a client makes a request to
    the server, it passes through the filter.

    Clients do not specifically target the filter in their
    requests, rather, clients simply send requests to the Web server, and
    then the Web server passes that request to the interested filters.

    Filters can then modify the request, perform some logging operations, etc.

    It was very difficult to implement these components because of
    the complexities involved. One had to use C/C++ to develop these
    components, and for many, development in C/C++ is a pain.

    So what does ASP.NET offer to harness this functionality? ASP.NET offers HttpHandlers and HttpModules.

    Before going into the details of these components, it is worth
    looking at the flow of http requests as it passes through the HTTP
    modules and HTTP handlers.


    Setting up the Sample Applications

    I have created the following C# projects, which demonstrate different components of the application.

    • NewHandler (HTTP handler)
    • Webapp (Demonstrates HTTP handler)
    • SecurityModules (HTTP module)
    • Webapp2 (Demonstrated HTTP module)

    To install the applications:

    • Extract all the code from the attached zip file.
    • Create two virtual directories named webapp and webapp2;
      point these directories to the actual physical folders for the Webapp
      and Webapp2 web applications.
    • Copy the Newhandler.dll file from the NewHandler project into the bin directory of webapp web application.
    • Copy the SecurityModules.dll file from the SecurityModules project into the bin directory of webapp2 web application.

    ASP.NET Request Processing

    ASP.NET
    request processing is based on a pipeline model in which ASP.NET passes
    http requests to all the modules in the pipeline. Each module receives
    the http request and has full control over it. The module can play with
    the request in any way it sees fit. Once the request passes through all
    of the HTTP modules, it is eventually served by an HTTP handler. The
    HTTP handler performs some processing on it, and the result again
    passes through the HTTP modules in the pipeline.

    The following figure describes this flow.

    Notice that during the processing of an http request, only one HTTP
    handler will be called, whereas more than one HTTP modules can be
    called.

    Http Handlers

    HTTP
    handlers are the .NET components that implement the
    System.Web.IHttpHandler interface. Any class that implements the
    IHttpHandler interface can act as a target for the incoming HTTP
    requests. HTTP handlers are somewhat similar to ISAPI extensions. One
    difference between HTTP handlers and ISAPI extensions is that HTTP
    handlers can be called directly by using their file name in the URL,
    similar to ISAPI extensions.

    HTTP handlers implement the following methods.

    Method Name Description
    ProcessRequest This method is actually the heart of all http handlers. This method is called to process http requests.
    IsReusable This property is called to determine whether
    this instance of http handler can be reused for fulfilling another
    requests of the same type. HTTP handlers can return either true or
    false in order to specify whether they can be reused.

    These classes can be mapped to http requests by using the web.config or
    machine.config file. Once that is done, ASP.NET will instantiate http
    handler whenever the corresponding request comes in. We will see how to
    specify all of these details in web.config and/or machine.config files.

    ASP.NET also supports the creation of http handlers by means of
    the IHttpHandlerFactory interface. ASP.NET provides the capability of
    routing http requests to an object of the class that implements the
    IHttpHandlerFactory interface. Here, ASP.NET utilizes the Factory
    design pattern. This pattern provides an interface for creating
    families of related objects without specifying their concrete classes.
    In simple terms, you can consider such a class as a factory that
    creates http handler objects depending on the parameters passed to it.
    We don’t have to specify a particular http handler class to
    instantiate; http handler factory takes care of it.
    The benefit of this is if in the future the implementation of the
    object that implements the IHttpHandler interface changes, the
    consuming client is not affected as long as the interface remains the
    same.

    These are following methods in IHttpHandlerFactory interface:

    Method Name Description
    GetHandler This method is responsible for creating the
    appropriate handler and returns the reference out to the calling code
    (the ASP.NET runtime). Handler object returned by this method should
    implement the IHttpHandler interface.
    ReleaseHandler This method is responsible for releasing
    the http handler once request processing is complete. The
    implementation of the factory decides what it should do. Factory
    implementation can either actually destroy the instance or return it to
    a pool for future requests.

    Registering HTTP Handlers and HTTP Handler Factories in Configuration Files

    ASP.NET maintains its configuration information in the following configuration files:

    • machine.config
    • web.config

    machine.config file contains the configuration settings that apply to all the Web applications installed on that box.

    web.config file is specific to each Web application. Each Web
    application can have its own web.config file. Any sub directory of a
    Web application may have its own web.config file; this allows them to
    override the settings imposed by the parent directories.

    We can use <httpHandlers> and <add> nodes for
    adding HTTP handlers to our Web applications. In fact the handlers are
    listed with <add> nodes in between <httpHandlers> and
    </httpHandlers> nodes. Here is a generic example of adding an
    HTTP handler:


    <httpHandlers>
    <add verb="supported http verbs" path="path" type="namespace.classname, assemblyname" />
    <httpHandlers>

    In the above XML,

    • The verb attribute specifies the HTTP verbs supported by the
      handler. If the handler supports all of the HTTP verbs, simply use "*",
      otherwise list the supported verbs in a comma separated list. So if
      your handler supports only HTTP GET and POST, then verb attribute will
      be "GET, POST".
    • The path attribute specifies the path or wildcard
      specification of the files for which this handler will be invoked. For
      example, if you want your handler to be called only when test.xyz file
      is requested, then the path attribute will contain "test.xyz";
      similarly if you want your handler called for any file having .xyz
      extension, the path attribute will contain "*.xyz".
    • The type attribute specifies the actual type of the
      handler or handler factory in the form of a combination of namespace,
      class name and assembly name. ASP.NET runtime first searches the
      assembly DLL in the application’s bin directory and then searches in
      the Global Assembly Cache (GAC).

    Use of HTTP Handlers by the ASP.NET Runtime

    Believe
    it or not, ASP.NET uses HTTP handlers for implementing a lot of its own
    functionality. ASP.NET uses handlers for processing .aspx, .asmx, .soap
    and other ASP.NET files.

    The following is the snippet from the machine.config file:


    <httpHandlers>
    <add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler"/>

    <add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>

    <add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory"/>

    <add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler"/>

    <add verb="GET,HEAD" path="*" type="System.Web.StaticFileHandler"/>

    . . . . . .
    . . . . . .
    </httpHandlers>

    You can see in the above configuration that all the requests for .aspx
    files are processed by the System.Web.UI.PageHandlerFactory class.
    Similarly all the requests for .config and other files, which should
    not be directly accessible to the clients, are handled by the
    System.Web.HttpForbiddenHandler class. As you might have already
    guessed, this class simply returns an error to the client stating that
    these kinds of files are not served.

    Implementing HTTP Handlers

    Now
    we will see how to implement an HTTP handler. So what should our new
    handler do? Well, as I stated above, handlers are mostly used for
    adding new functionalities to Web servers; therefore, we will create a
    handler that handles new types of files, files that have a .15seconds
    extension. Once we implement this handler and register it in the
    web.config file of our Web application, all requests for .15seconds
    files will be handled by this new handler.

    You might be thinking about the use of such a handler. Well,
    what if you want to introduce a new kind of server scripting language
    or dynamic server file such as asp, aspx? You can write your own
    handler for this. Similarly, what will you do if you want to run Java
    servlets, JSPs and other server side Java components on IIS? One way of
    doing this is to install some ISAPI extension like Allaire or
    Macromedia Jrun. Or you can write your own HTTP handler. Although it is
    a difficult task for third-party vendors like Allaire and Macromedia,
    it is a very attractive option because their HTTP handlers will have
    access to all the new functionalities exposed by the ASP.NET runtime.

    Steps involved in implementing our HTTP handler are as follows:

    1. Write a class which implements IHttpHandler interface
    2. Register this handler in web.config or machine.config file.
    3. Map the file extension (.15seconds) to ASP.NET ISAPI extension DLL (aspnet_isapi.dll) in Internet Services Manager.

    Step1
    Create a new C# Class Library project in Visual
    Studio.NET and name it "MyHandler". Visual Studio.NET will
    automatically add a class named "Class1.cs" into the project. Rename it
    "NewHandler"; open this class in the code window and change the class
    name and constructor name to "NewHandler".

    The following is the code for the NewHandler class.


    using System;
    using System.Web;

    namespace MyHandler
    {
    /// <summary>
    /// Summary description for NewHandler.
    /// </summary>
    public class NewHandler : IHttpHandler
    {
    public NewHandler()
    {
    //
    // TODO: Add constructor logic here
    //
    }

    #region Implementation of IHttpHandler
    public void ProcessRequest(System.Web.HttpContext context)
    {
    HttpResponse objResponse = context.Response ;
    objResponse.Write("<html><body><h1>Hello 15Seconds Reader ") ;
    objResponse.Write("</body></html>") ;
    }

    public bool IsReusable
    {
    get
    {
    return true;
    }
    }
    #endregion
    }
    }

    As you can see in the ProcessRequest method, the HTTP handler has
    access to all ASP.NET intrinsic objects passed to it in its parameter
    through the System.Web.HttpContext object. Implementing the
    ProcessRequest method is simply extracting the HttpResponse object from
    the context object and then sending some HTML out to the client.
    Similarly, IsReusable returns true to designate that this handler can
    be reused for processing the other HTTP requests.

    Let’s compile it and place it in the bin directory of the webapp virtual directory.

    Step 2
    Register this handler by adding the following text in the web.config file:


    <httpHandlers>
    <add verb="*" path="*.15seconds" type="MyHandler.NewHandler,MyHandler"/>
    </httpHandlers>

    Step 3
    Since we are creating a handler for handling files of
    a new extension, we also need to tell IIS about this extension and map
    it to ASP.NET. If we don’t perform this step and try to access the Hello.15seconds
    file, IIS will simply return the file rather than pass it to ASP.NET
    runtime. As a consequence, the HTTP handler will not be called.

    Launch the Internet Services Manager tool, right click on Default Web Site, select Properties, go to Home Directory tab and press Configuration button. This will popup Application Configuration dialog. Click Add button and fill the Executable field with the path to the aspnet_isapi.dll file and fill .15seconds in the Extension field. Leave the other fields as is; the dialog box should look as follows:

    Close the Application Configuration and Default Web Site Properties dialog boxes by pressing the OK button.

    Now we are good to go. Launch Internet Explorer and go to the following url:

    http://localhost/webapp/hello.15seconds

    You should see the following page:

    Session State in HTTP Handlers

    Maintaining
    session state is one of the most common tasks that Web applications
    perform. HTTP handlers also need to have access to the session state.
    But session state is not enabled by default for HTTP handlers. In order
    to read and/or write session data, HTTP handlers are required to
    implement one of the following interfaces:

    • IRequiresSessionState
    • IReadOnlySessionState.

    An HTTP handler should implement the IRequiresSessionState interface
    when it requires read-write access to the session data. If a handler
    only needs read access to session data, then it should only implement
    the IReadOnlySessionState interface.

    Both of these interfaces are just marker interfaces and do not
    contain any methods. So if we want to enable session state for our
    NewHandler handler, then declare the NewHandler class as followed:


    public class NewHandler : IHttpHandler, IRequiresSessionState

    HTTP Modules

    HTTP
    modules are .NET components that implement the System.Web.IHttpModule
    interface. These components plug themselves into the ASP.NET request
    processing pipeline by registering themselves for certain events.
    Whenever those events occur, ASP.NET invokes the interested HTTP
    modules so that the modules can play with the request.

    An HTTP module is supposed to implement the following methods of the IHttpModule interface:

    Method Name Description
    Init This method allows an HTTP module to register its event handlers to the events in the HttpApplication object.
    Dispose This method gives HTTP module an opportunity to perform any clean up before the object gets garbage collected.

    An HTTP module can register for the following events exposed by the System.Web.HttpApplication object.

    Event Name Description
    AcquireRequestState This event is raised when ASP.NET runtime is ready to acquire the Session state of the current HTTP request.
    AuthenticateRequest This event is raised when ASP.NET runtime is ready to authenticate the identity of the user.
    AuthorizeRequest This event is raised when ASP.NET runtime is ready to authorize the user for the resources user is trying to access.
    BeginRequest This event is raised when ASP.NET runtime receives a new HTTP request.
    Disposed This event is raised when ASP.NET completes the processing of HTTP request.
    EndRequest This event is raised just before sending the response content to the client.
    Error This event is raised when an unhandled exception occurs during the processing of HTTP request.
    PostRequestHandlerExecute This event is raised just after HTTP handler finishes execution.
    PreRequestHandlerExecute This event is raised just
    before ASP.NET begins executing a handler for the HTTP request. After
    this event, ASP.NET will forward the request to the appropriate HTTP
    handler.
    PreSendRequestContent This event is raised just before ASP.NET sends the response contents to
    the client. This event allows us to change the contents before it gets
    delivered to the client. We can use this event to add the contents,
    which are common in all pages, to the page output. For example, a
    common menu, header or footer.
    PreSendRequestHeaders This event is raised just before ASP.NET sends the HTTP response
    headers to the client. This event allows us to change the headers
    before they get delivered to the client. We can use this event to add
    cookies and custom data into headers.
    ReleaseRequestState This event is raised after ASP.NET finishes executing all request handlers.
    ResolveRequestCache This event is raised to determine whether the request can be fulfilled
    by returning the contents from the Output Cache. This depends on how
    the Output Caching has been setup for your web application.
    UpdateRequestCache This event is raised when ASP.NET has completed processing the current
    HTTP request and the output contents are ready to be added to the
    Output Cache. This depends on how the Output Caching has been setup for
    your Web application.

    Apart from these events, there are four more events that we can use. We
    can hook up to these events by implementing the methods in the
    global.asax file of our Web application.

    These events are as follows:

    • Application_OnStart
      This event is raised when the very first request arrives to the Web application.
    • Application_OnEnd
      This event is raised just before the application is going to terminate.
    • Session_OnStart
      This event is raised for the very first request of the user’s session.
    • Session_OnEnd
      This event is raised when the session is abandoned or expired.

    Registering HTTP Modules in Configuration Files

    Once
    an HTTP module is built and copied into the bin directory of our Web
    application or copied into the Global Assembly Cache, then we will
    register it in either the web.config or machine.config file.

    We can use <httpModules> and <add> nodes for adding
    HTTP modules to our Web applications. In fact the modules are listed by
    using <add> nodes in between <httpModules> and
    </httpModules> nodes.

    Since configuration settings are inheritable, the child directories
    inherit configuration settings of the parent directory. As a
    consequence, child directories might inherit some unwanted HTTP modules
    as part of the parent configuration; therefore, we need a way to remove
    those unwanted modules. We can use the <remove> node for this.

    If we want to remove all of the inherited HTTP modules from our application, we can use the <clear> node.

    The following is a generic example of adding an HTTP module:


    <httpModules>
    <add type="classname, assemblyname" name="modulename" />
    <httpModules>

    The following is a generic example of removing an HTTP module from your application.


    <httpModules>
    <remove name="modulename" />
    <httpModules>

    In the above XML,

    • The type attribute specifies the actual type of the HTTP module in the form of class and assembly name.
    • The name attribute specifies the friendly name for the
      module. This is the name that will be used by other applications for
      identifying the HTTP module.

    Use of HTTP Modules by the ASP.NET Runtime

    ASP.NET
    runtime uses HTTP modules for implementing some special features. The
    following snippet from the machine.config file shows the HTTP modules
    installed by the ASP.NET runtime.


    <httpModules>
    <add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
    <add name="Session" type="System.Web.SessionState.SessionStateModule"/>
    <add name="WindowsAuthentication"
    type="System.Web.Security.WindowsAuthenticationModule"/>
    <add name="FormsAuthentication"
    type="System.Web.Security.FormsAuthenticationModule"/>
    <add name="PassportAuthentication"
    type="System.Web.Security.PassportAuthenticationModule"/>
    <add name="UrlAuthorization"
    type="System.Web.Security.UrlAuthorizationModule"/>
    <add name="FileAuthorization"
    type="System.Web.Security.FileAuthorizationModule"/>
    </httpModules>

    All of the above HTTP modules are used by ASP.NET to provide
    services like authentication and authorization, session management and
    output caching. Since these modules have been registered in
    machine.config file, these modules are automatically available to all
    of the Web applications.

    Implementing an HTTP Module for Providing Security Services

    Now
    we will implement an HTTP module that provides security services for
    our Web application. Our HTTP module will basically provide a custom
    authentication service. It will receive authentication credentials in
    HTTP request and will determine whether those credentials are valid. If
    yes, what roles are the user associated with? Through the User.Identity
    object, it will associate those roles that are accessible to our Web
    application pages to the user’s identity.

    Following is the code of our HTTP module.


    using System;
    using System.Web;
    using System.Security.Principal;

    namespace SecurityModules
    {
    /// <summary>
    /// Summary description for Class1.
    /// </summary>

    public class CustomAuthenticationModule : IHttpModule
    {
    public CustomAuthenticationModule()
    {
    }
    public void Init(HttpApplication r_objApplication)
    {
    // Register our event handler with Application object.
    r_objApplication.AuthenticateRequest +=
    new EventHandler(this.AuthenticateRequest) ;
    }

    public void Dispose()
    {
    // Left blank because we dont have to do anything.
    }

    private void AuthenticateRequest(object r_objSender,
    EventArgs r_objEventArgs)
    {
    // Authenticate user credentials, and find out user roles.
    1. HttpApplication objApp = (HttpApplication) r_objSender ;
    2. HttpContext objContext = (HttpContext) objApp.Context ;
    3. if ( (objApp.Request["userid"] == null) ||
    4. (objApp.Request["password"] == null) )
    5. {
    6. objContext.Response.Write("<H1>Credentials not provided</H1>") ;
    7. objContext.Response.End() ;
    8. }

    9. string userid = "" ;
    10. userid = objApp.Request["userid"].ToString() ;
    11. string password = "" ;
    12. password = objApp.Request["password"].ToString() ;

    13. string[] strRoles ;
    14. strRoles = AuthenticateAndGetRoles(userid, password) ;
    15. if ((strRoles == null) || (strRoles.GetLength(0) == 0))
    16. {
    17. objContext.Response.Write("<H1>We are sorry but we could not
    find this user id and password in our database</H1>") ;
    18. objApp.CompleteRequest() ;
    19. }

    20. GenericIdentity objIdentity = new GenericIdentity(userid,
    "CustomAuthentication") ;
    21. objContext.User = new GenericPrincipal(objIdentity, strRoles) ;
    }

    private string[] AuthenticateAndGetRoles(string r_strUserID,
    string r_strPassword)
    {
    string[] strRoles = null ;
    if ((r_strUserID.Equals("Steve")) &&
    (r_strPassword.Equals("15seconds")))
    {
    strRoles = new String[1] ;
    strRoles[0] = "Administrator" ;
    }
    else if ((r_strUserID.Equals("Mansoor")) &&
    (r_strPassword.Equals("mas")))
    {
    strRoles = new string[1] ;
    strRoles[0] = "User" ;
    }
    return strRoles ;
    }
    }
    }

    Let’s explore the code.

    We start with the Init function. This function plugs in our handler
    for the AuthenticateRequest event into the Application object’s event
    handlers list. This will cause the Application object to call this
    method whenever the AuthenticationRequest event is raised.

    Once our HTTP module is initialized, its AuthenticateRequest
    method will be called for authenticating client requests.
    AuthenticateRequest method is the heart of the security/authentication
    mechanism. In that function:

    Line 1 and Line 2 extract the HttpApplication and HttpContext
    objects.
    Line 3 through Line 7 checks whether any of the userid or password is
    not provided to us. If this is the case, error is displayed and the
    request processing is terminated.

    Line 9 through Line 12 extract the user id and password from the HttpRequest object.

    Line 14 calls a helper function, named AuthenticateAndGetRoles.
    This function basically performs the authentication and determines the
    user role. This has been hard-coded and only two users are allowed, but
    we can generalize this method and add code for interacting with some
    user database to retrieve user roles.

    Line 16 through Line 19 checks whether the user has any role
    assigned to it. If this is not the case that means the credentials
    passed to us could not be verified; therefore, these credentials are
    not valid. So, an error message is sent to the client and the request
    is completed.

    Line 20 and Line 21 are very important because these lines
    actually inform the ASP.NET HTTP runtime about the identity of the
    logged-in user. Once these lines are successfully executed, our aspx
    pages will be able to access this information by using the User object.

    Now let’s see this authentication mechanism in action.
    Currently we are only allowing the following users to log in to our
    system:

    • User id = Steve, Password = 15seconds, Role = Administrator
    • User id = Mansoor, Password = mas, Role = User

    Note that user id and password are case-sensitive.

    First try logging-in without providing credentials. Go to
    http://localhost/webapp2/index.aspx and you should see the following
    message.

    Now try logging-in with the user id "Steve" and password
    "15seconds". Go to
    http://localhost/webapp2/index.aspx?userid=Steve&password=15seconds
    and you should see the following welcome message.

    Now try to log-in with the user id "Mansoor" and password
    "15seconds". Go to
    http://localhost/webapp2/index.aspx?userid=Mansoor&password=mas and
    you should see the following welcome page.

    Now try to log-in with the wrong combination of user id and
    password. Go to
    http://localhost/webapp2/index.aspx?userid=Mansoor&password=xyz and
    you should see the following error message.

    This shows our security module in action. You can generalize
    this security module by using database-access code in the
    AuthenticateAndGetRoles method.

    For all of this to work, we have to perform some changes in our
    web.config file. First of all, since we are using our own custom
    authentication, we don’t need any other authentication mechanism. To
    specify this, change the <authentication> node in web.config file
    of webapp2 to look like this:


    <authentication mode="None"/>

    Similarly, don’t allow anonymous users to our Web site. Add the following to web.config file:


    <authorization>
    <deny users="?"/>
    </authorization>

    Users should at least have anonymous access to the file that they
    will use for providing credentials. Use the following configuration
    setting in the web.config file for specifying index.aspx as the only
    anonymously accessible file:


    <location path="index.aspx">
    <system.web>
    <authorization>
    <allow users="*"/>
    </authorization>
    </system.web>
    </location>

    Conclusion

    As
    you might have realized with HTTP handlers and modules, ASP.NET has put
    a lot of power in the hands of developers. Plug your own components
    into the ASP.NET request processing pipeline and enjoy the benefits.

    This article should at least get you started with these
    components. As an exercise, you might want to go and make this sample
    authentication module more flexible and tune it according to your
    needs.

    About the Author

    Mansoor
    Ahmed Siddiqui is a software consultant and technical writer working in
    the United States. He has a masters degree in computer science and been
    involved in software development since 1997. His areas of expertise
    include designing and developing Web-based applications, client-server
    applications, and n-tier applications, with a special focus on
    middle-tier and Win32 programming.

    He has expertise in Microsoft. NET Framework, ASP.NET, C#, Visual
    Studio .NET, Web Services, ADO.NET, ASP, JavaScript, eXtensible Markup
    Language (XML), Simple Object Access Protocol (SOAP), Visual C++,
    Microsoft Foundation Class Library (MFC), Active Template Library
    (ATL), Visual Basic 6.0, ActiveX Data Objects (ADO), COM/DCOM/COM+,
    Microsoft Transaction Server (MTS), Microsoft Message Queue (MSMQ), SQL
    Server 7.0/2000, OMG’s Unified Modeling Language (UML), Rational
    Software Corp.’s Rational Rose, Java, Java Server Page (JSP), servlets,
    Enterprise JavaBeans (EJBs), Java 2 Platform Enterprise Edition (J2EE).
    Currently, he is working with Visual Studio 7.0 and the Microsoft .NET
    platform. He is an MCSD and is Brainbench certified in different
    languages.

    Apart from technical writing, other interests include listening
    to music, swimming, playing cricket and pool, and hanging out with
    friends. He can be reached at mansoorasiddiqui@hotmail.com and ICQ
    151707288.

    This entry was posted in ASP.NET. Bookmark the permalink.

    发表评论

    Fill in your details below or click an icon to log in:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out / 更改 )

    Twitter picture

    You are commenting using your Twitter account. Log Out / 更改 )

    Facebook photo

    You are commenting using your Facebook account. Log Out / 更改 )

    Google+ photo

    You are commenting using your Google+ account. Log Out / 更改 )

    Connecting to %s