"High speed effective parallel asynchronous web service that can receive and dispatch virtually any data construct"
"No, it's not the Windows .Net web service as you know it..."

PAWS = Parallel Asynchronous Web Service

pawsAlso fondly know as Pretty Awesome Web Stuff. It's not your standard .Net web service done by the book, rather a raw protocol engine capable of being implemented to consume and provide any information structure you can think of, from XML, JSON, binary data streaming to complete SQL table structures and even your own creative structures.

Classic .Net web services work hand in hand with IIS and sessions. Session based web requests tend to be dealt with and processed in a synchronous way, this can cause unwanted wait periods as requests are issued and dealt with one at a time.

Asynchronous vs synchronous Web Services

A demonstration of session bound (thus sequential) web service requests in relation to asynchronous reusable sessionless web service requests.

Purpose: Fill two grids with randomly generated QR Codes produced by the same method, the one is filled using standard web service calls, the other using the asyncronous reusable routable class as shown below, you decide which is best.

Async Web Service

Standard Web Service

AWS Engineering

It all started with frustration waiting for sequences of repetitive tasks via web services to complete. The Idea: Can I wire a function or method directly to a 'web URL call'. The answer is yes, by making use of the routing feature available with .Net 4.0. The goal was to connect a web request with or without payload directly to function.

Routing Setup

In the Global.asax file, ensure to include the 'System.Web.Routing' namespace. Then setup your routing table to point to your function.

<%@ Import Namespace="System.Threading" %>

<%@ Import Namespace="System.Web.Routing" %>

<%@ Import Namespace="System.Globalization" %>

 

<script runat="server">

 

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

        '// Ensure only the resources we want are routed.

        RouteTable.Routes.Ignore("{resource}.axd")

        RouteTable.Routes.Ignore("{resource}.ashx")

        RouteTable.Routes.Ignore("{resource}.js")

        RouteTable.Routes.Ignore("{resource}.css")

        RouteTable.Routes.Ignore("{resource}.png")

        RouteTable.Routes.Ignore("{resource}.jpg")

        RouteTable.Routes.Ignore("{resource}.eps")

        RouteTable.Routes.Ignore("{resource}.pdf")

        RegisterRoutes(RouteTable.Routes)

    End Sub

 

    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)

        ' Code that runs on application shutdown

    End Sub

 

    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)

        ' Code that runs when an unhandled error occurs

    End Sub

 

    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)

        Session.Contents("uid") = Nothing

        'Session.Contents("MyCulture") = LCase(Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName)

    End Sub

 

    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)

        ' Code that runs when a session ends.

        ' Note: The Session_End event is raised only when the sessionstate mode

        ' is set to InProc in the Web.config file. If session mode is set to StateServer

        ' or SQLServer, the event is not raised.

    End Sub

 

    Sub RegisterRoutes(ByVal routes As RouteCollection)

        routes.Add(New Route("generate/qrcode", New generate_qrcode()))

        routes.Add(New Route("generate/pdf", New generate_pdf()))

 

    End Sub

 

    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)

        If (Request.Path.IndexOf(Chr(92)) >= 0 Or System.IO.Path.GetFullPath(Request.PhysicalPath) <> Request.PhysicalPath) Then

            Throw New HttpException(404, "Not Found")

        End If

    End Sub

</script>

<%@ Import Namespace="System.Threading" %>

<%@ Import Namespace="System.Web.Routing" %>

<%@ Import Namespace="System.Globalization" %>

 

<script runat="server">

 

public void Application_Start(object sender, EventArgs e)

{

 // Ensure only the resources we want are routed.

 RouteTable.Routes.Ignore("{resource}.axd");

 RouteTable.Routes.Ignore("{resource}.ashx");

 RouteTable.Routes.Ignore("{resource}.js");

 RouteTable.Routes.Ignore("{resource}.css");

 ;RouteTable.Routes.Ignore("{resource}.png");

 RouteTable.Routes.Ignore("{resource}.jpg");

 RouteTable.Routes.Ignore("{resource}.eps");

 RouteTable.Routes.Ignore("{resource}.pdf");

 RegisterRoutes(RouteTable.Routes);

}

 

