How to call a Stored Procedure from Classic ASP

ASP is a program based on Microsoft Technologies that runs inside a web server.

Below is the method used for calling a Stored Procedure in MSSQLSERVER using classic ASP scripting.

The variable SystemDSN holds the value of the Data Source Name that is configured using Odbcad.exe under the SysWow64 folder on the Server. Select the required driver for SQL Server for the DSN configuration to connect to your database.

Set cn = Server.CreateObject("ADODB.Connection")
cn.Open SystemDSN
Set cmd = Server.CreateObject("ADODB.Command")
Set cmd.ActiveConnection = cn
cmd.CommandText = "usp_GetJSON"
cmd.CommandType = adCmdStoredProc

cmd.Parameters.Append(cmd.CreateParameter("@Ticket_Code",adInteger,adParamInput,100, Request.QueryString("inp_ticket_id")))
cmd.Parameters.Append(cmd.CreateParameter("@Username",adVarchar,adParamInput,100000,user))
cmd.Parameters.Append(cmd.CreateParameter("@OperatorID",adVarchar,adParamInput,100000,oprID))

cmd.Parameters.Append(cmd.CreateParameter("@ReturnJson", adVarchar, adParamOutput,100000))
cmd.Execute

'show alert in case of failure.
ReturnValue = cmd.Parameters("@ReturnJson").Value
if ReturnValue <> " " then
  jsonObject = ReturnValue
  'set the flag as 1 to ensure that JSON has been returned from SP to be used later.
  flag= "1"

end if

The above example shows the SP takes 3 input parameters and 1 output parameter. The SP returns a jsonObject assigned to the ReturnValue.

The ADO Connection Object is used to create an open connection to a data source which lets you access and manipulate a database. The ADO Command object is used to execute a single query against a database using which you can perform CRUD operations.

The json can be generated in the SP using the “FOR JSON PATH” feature for SQL Server. However, json is used just for this example. The return value can be anything as per your requirement.

How to read connection strings stored in appsettings file C#

This post is based on a setup of an asp.net core application. Configuration is read in the Startup class upon the Application startup. The Configure method in this class calls the ApiBootstrapper to check whether the connection string for Dev or Production is required.
This can be further used to call the Stored Procedures or query tables using ADO.Net.

Appsettings.json file is the asp.net core config file. This file contains the Connection Strings is as shown below:

{
	"configSetting": {
		"ConnectionStrings": {
			"ProdConnection": "Data Source=ServerName;Initial Catalog=DBProd;UID=username;PWD=password;",
			"DevConnection": "Data Source=ServerName;Initial Catalog=DBDev;UID=username;PWD=password;"
		},
		"Parameters": {
			"IsProduction": true
			"IsDev": false
		}
	}
}
public class Startup
{
	public Startup(IConfiguration configuration)
	{
		Configuration = configuration;
	}
	
	public IConfiguration Configuration { get; }
	
	public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
	{
		////
	
	
		ApiBootstrapper.Initialize(Configuration);
	}
	
}

Below is the code for ApiBootstrapper class:

public class ApiBootstrapper
{
	
	public static void Initialize(IConfiguration configuration)
	{
		CommonUtil.IsProduction = configuration.GetSection(ConfigKeys.configSetting.ToString()).GetSection(ConfigKeys.Log.ToString()).Value.ToString();
		if (Convert.ToBoolean(CommonUtil.IsProduction))
		{
			CommonUtil.ConnectionString = configuration.GetSection("configSetting").GetSection("ConnectionStrings").GetSection("ProdConnection").Value.ToString();
		}
	}
}

The above example shows how we can store Connection Strings for different environments like Dev and Prod and read it based on Config file settings.

Configure Reverse Proxy in IIS with URL Rewrite

Reverse Proxy is an intermediate Server that might be exposed to the Internet that can help secure your incoming traffic from the Client and forwarding the request to a back-end service that might be on a Private network. This returns the response back to the Client and hides your Web Server from the Outside world.

You need the following IIS extensions for configuring IIS Reverse Proxy:

URL Rewrite:
https://www.iis.net/downloads/microsoft/url-rewrite

Application Request Routing:
https://www.iis.net/downloads/microsoft/application-request-routing

Now add the following URL Rewrite rule:

You’ll be prompted to enable the ARR to further enable Proxy functionality. Click on OK.

In the above window, you can also provide the Outbound configuration to map the response URLs From Private URL To Public URL conversions mapping.

For this example, accessing http://localhost:8087 will simply redirect to http://localhost:8084 and serve the Client.

