Use react-router-dom for client side routing

Create a React app using the create-react-app command. For details, you can check out my other post to get started.

React-router-dom is a package used for Client side routing and you can install it from npm. Since React lets you create Single Page Applications (SPA), you need to use react-router to navigate between different components, changing the browser URL, modifying the browser history, and keeping the UI state in sync. SPA only modifies parts of a page instead of loading entire new pages from a Server.

react-router is the core package for routing, however for web you can use react-router-dom as shown in this demo.

The index.js file will use BrowserRouter from the API which uses the HTML5 History API e.g. http://abc/route/subroute

Our App component will be wrapped inside the BrowserRouter. The Router component can have only one child element.

Code sample below for index.js file:

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./components/App";
import * as serviceWorker from "./serviceWorker";
import { BrowserRouter as Router } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";

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

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

App.js component code:

import React from "react";
import { Route, Switch } from "react-router-dom";
import HomePage from "./home/HomePage";
import AboutPage from "./about/AboutPage";
import Header from "./common/Header";
import PageNotFound from "./PageNotFound";
import CoursesPage from "./courses/CoursesPage";

function App() {
  return (
    <div className="container-fluid">
      <Header />
      <Switch>
        <Route exact path="/" component={HomePage} />
        <Route path="/courses" component={CoursesPage} />
        <Route path="/about" component={AboutPage} />
        <Route component={PageNotFound} />
      </Switch>
    </div>
  );
}

export default App;

Use the Switch component to match the first route that matches the location for rendering and does not look further.
exact property is used to match the URL path exactly. This will match the Home page for “/” path.

What happens when no route matches? We need to handle this scenario with a PageNotfound error page. Path attribute is not used for this Route but only the Component is required.

Link component is used to create links in your application. NavLink is used to add the style attributes to the active routes.

Code for Header section:

import React from "react";
import { NavLink } from "react-router-dom";

const Header = () => {
  const activeStyle = { color: "#F15B2A" };

  return (
    <nav>
      <NavLink to="/" activeStyle={activeStyle} exact>
        Home
      </NavLink>
      {" | "}
      <NavLink to="/courses" activeStyle={activeStyle}>
        Courses
      </NavLink>
      {" | "}
      <NavLink to="/about" activeStyle={activeStyle}>
        About
      </NavLink>
    </nav>
  );
};

export default Header;

You can find the complete code sample here in my github profile under the react-router-dom-demo branch.

Handle client side routes with IIS on Page refresh React App

When trying to handle Client side routing for your React App hosted on IIS say using react-router-dom, you might need to handle situations where users access specific sections of your App like http://testapp/courses. Users might even save these URLs in their favorites and try to access them later.

This problem is not known while debugging the App in localhost until you host the App on an IIS Server. Since your React App is a Single Page Application (SPA), the Server is unaware of any static files like courses and will give 404 error. To solve this, send all your requests back to IIS with URL rewrite to the index.html static file and let the React App handle the routing.

First install the URL Rewrite module on the IIS Server. Then create a web.config file for your App or create a new one with code as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
		<rewrite>
		  <rules>
			<rule name="ReactRouter Routes" stopProcessing="true">
			  <match url=".*" />
			  <conditions logicalGrouping="MatchAll">
				<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
			  </conditions>
			  <action type="Rewrite" url="index.html" />
			</rule>

		  </rules>
		</rewrite>
    </system.webServer>
</configuration>

This should work well for your App when the user tries to access a Client side route and refresh the page or when trying to access the route later.

Serve static json files on IIS hosted React App

When you have a React App hosted on IIS Server, you might need to access the static json files in your application for various purposes like json translations etc.

When you try to access these static files directly in browser or through code e.g. http://app/translation.json, you’ll get a 404 File Not Found error because the MIME type is not set by default in IIS. This is true for any other static file like woff files for fonts.

Under your Web.config file configuration section, place the below sample code within system.webServer tags.

<staticContent>
		<mimeMap fileExtension=".woff" mimeType="application/octet-stream" />
		<mimeMap fileExtension=".json" mimeType="application/json" />
	</staticContent>

The Web.config file is not available by default for a React App. You can either create one manually or make a change in the IIS Server Website configuration which will generate the Web.config file automatically and then you can add the above changes.

Handle WebDriver browser prompt for ADFS credentials Selenium C#

While working on Automating the UI using Selenium C#, you might encounter a scenario where a website requires to be authenticated with ADFS. The browser would prompt the user to provide the AD domain credentials to authorize for accessing the website. So automating this scenario with the Selenium C# API, would require you to provide the domain credentials programatically.