public void Application_End(object sender, EventArgs e)

{

 // Code that runs on application shutdown

}

 

public void Application_Error(object sender, EventArgs e)

{

 // Code that runs when an unhandled error occurs

}

 

public void Session_Start(object sender, EventArgs e)

{

 Session.Contents("uid") = null;

 //Session.Contents("MyCulture") = LCase(Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName)

}

 

public void Session_End(object sender, EventArgs e)

{

 // Code that runs when a session ends.

 // Note: The Session_End event is raised only when the sessionstate mode

 // is set to InProc in the Web.config file. If session mode is set to StateServer

 // or SQLServer, the event is not raised.

}

 

public void RegisterRoutes(RouteCollection routes)

{

 routes.Add(new Route("generate/qrcode", new generate_qrcode()));

 routes.Add(new Route("generate/pdf", new generate_pdf()));

 

}

 

public void Application_BeginRequest(object sender, EventArgs e)

{

 if ((Request.Path.IndexOf('\\') >= 0 | System.IO.Path.GetFullPath(Request.PhysicalPath) != Request.PhysicalPath)) {

  throw new HttpException(404, "Not Found");

 }

}

</script>

HTTP Class handler

In order for our class to be able to function as an URL handler we need to implement System.Web.Routing.IRouteHandler. You may notice that all references to 'System.Web.SessionState' and 'IRequiresSessionState' are missing, the reason is as soon as sessionstate is implemented, it becomes syncronous and strictly foloows sessionstate. Besides, testing with sessionstate enabled was dissapointing as access to sessionid was not possible from within the class.

IRouteHandler

The code below shows how to setup and implement a HTTP handler function. In this case it calls a function to generate a random QR code and stream the binary image data back to the requestor. If the QR code generator is not available or fails, a default 'no image' is returned. This routine is for demonstration only, and can be any function or method with any output format or type.

using System;

using System.Collections;

using System.Collections.Generic;

using System.Data;

using System.Diagnostics;

using System.Globalization;

using System.IO;

using System.Xml;

using System.Web;

using System.Configuration;

 

public class generate_qrcode : System.Web.Routing.IRouteHandler

{

 

    public IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)

    {

        HttpHandler MyhttpHandler = new HttpHandler();

        return MyhttpHandler;

    }

 

    public class HttpHandler : IHttpHandler

    {

 

        public bool IsReusable

        {

            get { return true; }

        }

 

        public void ProcessRequest(System.Web.HttpContext context)

        {

            System.Net.ServicePointManager.DefaultConnectionLimit = 65535;

            string sid = HttpContext.Current.Request.QueryString["sid"];

            if ((sid == null))

            {

                return;

            }

            try

            {

                MemoryStream Myinput = new MemoryStream(Utils.GenerateRandomQRCode());

                byte[] Buffer = null;

                Buffer = new byte[Myinput.Length + 1];

                Myinput.Read(Buffer, 0, Buffer.Length);

                Myinput.Close();

                Myinput.Dispose();

                context.Response.Clear();

                context.Response.ContentType = "image/png";

                context.Response.AddHeader("Content-Type", "image/png");

                context.Response.AddHeader("Content-Length", Buffer.Length.ToString());

                context.Response.AddHeader("Content-Transfer-Encoding", "binary");

                context.Response.BinaryWrite(Buffer);

                context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

                context.Response.Cache.SetAllowResponseInBrowserHistory(false);

                context.Response.Flush();

                context.Response.Close();

                GC.Collect();

            }

            catch (Exception ex)

            {

                // Error Handling (Depending on what and how you return to the call, you best deal with the exception here

                NoImage(context);

                return;

            }

        }

 

        public void NoImage(System.Web.HttpContext context)

        {

            // Stream no image

            FileStream Myinput = new FileStream(ConfigurationManager.AppSettings("NoImage"), FileMode.Open, FileAccess.Read);

            byte[] Buffer = null;

            Buffer = new byte[Myinput.Length + 1];

            Myinput.Read(Buffer, 0, Buffer.Length);

            Myinput.Close();

            Myinput.Dispose();

            context.Response.Clear();

            context.Response.ContentType = "image/png";

            context.Response.AddHeader("Content-Type", "image/png");

            context.Response.AddHeader("Content-Length", Buffer.Length.ToString());

            context.Response.AddHeader("Content-Transfer-Encoding", "binary");

            context.Response.BinaryWrite(Buffer);

            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

            context.Response.Cache.SetAllowResponseInBrowserHistory(false);

            context.Response.Flush();

            context.Response.Close();

            GC.Collect();

        }

    }

}