Use package react-svg-radar-chart to create Radar chart ReactJS

Create a basic ReactJS App using the create-react-app Post here.

Our final aim is to generate a Radar Chart using the npmjs package react-svg-radar-chart. Also, the dot markings on the chart should be able to show the current index and key, values on the chart on Hover as shown below.

The code is available in my Github profile.

Install the Package in your Project by running the following command in the Terminal:

npm install react-svg-radar-chart

Replace the code for the index.js file as shown below:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

Create the App.js file for the App component and add the below code:

import React, { Component } from "react";
import MyComp from "./MyComp";
import MyRadarComp from "./MyRadarComp";

export default class App extends Component {
    render() {
        return (
          <div className="App">
            <MyRadarComp />
          </div>
        );
      }
}

Create MyRadarComp.js file and add the below code:

import React from 'react';
 
import RadarChart from 'react-svg-radar-chart';
import 'react-svg-radar-chart/build/css/index.css'
 
export default class MyRadarComp extends React.Component {
  render() {
    const tooltipstyle = {
        position: 'relative',
        display: 'inline-block',
        borderBottom: '1px dotted black'
    }

    const tooltiptextstyle = {
        visibility: 'hidden',
        width: '220px',
        backgroundColor: 'black',
        color: '#fff',
        textAlign: 'center',
        borderRadius: '6px',
        padding: '5px 0',
    
        /* Position the tooltip */
        position: 'absolute',
        zIndex: '1',
    }

 	 const data = [
      {
        data: {
          battery: 0.5,
          design: .7,
          useful: 0.985,
          speed: 0.57,
          weight: 0.7
        },
        meta: { color: 'blue' }
      },
      {
        data: {
          battery: 0.6,
          design: .85,
          useful: 0.5,
          speed: 0.6,
          weight: 0.7
        },
        meta: { color: 'red' }
      },
      {
            data: {
              battery: 0.7,
              design: .8,
              useful: 0.9,
              speed: 0.67,
              weight: 0.8
            },
            meta: { color: '#58FCEC' }
        }
    ];
 
    const captions = {
      // columns
      battery: 'Battery Capacity',
      design: 'Design',
      useful: 'Usefulness',
      speed: 'Speed',
      weight: 'Weight'
    };

    const noSmoothing = points => {
        let d = 'M' + points[0][0].toFixed(4) + ',' + points[0][1].toFixed(4);
        for (let i = 1; i < points.length; i++) {
          d += 'L' + points[i][0].toFixed(4) + ',' + points[i][1].toFixed(4);
        }
        return d + 'z';
      };
       
      const defaultOptions = {
        size: 200,
        axes: true, // show axes?
        scales: 3, // show scale circles?
        captions: true, // show captions?
        captionMargin: 10,
        dots: true, // show dots?
        zoomDistance: 1.2, // where on the axes are the captions?
        setViewBox: (options) => `-${options.captionMargin} 0 ${options.size + options.captionMargin * 2} ${options.size}`, // custom viewBox ?
        smoothing: noSmoothing, // shape smoothing function
        axisProps: () => ({ className: 'axis' }),
        scaleProps: () => ({ className: 'scale', fill: 'none' }),
        shapeProps: () => ({ className: 'shape' }),
        captionProps: () => ({
          className: 'caption',
          textAnchor: 'middle',
          fontSize: 10,
          fontFamily: 'sans-serif'
        }),
        dotProps: () => ({
          className: 'dot',
          mouseEnter: (dot) => { 
              document.getElementById("tooltip").innerText = "index: " + dot.idx + ", key: " + dot.key + ", value: " + dot.value;
              document.getElementById("tooltip").style.visibility = "visible";
            },
          mouseLeave: (dot) => { 
              document.getElementById("tooltip").innerText = "";
              document.getElementById("tooltip").style.visibility = "hidden";
            }
        })
      };
 
    return (
      <div>
        <RadarChart
            captions={{
              // columns
              battery: 'Battery Capacity',
              design: 'Design',
              useful: 'Usefulness',
              speed: 'Speed',
              weight: 'Weight'
            }}
            data={data}
            size={400}
            options={defaultOptions}
          />
          <div id="divtool" style={tooltipstyle}><label id="tooltip" style={tooltiptextstyle}></label></div>
        </div>
    );
  }
}

Run the Project:

npm start

A few points about the MyRadarComp component:

  1. The code is taken from the npmjs package sample provided in the package description.
  2. I’ve modified the css a bit to show the dots on the chart and also show the values on the Hover event of the dots.
  3. The caption labels and the data property names should match in order to correctly display the data.