The WebDriver used is Firefox with Geckodriver. Another post explains the working of the automation and initialization of the WebDriver in detail here.

Code sample is as shown below:

public static IWebDriver driverWeb;
driverWeb.Navigate().GoToUrl(link);
try
{
	driverWeb.SwitchTo().Alert().SendKeys("Username" + Keys.Tab + "Password");
	driverWeb.SwitchTo().Alert().Accept();
}
catch { }

try
{
	driverWeb.FindElement(By.Id("acknowledgeCookieId")).Click();
}
catch { }

Take screen-shot of webpage with Firefox and Geckodriver using Selenium with C#

Gecko is a web browser engine used in many applications developed by Mozilla Foundation and the Mozilla Corporation. It is a proxy for using W3C WebDriver-compatible clients to interact with Gecko-based browsers, in this case, Firefox. Gecko Driver acts as the bridge between your script in Selenium and the Firefox browser.

Firefox browser implements the WebDriver protocol using an executable called GeckoDriver.exe. This executable starts a server on your system through which all interaction happens. It translates calls into the Marionette automation protocol by acting as a proxy between the local and remote ends.

To generate the screenshot, the web page will be loaded in the Firefox WebDriver and the height of the window adjusted appropriately. Every GeckoDriver process spawns 4 Firefox processes which you can check through Task Manager. The Preview generation logic can be written as a Web Service and hosted on IIS. The AppPool would require to be run with LocalSystem permission to enable communication between GeckoDriver and Firefox WebDriver.

The below code will run Firefox WebDriver in headless mode:

public static IWebDriver driverWeb;
public static FirefoxOptions optionsFirefox;
static int totalWidth = 1024;
static int additionalHeight = 220;
static int additionalHeightOffset = 2180;
static int normalHeight = 768;
static int explicitWaitTime = 5;

Setup browser profile:

static Firefox()
{
	try
	{
		optionsFirefox = new FirefoxOptions();
		FirefoxProfile profile = new FirefoxProfile();
		profile.SetPreference("permissions.default.desktop-notification", 1);
		profile.AcceptUntrustedCertificates = true; //Accept SSL certificates which have expired
		profile.AssumeUntrustedCertificateIssuer = false; //Firefox assumes untrusted SSL certificates are coming from untrusted issuer 
		profile.SetPreference("general.useragent.override", Convert.ToString(ConfigurationManager.AppSettings["driverUserAgent"]));
		profile.SetPreference("layout.css.devPixelsPerPx", "0.9");
		optionsFirefox.Profile = profile;
		optionsFirefox.AddArgument("-headless");
		KillExistingProcesses();
		initializeWebDriver();
	}
	catch (Exception e)
	{
		throw e;
	}
}

Initialize Web Driver:

public static void initializeWebDriver()
{
	try
	{
		FirefoxDriverService service = FirefoxDriverService.CreateDefaultService(Convert.ToString(ConfigurationManager.AppSettings["driverPath"]));
		service.HideCommandPromptWindow = true;
		driverWeb = null;
		driverWeb = new FirefoxDriver(service, optionsFirefox, new TimeSpan(0, 0, Convert.ToInt16(ConfigurationManager.AppSettings["setDriverTimeout"])));
		driverWeb.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, Convert.ToInt16(ConfigurationManager.AppSettings["setPageLoadTimeout"]));
		driverWeb.Manage().Timeouts().PageLoad = new TimeSpan(0, 0, Convert.ToInt16(ConfigurationManager.AppSettings["setPageLoadTimeout"]));
	}
	catch
	{
		//log exception.
	}
}

Generate Preview:

//This method will be called from a Rest Service and returns a byte array for image.
public byte[] getImage()
{
	byte[] imageDataWeb;
	try
	{
		if (driverWeb == null)
		{
			lock (padlockWeb)
			{
				//double lock check for thread-safety.
				if (driverWeb == null)
				{
					initializeWebDriver();
				}
			}
		}

		if (getHttpResponseCode(link))
		{
			lock (driverWeb)
			{
				driverWeb.Navigate().GoToUrl(link);
				Thread.Sleep(100);
				/*Start Area: Get rendered page height/width and adjust browser accordingly*/
				try
				{
					var javaScriptExecutor = driverWeb as IJavaScriptExecutor;
					var waitPage = new WebDriverWait(driverWeb, TimeSpan.FromSeconds(explicitWaitTime));
					bool readyCondition(IWebDriver webDriver) => (bool)javaScriptExecutor.ExecuteScript("return document.readyState == 'complete'");
					waitPage.Until(readyCondition);

					string HeightScript = "return document.body.scrollHeight";
					long totalHeight1 = (long)javaScriptExecutor.ExecuteScript(HeightScript);
					int totalHeight = (int)totalHeight1;
					if (totalHeight == 0)
					{
						totalHeight = normalHeight + additionalHeight;
					}
					else
					{
						if (totalHeight <= additionalHeightOffset)
						{
							totalHeight += additionalHeight;
						}
					}
					driverWeb.Manage().Window.Size = new Size(totalWidth, totalHeight);
				}
				catch (Exception e)
				{
					_txtSource.TraceEvent(TraceEventType.Error, 0, e.Message);
					_txtSource.TraceEvent(TraceEventType.Error, 0, e.StackTrace);
					_txtSource.Flush();

					driverWeb.Manage().Window.Size = new Size(totalWidth, normalHeight + additionalHeight);
				}
				/*End Area: Get rendered page height/width and adjust browser accordingly*/

				screenshot = ((ITakesScreenshot)driverWeb).GetScreenshot().AsByteArray;

				if (screenshot.Length == 0)
				{
					throw new Exception("Website not responding.");
				}

				driverWeb.Navigate().GoToUrl("about:blank");
				driverWeb.Manage().Window.Size = new Size(totalWidth, normalHeight);
				return screenshot;
			}
		}
		else
		{
			imageDataWeb = returnErrorImage(); //return error image.
		}
		return imageDataWeb;

	}
	catch (Exception e)
	{
		//log exception
		imageDataWeb = doExtractEmptyPage();
		return imageDataWeb;
	}
	finally
	{
		imageDataWeb = null;
	}
}

Use Robocopy to copy files on Windows Server

Robocopy is a robust file copy command for the Windows command line. It allows users to copy files, directories, and even drives from one location to another. It can be automated with Task Scheduler to run at specific times.

Robocopy example to copy a file from Source to Destination:

Format:

Robocopy [Src] [Dest] [filename] [options]

Src: Can be local or UNC path

Dest: Can be local or UNC path

Code Sample batch file:

SET DTVARYEAR=%Date:~10,4%
SET DTVARMONTH=%Date:~4,2%
SET DTVARDATE=%Date:~7,2%


echo Sync Started

Robocopy C:\Data\TestFolder C:\Data\Logs\TestFolder\%DTVARYEAR%-%DTVARMONTH%-%DTVARDATE%_TestFolder testlogfile.log /FFT /Z /XA:H /LOG+:C:\Data\SchedTasks\LogsTest\%DTVARYEAR%-%DTVARMONTH%_AppLogs.txt 

echo  Log synced

The above code will copy the testlogfile.log from Source to Destination.

Options:
/FFT Assumes FAT file times (two-second precision).
/Z Copies files in restartable mode.
/XA:H exclude hidden file
/LOG+ log output to file and append.

Additional useful options:
/MIR Mirrors a directory tree (equivalent to /e plus /purge).
/XF exclude specified file
/XD exclude specified directory

Standard deviation using C# and Ruby

Standard Deviation definition states:

A quantity expressing by how much the members of a group differ from the mean value for the group.

The logic below calculates the Standard Deviation for the population of values. If the data is being considered a population on its own, we divide by the number of data points, say N. If the data is a sample from a larger population, we divide by one fewer than the number of data points in the sample, n-1. So you can change the formula accordingly.

Ruby code sample:

#sample = Array[1,2,3,4,5,6,7,8]
sample = Array[1,2,3,4,5]

def calc_standard_deviation(values)
    avg = values.sum {|x| x.to_f} / values.size.to_f
    Math.sqrt(values.sum {|x| (x.to_f - avg.to_f) ** 2} / values.size)
end

puts "Standard Deviation is: " + calc_standard_deviation(sample).to_s

Run the Ruby code to test as below in VS Code:

PS C:\code\Ruby test> ruby .\stdDev.rb
#Ruby Output: Standard Deviation is: 1.4142135623730951

C# code sample:

static void Main(string[] args)
{
	//double[] sample = new double[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
	double[] sample = new double[5] { 1, 2, 3, 4, 5 };

	Console.WriteLine("Standard Deviation is: " + StdDev(sample));
}

public static double StdDev(IEnumerable<double> values)
{
	// Get the mean.
	double mean = values.Sum() / values.Count();

	// Get the sum of the squares of the differences
	// between the values and the mean.
	var squares_query =
					from double value in values
					select (value - mean) * (value - mean);
	double sum_of_squares = squares_query.Sum();

	return Math.Sqrt(sum_of_squares / values.Count());
}

C# Output: Standard Deviation is: 1.4142135623731