Imports Microsoft.VisualBasic

Imports System.Globalization

Imports System

Imports System.IO

Imports System.Xml

Imports System.Web

Imports System.Configuration

Imports System.Collections.Generic

 

Public Class generate_qrcode

    Implements System.Web.Routing.IRouteHandler

 

    Function GetHttpHandler(requestContext As Routing.RequestContext) As IHttpHandler Implements System.Web.Routing.IRouteHandler.GetHttpHandler

        Dim MyhttpHandler As HttpHandler = New HttpHandler()

        Return MyhttpHandler

    End Function

 

    Public Class HttpHandler

        Implements IHttpHandler

 

        Public ReadOnly Property IsReusable As Boolean Implements System.Web.IHttpHandler.IsReusable

            Get

                Return True

            End Get

        End Property

 

        Public Sub ProcessRequest(context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest

            System.Net.ServicePointManager.DefaultConnectionLimit = 65535

            Dim sid As String = HttpContext.Current.Request.QueryString("sid")

            If IsNothing(sid) Then

                Exit Sub

            End If

            Try

                Dim Myinput As MemoryStream = New MemoryStream(Utils.GenerateRandomQRCode())

                    Dim Buffer() As Byte

                ReDim Buffer(Myinput.Length)

                    Myinput.Read(Buffer, 0, Buffer.Length)

                    Myinput.Close()

                    Myinput.Dispose()

                    context.Response.Clear()

                    context.Response.ContentType = "image/png"

                    context.Response.AddHeader("Content-Type", "image/png")

                    context.Response.AddHeader("Content-Length", Buffer.Length.ToString)

                    context.Response.AddHeader("Content-Transfer-Encoding", "binary")

                    context.Response.BinaryWrite(Buffer)

                    context.Response.Cache.SetCacheability(HttpCacheability.NoCache)

                    context.Response.Cache.SetAllowResponseInBrowserHistory(False)

                    context.Response.Flush()

                    context.Response.Close()

                    GC.Collect()

            Catch ex As Exception

                '// Error Handling (Depending on what and how you return to the call, you best deal with the exception here

                NoImage(context)

                Exit Sub

            End Try

        End Sub

 

        Sub NoImage(context As System.Web.HttpContext)

            '// Stream no image

            Dim Myinput As FileStream = New FileStream(ConfigurationManager.AppSettings("NoImage"), FileMode.Open, FileAccess.Read)

            Dim Buffer() As Byte

            ReDim Buffer(Myinput.Length)

            Myinput.Read(Buffer, 0, Buffer.Length)

            Myinput.Close()

            Myinput.Dispose()

            context.Response.Clear()

            context.Response.ContentType = "image/png"

            context.Response.AddHeader("Content-Type", "image/png")

            context.Response.AddHeader("Content-Length", Buffer.Length.ToString)

            context.Response.AddHeader("Content-Transfer-Encoding", "binary")

            context.Response.BinaryWrite(Buffer)

            context.Response.Cache.SetCacheability(HttpCacheability.NoCache)

            context.Response.Cache.SetAllowResponseInBrowserHistory(False)

            context.Response.Flush()

            context.Response.Close()

            GC.Collect()

        End Sub

    End Class

End Class