Using Fetch with React example async await

I’ve created a basic React App as described in my previous post. This is just a demo on how you can use fetch API to load data in the componentDidMount() lifecycle method with/without
async/await. I’ve not used any error handling yet.

The basic structure of the React App contains index.js and index.html files. The code is added to my Github profile.

Replace the code of the index.js file as below:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));

Create App.js file under the src directory and add the below code:

import React, { Component } from "react";
import MyComp from "./MyComp";
export default class App extends Component {
    render() {
        return (
          <div className="App">
            <MyComp />
          </div>
        );
      }
}

It’s time to create MyComp which is the sample component that will call the placeholder JSON API to show the list of users using Fetch GET request.

The code for MyComp is as shown below:

import React from "react";
export default class MyComp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            usernames : []
        };
    }
    componentDidMount() {
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(res => res.json())
            .then(json => this.setState({ usernames: json }));
    }
    render() {
        return(
            <div>
                Hey guys!
                <ul>
                {this.state.usernames.map(user => (
                    <li key={user.username}>
                    Hello, {user.username}
                    </li>
                ))}
                </ul>
            </div>
        );
    }
}

Run the App using as below:

npm start

The above code will now use async/await. It is a clean asynchronous way to call the API by writing unblocking code just like promises and callbacks.

Run the following command in the terminal:

npm i @babel/preset-env @babel/plugin-transform-runtime @babel/runtime --save

Replace the componentDidMount() code as below:

async componentDidMount() {
        const response = await fetch(`https://jsonplaceholder.typicode.com/users`);
        const json = await response.json();
        this.setState({ usernames: json });
    }

The async function which in this case is the componentDidMount contains the await expression that pauses the execution of the async function. It waits until the passed Promise is resolved. It then resumes the async function’s execution and evaluates as the resolved value.

Run the App again to see the results which are the same in this case.

You can also include headers and credentials in the Fetch call as shown below:

const myHeaders = new Headers();
myHeaders.append('token', 'xxxx');
const response = fetch(`http://someurl/home/details?username=someuser`, {
	credentials: 'include',
	headers: myHeaders,
	cors: 'cors'
  });

Managing Custom Errors with Asp.net

You never want your users to see that yellow screen which shows up when a run-time or design-time error occurs in Asp.Net. However, a developer might want to see the error which may help in finding out the issue.

We have the following Custom error modes in Asp.net that can be set in web.config file:

  • Off: shows the actual error on the screen for all users.
  • On: shows only the custom error page and not the error details to all users.
  • RemoteOnly: shows the error details only to the local users where the Application is running. But does not show it to the outside users.

We recently faced a scenario where one of our Asp.Net Application was returning 3xx series status code from IIS Server for non-existent pages. This was flagged as a possible Security flaw by the team.
e.g. https://abc.com/xyz.aspx

So, if the page xyz.aspx does not exist, the Server will return 404 status code by default.

The following CustomErrors setting by default will give 404 status code:

<customErrors mode="Off" defaultRedirect="Error.htm"/>

We have used CustomErrors in our Web.config file which by the default behaviour of Asp.Net will make the IIS send the following response…
• With status code 302: Found, which effectively means a redirect
• Having a Location response header where the resource should be requested (in this case, the generic error page).
In the end, because the generic error page is static and does not change, when that is requested over same session IIS may return the response 304: Not modified.

Asp.Net CustomErrors setting in Web.Config file:

<customErrors mode="On" defaultRedirect="Error.htm"/>

The below setting produces the same result:

<customErrors mode="On" defaultRedirect="Error.htm">
    <error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>

Similarly, you can manage other status codes.

The default behaviour of Asp.Net returning 3xx series status codes is by design for redirect done by Custom Errors and could be a false Security alert.

Prevent form submission with Javascript button click

Suppose you have a html form and you need to prevent the submission of a form based on the input provided in a textbox.
The html input type should be “button” in this case.

<input type="button" value="Submit" onclick="checkInput();">

Below is the Javascript code that gets called on the button click:

function checkInput() {
	var form = document.getElementById('form1');
	var str = document.getElementById("txtBox").value; 
	if (str == "") {
		var r = confirm("Do you want to add the detail in the input box?");
		if (r == true) {
			document.getElementById("txtBox").focus();
		} else {
			form.submit();
		}
	}
	else {
		form.submit();
	}
}

The above code will submit the form if field is not blank. If the field is blank, focus gets set to the textbox field named “txtBox” when clicking on OK button. Clicking on Cancel will again submit the form.