Manifestresource stream load gives null reference expection on some files

I'm doing a Xamarin project and having this problem and I don't know how to fix it.

I'm doing a Xamarin project and having this problem and I don't know how to fix it.

I'm trying to get some data from a .txt file. I've already fixed it and it works on one of the files, but when I switch to another file it suddenly gives me NullReferenceException.

Here's the code that works:

var assembly = IntrospectionExtensions.GetTypeInfo(typeof(ReadFromTxtFile)).Assembly;
Stream stream = assembly.GetManifestResourceStream("HanafiSalahTider.salahtider2019.txt");

using (StreamReader myreader = new StreamReader(stream))
{
fileContent = myreader.ReadToEnd();
}

Here's the nonworking code:

var assembly = IntrospectionExtensions.GetTypeInfo(typeof(ReadFromTxtFile)).Assembly;
Stream stream = assembly.GetManifestResourceStream("HanafiSalahTider.salahtider.txt");

using (StreamReader myreader = new StreamReader(stream))
{
fileContent = myreader.ReadToEnd();
}

Here's both files in the solution explorer:

Create a desktop app with Electron, React and C#

Create a desktop app with Electron, React and C#

An Electron is a framework to create native desktop applications for Windows, MacOS, and Linux. And what is the wow part in it, you can use vanilla javascript or any other javascript framework for building UI.

An Electron is a framework to create native desktop applications for Windows, MacOS, and Linux. And what is the wow part in it, you can use vanilla javascript or any other javascript framework for building UI.

First years in my software craftsmanship started with Delphi 7. It was amazing, it was time when the internet was semi-empty. It was hard to find examples, ask help, basically, you were on your own. Ohh good old times, I wouldn’t change that experience, but I wouldn’t want to do that again.

Time goes on, everything evolves, new technologies come in play. Time to time, I stop and look at what has been changed. And that is so cool, always there is something new to look into. To change my own biases, yes painful, but the world isn’t stuck in time warp.

Ladies and gentlemen I bring to you my experience with Electron.

What is an Electron

An Electron is a framework to create native desktop applications for Windows, MacOS, and Linux. And what is the wow part in it, you can use vanilla javascript or any other javascript framework for building UI.

This is amazing, you can be a web app developer and by reusing the same skillset you can build a desktop app.

If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.### The project

Let us create an empty npm project

npm init --yes

Add Electron stuff and start command

npm i -D electron

Add start script inside package.json

"start":"electron ."
{
  "name": "electron-demo",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Kristaps Vītoliņš",
  "license": "MIT",
  "devDependencies": {
    "electron": "^4.0.6"
  }
}

If we execute the npm start, we should get a popup error from Electron. That is ok, this only means that Electron is alive and we don’t know how to boot it.

The main and renderer process

Before we dive into coding, it is important to understand the basics of Electrons architecture.

If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.> If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.> If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.
My oversimplified explanation would be. There is a main process which creates a window and that window is a Chromium. Where Chromium is a process by itself aka renderer.

Typescript

Starting from the 1 June of the year 2017, Electron supports Typescript. Good, let’s use it.

npm i -D typescript
npm i -D tslint
npm i -D prettier

Add tslint.jsonin the project root

{
  "extends": "tslint:recommended",
  "rules": {
    "max-line-length": {
      "options": [
        120
      ]
    },
    "new-parens": true,
    "no-arg": true,
    "no-bitwise": true,
    "no-conditional-assignment": true,
    "no-consecutive-blank-lines": false
  },
  "jsRules": {
    "max-line-length": {
      "options": [
        120
      ]
    }
  }
}

Add tsconfig.json in the root of the project

{
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5"
  },
  "exclude": [
    "node_modules"
  ],
  "compileOnSave": false,
  "buildOnSave": false
}

For typescript compilation, tsc could be used, but as the end game is to use React and manipulate with templates. Webpack is the way to go this time.

Web pack

Setup for the web pack

npm i -D webpack webpack-cli
npm i -D html-webpack-plugin
npm i -D @babel/cli @babel/core @babel/preset-env babel-loader @babel/plugin-proposal-class-properties @babel/plugin-transform-arrow-functions
npm i -D @babel/preset-typescript



Add .babel.rc in the root of the project

{
  "presets": [
    "@babel/env",
    "@babel/preset-typescript"
  ],
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-transform-arrow-functions"
  ]
}

So far so good, now let us create a main process of Electron and say hello to Mom!

Create a folder src

Add main.ts file in src folder

const url = require("url");
const path = require("path");

import { app, BrowserWindow } from "electron";

let window: BrowserWindow | null;

const createWindow = () => {
  window = new BrowserWindow({ width: 800, height: 600 });

  window.loadURL(
    url.format({
      pathname: path.join(__dirname, "index.html"),
      protocol: "file:",
      slashes: true
    })
  );

  window.on("closed", () => {
    window = null;
  });
};

app.on("ready", createWindow);

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("activate", () => {
  if (window === null) {
    createWindow();
  }
});

line 8 creating a window and loading index.html into window aka Chromium.

Add index.html to the src folder

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Hi mom</title>
  </head>
  <body>
    <h1>Hi mom!</h1>
  </body>
</html>

Add webpack.config.js in the root. Instruction for the web pack how to handle Electrons main process build. Important target:"electron-main"

const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");

const htmlPlugin = new HtmlWebPackPlugin({
  template: "./src/index.html",
  filename: "./index.html",
  inject: false
});

const config = {
  target: "electron-main",
  devtool: "source-map",
  entry: "./src/main.ts",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js"]
  },
  node: {
    __dirname: false,
    __filename: false
  },
  plugins: [htmlPlugin]
};

module.exports = (env, argv) => {
  return config;
};

Adjust a bit package.json

{
  "name": "electron-demo",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "build": "webpack --mode development",
    "start": "electron ./dist/main.js"
  },
  "keywords": [],
  "author": "Kristaps Vītoliņš",
  "license": "MIT",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.3.4",
    "@babel/plugin-proposal-class-properties": "^7.3.4",
    "@babel/plugin-transform-arrow-functions": "^7.2.0",
    "@babel/preset-env": "^7.3.4",
    "@babel/preset-typescript": "^7.3.3",
    "babel-loader": "^8.0.5",
    "electron": "^4.0.6",
    "html-webpack-plugin": "^3.2.0",
    "prettier": "^1.16.4",
    "tslint": "^5.13.1",
    "typescript": "^3.3.3333",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}

Execute commands

npm run build
npm run start

And here it is. A fully functional desktop application. Which is saying hi to mom.

And this is actually the place where your front end developer skills kick in. As it is a Chromium you can use any kind of frontend technology, React, Vue, Angular, plain javascript.

The React

React will live in Electrons renderer process for that reason we will have to create a separate web pack build configuration. And teach babel to use react loader

npm i -D @babel/preset-react
npm i -S react react-dom
npm i -D @types/react @types/react-dom

Adjust.babelrc

{
  "presets": [
    "@babel/env",
    "@babel/preset-typescript",
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-transform-arrow-functions"
  ]
}

Adjust webpack.config.js by removing the responsibility of index.html template generation. It is the responsibility of the renderer build process.

const path = require("path");

const config = {
  target: "electron-main",
  devtool: "source-map",
  entry: "./src/main.ts",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js"]
  },
  node: {
    __dirname: false,
    __filename: false
  }
};

module.exports = (env, argv) => {
  return config;
};

Add new web pack config file webpack.react.config.js . This configuration is responsible for compiling react stuff and making sure that compiled result is injected insideindex.html

const path = require("path");
const HtmlWebPackPlugin = require("html-webpack-plugin");

const htmlPlugin = new HtmlWebPackPlugin({
  template: "./src/index.html",
  filename: "./index.html"
});

const config = {
  target: "electron-renderer",
  devtool: "source-map",
  entry: "./src/app/renderer.tsx",
  output: {
    filename: "renderer.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.(ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js"]
  },
  plugins: [htmlPlugin]
};

module.exports = (env, argv) => {
  return config;
};

Adjust index.html so that it contains a container where React can place its component.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Hi mom</title>
  </head>
  <body>
    <div id="renderer"></div>
  </body>
</html>

Create a folder app inside src and create renderer.tsx

import * as ReactDOM from 'react-dom';
import * as React from 'react';
import {Dashboard} from "./components/Dashboard";

ReactDOM.render(<Dashboard />, document.getElementById('renderer'));

Now let’s say Hello mom again, only now we will use a React to do so.

Create a folder components inside app and create Dashboard.tsx

import * as React from 'react';

export const Dashboard = () => {
    return <div>Hello Mom!</div>;
};

Adjust the package.json and add a new command so we can compile the renderer.

{
  "name": "electron-demo",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "build:react": "webpack --mode development --config webpack.react.config.js",
    "build": "webpack --mode development",
    "start": "electron ./dist/main.js"
  },
  "keywords": [],
  "author": "Kristaps Vītoliņš",
  "license": "MIT",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.3.4",
    "@babel/plugin-proposal-class-properties": "^7.3.4",
    "@babel/plugin-transform-arrow-functions": "^7.2.0",
    "@babel/preset-env": "^7.3.4",
    "@babel/preset-react": "^7.0.0",
    "@babel/preset-typescript": "^7.3.3",
    "@types/react": "^16.8.6",
    "@types/react-dom": "^16.8.2",
    "babel-loader": "^8.0.5",
    "electron": "^4.0.6",
    "html-webpack-plugin": "^3.2.0",
    "prettier": "^1.16.4",
    "tslint": "^5.13.1",
    "typescript": "^3.3.3333",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  },
  "dependencies": {
    "react": "^16.8.3",
    "react-dom": "^16.8.3"
  }
}
npm run build:react
npm run build
npm run start

Now, this is something I don’t see every day. A native desktop app running React inside of it. Well maybe I do, I just don’t know it as Electron is a popular framework and is used all over the place. For example, Visual Studio code, try to guess what is powering it ;).

The C# what?

A blog post by Rui Figueiredo ignited my interest in Electron.

Electron using C#. That is an interesting synergy going on here. And as it is C# core, it is cross-platform as well.

Cross-platform desktop app powered by Electron using React for UI and extended functionality by C# goodness. And now not only you can use your frontend skills, but backend as well.

Install new package for npm project

npm i -D electron-cgi

Adjust main.ts for a test run, we will send Mom to C# console app and it will return Hello Mom back. And we will console log that.

const { ConnectionBuilder } = require("electron-cgi");

...

let connection = new ConnectionBuilder()
  .connectTo("dotnet", "run", "--project", "./core/Core")
  .build();

connection.onDisconnect = () => {
  console.log("lost");
};

connection.send("greeting", "Mom", (response: any) => {
  console.log(response);
  connection.close();
});

Create a simple dotnet C# core console app. Add ElectronCgi.DotNet nuget.

using ElectronCgi.DotNet;

namespace Core
{
    class Program
    {
        static void Main(string[] args)
        {
            var connection = new ConnectionBuilder()
                .WithLogging()
                .Build();
            
            connection.On<string, string>("greeting", name => "Hello " + name);
            
            connection.Listen();    
        }
    }
}
npm run build
npm run start

Amazing isn’t it? Rui did go an extra mile and added this to C# as well

connection.OnAsync();

Now we are talking serious stuff. Imagen what possibilities this opens? Async communication to a database, to Rest API, to Queues, all nice packages for clouds, Amazon, Azure etc. All the good stuff from C# at your fingertips.

And it is not limited only to sending strings, it can be strongly typed object in C#.

Here is how

If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.> If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.> If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.> If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.
Heavy use of stdout. Which isn’t necessarily something bad, for example, php.exe and the frameworks which surround it ;).

I generally like the approach, clean, smart and innovating. I do endorse read a full blog post of Rui.

Extra mile with React and C#

Let’s make this even interesting, send the message to React from C#.

For that make changes in renderer by changing the Dashboard functional component to a component with the state.

import * as React from "react";
import { ipcRenderer } from "electron";

interface IState {
  message: string;
}

export class Dashboard extends React.Component<{}, IState> {
  public state: IState = {
    message: ""
  };

  public componentDidMount(): void {
    ipcRenderer.on("greeting", this.onMessage);
  }

  public componentWillUnmount(): void {
    ipcRenderer.removeAllListeners("greeting");
  }

  public render(): React.ReactNode {
    return <div>{this.state.message}</div>;
  }

  private onMessage = (event: any, message: string) => {
    this.setState({ message: message });
  };
}

What is going there? We subscribe to the channel greeging and upon receiving a message from the main process we put the message into the state. And from that point React takes ower, notices the state changes and renders the message.

Changes in the main process by sending received message from C# to React

const url = require("url");
const path = require("path");
const { ConnectionBuilder } = require("electron-cgi");

import { app, BrowserWindow } from "electron";

...

connection.send("greeting", "Mom from C#", (response: any) => {
  window.webContents.send("greeting", response);
  connection.close();
});

Create a legit EXE file

Add package

npm i -D electron-packager

Adjust the package.json file by adding package-win command and point main to dist folder file main.js.

Tutorial for all platform build commands here.

{
  "main": "dist/main.js",
  "scripts": {
    "package-win": "electron-packager . electron-demo --overwrite --asar=true --platform=win32 --arch=ia32 --icon=assets/icons/win/icon.ico --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"Electron-demo\""
  }
}
npm run package-win

Copy C# folder “core” into “release-builds\electron-demo-win32-ia32” and run the electron-demo.exe

The end

This journey of mine from Delphi 7 to React, Electron, C# is awesome. As I said before, nothing is stuck in time, every day new technologies pop up which makes us better and breaks our personal biases.

To stay open minded is our biggest challenge.

Sourcecode of demo in GitHub

How to make a basic Login in Xamarin with Xamarin.Forms

How to make a basic Login in Xamarin with Xamarin.Forms

In this article, you'll learn build login in Xamarin with Xamarin.Forms

Chuck Norris could easily make a single app run on all of the platforms iOS, Android, and Windows - without any frameworks or tools. Most of the rest of us could probably do with some help.

Happily, Xamarin Forms is the perfect tool for the job, and makes it a breeze to create an app! With Xamarin Forms your app will run on all three platforms from a single codebase. Xamarin Forms comes free with Visual Studio 2019 community edition from Microsoft. Let’s try it out - and have some fun. We’ll make a simple app that fetches Chuck Norris facts and collects your favorites.

This post will use these tools, libraries, and services:

  • Visual Studio 2019 community edition
  • Xamarin.Forms
  • RestSharp - for REST calls
  • Chuck Norris facts API at [https://api.chucknorris.io/](https://api.chucknorris.io/)
  • System.IdentityModel.Tokens.Jwt

Start by downloading Visual Studio 2019 community edition from visualstudio.microsoft.com. Make sure to check the boxes “Mobile development” and “Universal Windows Platform development” during the installation process:

How to make a basic Login in Xamarin with Xamarin.Forms

If you forget, no problem! Just open “Visual Studio Installer” from your start menu, select Modify and then you are back at the screen where you can tick off the workloads you want.

When you continue, it will open the Windows Settings window to turn on developer mode. Make sure to turn it on (it’s not defaulted).

You may also use Visual Studio 2017, but it would be wise to update it - to make sure you have the latest version of Xamarin.Forms. Start the Visual Studio installer and select Update if that is an option.

Scaffold Your Xamarin App for Secure Login

Start Visual Studio, select Create a new project, and select the template Mobile App (Xamarin.Forms) and then click Next:

How to make a basic Login in Xamarin with Xamarin.Forms

Enter “ChuckNorrisFacts” for Project name and then click the button Next.

Then check all platforms and select the template Blank:

How to make a basic Login in Xamarin with Xamarin.Forms

Then you’re in. Have a look around!

The Solution Explorer on the right contains four projects:

How to make a basic Login in Xamarin with Xamarin.Forms

The first one is the only one you will work on. The others are for platform-specific code, and you may as well collapse them as I have done in the image above.

Notice that the last project, ChuckNorrisFacts.UWP (Universal Windows) is in bold text. This means that hitting F5 will run this as a Windows application. If you want to run the Android or iOS versions, you must right-click the project you want and then select Set as StartUp Project.

Now it’s time to build a user interface for getting Chuck Norris facts! Right-click the project ChuckNorrisFacts, select Add and then New Item…. Select Xamarin.Forms to the left and Content View in the middle (not the one with C# in a parenthesis), and enter “FactsView” in the Name field:

How to make a basic Login in Xamarin with Xamarin.Forms

Click Add, and two new files will be created. FactsView.xaml is the view part of the component, declaring which components are included and their visual appearance, including layout. FactsView.xaml.cs is for C# and is called the code behind file.

Change the FactsView.xaml file’s content to this:


<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ChuckNorrisFacts.FactsView">
    
        
            
                
                
                <Button x:Name="GetFavoriteButton" Clicked="GetFavoriteClicked"
                          Text="Get random favorite" IsEnabled="False">
                <Button x:Name="AddFavoriteButton" Clicked="AddFavoriteClicked"
                          Text="Add to favorites" IsEnabled="False">
            
            
        
    

The content of this view is a StackLayout, which by default lays out its content from top to bottom. In the first row is another StackLayout with Orientation="Horizontal", which means it lays out its content from left to right. Inside it, there are a combo box (which is called Picker in Xamarin.Forms) and three buttons.

The x:Name attribute gives a variable name to each component, which enables you to access them in the code behind file. You will see that soon.

The Clicked attribute tells which method be called when the button is clicked. The attribute Text specifies the text on the button.

The last two buttons are disabled, more about that later.

Run Your New Xamarin App

It is always wise to often test that everything is right. To actually see our FactsView, open MainPage.xaml and add right after the comment. Also, to make it build without errors, you need to add the click-handlers. Open FactsView.xaml.cs and add these methods to the class - we will finish them later:

private void GetFavoriteClicked(object sender, EventArgs e)
{
}

private void GetFactClicked(object sender, EventArgs e)
{
}

private void AddFavoriteClicked(object sender, EventArgs e)
{
}

Now you can run the application. Make sure the UWP project is set as the startup project, and enable developer mode in Windows settings if you have not done it already. Then press F5, and Visual Studio will build your solution and run it. Building it takes a while the first time. When started, it should look something like this:

How to make a basic Login in Xamarin with Xamarin.Forms

The black thing in the center almost at the top is a debug tool. Click on it to expand it. If you run with CTRL+F5 instead of F5 alone, Visual Studio will run your app without debug mode and without this debug tool.

Make a REST Call in You Xamarin App

Next up is actually getting some Chuck Norris Facts! That’s where Chuck Norris facts JSON API at [https://api.chucknorris.io/](https://api.chucknorris.io/) comes in handy. Go to https://api.chucknorris.io/jokes/random and you will get a random joke in JSON format.

You need to build a model class to parse this JSON. Let’s do it the easy way. Copy the JSON of the random joke you got from the browser. Then add a new class, either by the shortcut Shift+Alt+C or by right-clicking the project ChuckNorrisFacts, selecting Add and then New Item…. Call the class Fact. Once it has been created, delete the class and the using statements so you are left with only this:

namespace ChuckNorrisFacts
{
}

Place the cursor between the curly braces and go to the Edit menu in the top bar of Visual Studio. Select Paste Special and then Paste JSON as Classes. Visual Studio creates all the properties for you! Change the name of the class back to Fact, and it should now look like this:

namespace ChuckNorrisFacts
{
    public class Fact
    {
        public object category { get; set; }
        public string icon_url { get; set; }
        public string id { get; set; }
        public string url { get; set; }
        public string value { get; set; }
    }
}

Now you will add some NuGet packages to do REST calls and parse JSON. Go to the Tools menu at the top bar of Visual Studio. Select NuGet Package Manager and then Manager NuGet Packages for Solution. Install RestSharp and Newtonsoft.JSON into the main project, ChuckNorrisFacts.

Now you can finish FactsView.xaml.cs. Add these two using-statements at the top:

using Newtonsoft.Json;
using RestSharp;

Add the two object variables from the code below to FactsView.xaml.cs - and also the initialization code at the end of the constructor:

public partial class FactsView : ContentView
{
    private readonly Dictionary> _userFavorites;
    private string _userName;
    private List Favorites => _userFavorites[_userName];
    private readonly RestClient _client = new RestClient("https://api.chucknorris.io");


    public FactsView()
    {
        InitializeComponent();

        var categoryList = new List { "Random" };
        categoryList.AddRange(GetCategories());
        CategoryPicker.ItemsSource = categoryList;
        CategoryPicker.SelectedIndex = 0;
        _userFavorites = new Dictionary>();
    }

Each user has its own favorites list for saving his or her favorite Chuck Norris Facts in-memory. The Dictionary maps a username to the correct List. is, and the read-only property Favorite does this for the current username. _client is for an object that will help us to do REST calls.

In the constructor, the list will be initialized with options to the Picker. The first option is to have a random fact, and the rest are the categories you will fetch from https://api.chucknorris.io/jokes/categories with a REST call.

Next, replace GetFactClicked with this:

private void GetFactClicked(object sender, EventArgs e)
{
    var isRandom = CategoryPicker.SelectedIndex == 0;
    FactLabel.Text = GetFact(isRandom ? null : CategoryPicker.SelectedItem.ToString());
}

You will make a method GetFact() that can take a category name as a parameter and get a fact in that category - or get a random fact if no category is provided.

To make GetFact() and GetCategories() actually work, add this:

public string GetFact(string category = null)
{
    var url = "/jokes/random";
    if (category != null) url += "?category=" + category;
    var fact = Get(url);
    return fact?.value;
}

public string[] GetCategories()
{
    return Get("/jokes/categories");
}

private T Get(string url)
{
    var request = new RestRequest(url, Method.GET);
    var response = _client.Execute(request);
    return JsonConvert.DeserializeObject(response.Content);
}

The last one is a helper method which gets a URL as a parameter, does the REST call, and converts the result to data type T. To make this as general as possible, you use generics, that’s the `` in Get and it lets you call this method with whatever class you want.

GetCategories() simply calls the helper method with the correct URL ending - and asks for the results to be interpreted as a string array.

GetFact() does something similar. If a category is set, it adds it to the URL the way that the Chuck Norris API wants it. And it wants the result as an object of the class you made earlier, Fact.

The logic for favorites simply works with the in-memory list. Add their implementations:

private void GetFavoriteClicked(object sender, EventArgs e)
{
    FactLabel.Text = Favorites.Count == 0
        ? "You have no favorites yet."
        : Favorites[new Random().Next(0, Favorites.Count)];
}

private void AddFavoriteClicked(object sender, EventArgs e)
{
    Favorites.Add(FactLabel.Text);
}

AddFavoriteClicked() will add the current fact to the favorites list. GetFavoriteClicked() will show a random favorite. If the list is empty, it lets the user know there are no favorites yet.

But wait - those buttons are disabled! Sure, you can enable them, but you don’t want users to see anything other than their own favorites. So you need a way to ensure that the user is who he or she claims to be.

Add Login to Your Xamarin App

No reason to write the authentication yourself. You can easily integrate Okta to handle the authentication for you and easily:

  • Authenticate and authorize your users
  • Store data about your users
  • Perform password-based and social login
  • Secure your application with multi-factor authentication
  • And much more! Check out our product documentation

Sign up for a forever-free developer account (or login if you already have one). Once you have signed up and logged in, you’ll be taken to your dashboard. Make note of your Org URL in the top right corner.

How to make a basic Login in Xamarin with Xamarin.Forms

Next, you will create an application. Select Applications in the menu bar, and then Add Application. Select Native and then Next. Enter Chuck Norris Facts for Name, check Implicit (Hybrid), and click Done.

Go back to Visual Studio, and create a new login component. Right-click the project ChuckNorrisFacts, select Add and then New Item…. Select Xamarin.Forms to the left and Content View in the middle, and enter “LoginView” in the Name field. Click Add.

Open LoginView.xaml and change its content to this:


<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ChuckNorrisFacts.LoginView">
    
        
            
                
                
            
            
                
                
            
        
    

So you have made a login panel and a logout panel. Only one of them will be visible at a time. The login panel has a button for logging in and a label to show a message if the login fails. The logout panel only shows a label and a button to log out.

You will make LoginView fire an event when the user has logged in. FactsView will listen to and react to this event. Open LoginView.xaml.cs and add the following line to the class:

public event EventHandler<string> LoginChanged; 

Now install version 5.4.0 of the System.IdentityModel.Tokens.Jwt NuGet package in the main project, and add this using statement at the top of LoginView.xaml.cs:

using System.IdentityModel.Tokens.Jwt; 

Then add this method to handle a click on the login button:

private async void LoginClicked(object sender, EventArgs e)
{
    var loginProvider = DependencyService.Get();
    var idToken = await loginProvider.LoginAsync();

    string userName = null;
    if (idToken != null)
    {
        var jwtHandler = new JwtSecurityTokenHandler();
        var token = jwtHandler.ReadJwtToken(idToken);
        userName = token.Claims.FirstOrDefault(c => c.Type == "preferred_username")?.Value;
    }

    if (LoginChanged != null) LoginChanged(this, userName);

    if (userName == null)
    {
        ErrorLabel.Text = "Login failed.";
        return;
    }

    LoginPanel.IsVisible = false;
    LogoutPanel.IsVisible = true;
    ErrorLabel.Text = "";
    LoggedInLabel.Text = "You are logged in as " + userName;
}

The actual login process is handled in a separate class LoginProvider. It will have its own implementation on each of the platforms iOS, Android and Windows. This text describes how to implement it for Windows, and at the bottom of this article, there will be a link to another article about how it is implemented in iOS and Android.

Add a new interface ILoginProvider that will be implemented by LoginProvider. It will only contain one method:

using System.Threading.Tasks;

namespace ChuckNorrisFacts
{
    public interface ILoginProvider
    {
        Task LoginAsync();
    }
}

The method LoginClicked first gets an object of a class that implements ILoginProvider. It does so with the DependencyService, which is a part of the Xamarin.Forms framework that allows apps to call into platform-specific functionality from shared code.

You will now add an implementation of this for the UWP project and register it with the DependencyService. Add a new class LoginProvider to the UWP project and replace its content with this:

using System;
using System.Linq;
using System.Threading.Tasks;
using Windows.Security.Authentication.Web;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;
using ChuckNorrisFacts;
using ChuckNorrisFacts.UWP;


[assembly: Xamarin.Forms.Dependency(typeof(LoginProvider))]
namespace ChuckNorrisFacts.UWP
{
    class LoginProvider : ILoginProvider
    {
        public async Task LoginAsync()
        {
            var clientId = "{yourClientId}";
            var url = "{yourOktaDomain}/oauth2/default/v1/authorize";
            var state = GetBase64UrlData(32);
            var nonce = GetBase64UrlData(12);
            var codeVerifier = GetBase64UrlData(32);
            var tmp = CryptographicBuffer.ConvertStringToBinary(codeVerifier, BinaryStringEncoding.Utf8);
            var codeVerifierBuffer = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Sha256).HashData(tmp);
            var codeChallenge = GetBase64UrlData(null, codeVerifierBuffer);

            var absoluteUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().AbsoluteUri;
            var callback = Uri.EscapeDataString(absoluteUri);

            var authorizationRequest = string.Format(
                "{0}?response_type=id_token&scope=openid profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method=S256&nonce={5}",
                url, callback, clientId, state, codeChallenge, nonce);

            var result = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None,
                new Uri(authorizationRequest), new Uri(absoluteUri));
            if (result.ResponseStatus != WebAuthenticationStatus.Success) return null;
            var queryParams = result.ResponseData.Split("#?&".ToCharArray());
            var idToken = queryParams.FirstOrDefault(p => p.StartsWith("id_token"));
            return idToken?.Substring(9);
        }

        public static string GetBase64UrlData(uint? length = null, IBuffer buffer = null)
        {
            if (length != null) buffer = CryptographicBuffer.GenerateRandom(length.Value);
            return CryptographicBuffer.EncodeToBase64String(buffer)
                .Replace("+", "-")
                .Replace("/", "_")
                .Replace("=", "");
        }
    }
}

There is no need to explain everything that goes on in this code, but it implements the auth code flow with PKCE and redirect. That means it will open a modal popup with a login form hosted by Okta. If the login is successful, Okta will redirect this browser to a special callback URI that the WebAuthenticationBroker will pick up. The URI will contain the id token for the user. WebAuthenticationBroker will close to browser popup and return this value inside result.Data. The code then extracts and returns the id token.

There is one important thing you must do to make this work. In the Okta dashboard, you must register the callback URI, or else it will not work. Set a breakpoint at the code line below, and use the debugger to get the value of absoluteUri:

var absoluteUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().AbsoluteUri; 

Go to the app you created in the Okta dashboard. Select Edit to the right of the box General Settings. Then click Add URI to the right of Login redirect URIs. Paste in the value of absoluteURI (it should look something like this: ms-app://s-1-15-2-1887544707-1408717265-2456949125-1910559573-2904915393-20160902-2550841693/) and click Save.

You must get your client app id from the Okta dashboard and enter it in the first line of the method. Select Applications in the menu bar. Select your app. Select the tab General. Scroll down and find Client ID. Click the button to the right to copy this value to the clipboard. Paste it into your code, so that it is assigned to the variable clientId. On the next line, make sure the URL starts with your specific Okta URL.

Go back to LoginView.xaml.cs in the main project. In the second line, it calls the implementation of LoginAsync and gets an id token back - or null if the login fails. If it gets an id token it will decode it using JwtSecurityTokenHandler and extract the username field. Then it fires an event, which we will later work on in FactsView. On success, it shows the logout panel and hides the login panel. If the login fails it shows an error message.

Also, add a method to handle logout:

private void LogoutClicked(object sender, EventArgs e)
{
    LoginPanel.IsVisible = true;
    LogoutPanel.IsVisible = false;
    if (LoginChanged != null) LoginChanged(this, null);
}

It hides the logout panel, shows the login panel and fires the event.

Send Notifications in Your Xamarin App

To show LoginView and make the event work, open MainPage.xaml and change the content of the StackLayout to this:



The main page will have both a FactsView and a LoginView. The event will be handled by a method HandleLoginChanged. Open MainPage.xaml.cs and add this:

private void HandleLoginChanged(object sender, string userName)
{
    FactsView.HandleLoginChanged(userName);
}

When the event occurs this code just passes it on to FactsView. Open FactsView.xaml.cs and add this:

public void HandleLoginChanged(string userName)
{
    FactLabel.Text = "";
    bool isLoggedIn = userName != null;
    AddFavoriteButton.IsEnabled = GetFavoriteButton.IsEnabled = isLoggedIn;
    _userName = isLoggedIn ? userName : null;
    if (userName != null && !_userFavorites.ContainsKey(userName))
        _userFavorites.Add(userName, new List());
}

It will enable or disable to favorite buttons depending on if you are logged in or not. And it will add a new list to the Dictionary for this user if it does not exist.

Now run the app with CTRL-F5 or F5 and start collecting your favorite Chuck Norris Facts! The first time you log in with a new user, Okta will ask you to register a security question.

Selenium WebDriver with C# Tutorial for Beginners

Selenium WebDriver with C# Tutorial for Beginners

Selenium is the most popular tool to test websites! Join me and thousands of students to learn Selenium Webdriver!


Selenium is a free automation testing tool for web applications. It is able to work with different browsers like Chrome, Firefox, IE, Opera and simulate human like behavior. Selenium is able to interact with all the different elements in a webpage. It can click on them, input text, extract text and much more. By covering all the different functionalities on your website with Selenium tests, you will be able to quickly catch new and reappearing old bugs. This will save your team time and money.

Specially for you, I have prepared a website where you can play around and practice your skills.

The website has special elements designed specificly for the course and for you to be able to easily work with them and learn.

In this course we will focus on Graphic User Interface and Functionality Testing and we will learn how to work with the various selectors that Selenium offers us to use like:

  • Name selector
  • ID Selector
  • Class Name selector
  • CSS Path selector
  • X Path selector

After that we will learn how to work with some special elements like:

  • Input text boxes
  • Check boxes
  • Radio buttons
  • Drop down menus
  • JavaScript Alert boxes

We will also have a few theory lectures in which I will explain when you should use either of these selectors, how to inspect elements and what is an Automation Testing Framework and why do we need to learn how to create one.


Learn More

C# Basics for Beginners - Learn C# Fundamentals by Coding

C# Intermediate: Classes, Interfaces and OOP

Complete C# Unity Developer 2D: Learn to Code Making Games

Full Stack Developers: Everything You Need to Know

VS Code extensions you may not have heard of before

ASP.NET Core 3.0 - Basic Authentication Tutorial with Example API

ASP.NET Core 3.0 - Basic Authentication Tutorial with Example API

In this tutorial we'll go through a simple example of how to implement Basic HTTP authentication in an ASP.NET Core 3.0 API with C#.

Tutorial built with ASP.NET Core 3.0

In this tutorial we'll go through a simple example of how to implement Basic HTTP authentication in an ASP.NET Core 3.0 API with C#.

The example API has just two endpoints/routes to demonstrate authenticating with basic http authentication and accessing a restricted route:

  • /users/authenticate - public route that accepts HTTP POST requests containing the username and password in the body. If the username and password are correct then the user details are returned.
  • /users - secure route that accepts HTTP GET requests and returns a list of all the users in the application if the HTTP Authorization header contains valid basic authentication credentials. If there are no basic auth credentials or the credentials are invalid then a 401 Unauthorized response is returned.

Tutorial Contents

Tools required to run the ASP.NET Core 3.0 Tutorial Example Locally

To develop and run ASP.NET Core applications locally, download and install the following:

  • .NET Core SDK - includes the .NET Core runtime and command line tools
  • Visual Studio Code - code editor that runs on Windows, Mac and Linux
  • C# extension for Visual Studio Code - adds support to VS Code for developing .NET Core applications
Running the ASP.NET Core Basic Authentication API Locally
  1. Download or clone the tutorial project code from https://github.com/cornflourblue/aspnet-core-3-basic-authentication-api
  2. Start the api by running dotnet run from the command line in the project root folder (where the WebApi.csproj file is located), you should see the message Now listening on: http://localhost:4000. Follow the instructions below to test with Postman or hook up with one of the example single page applications available (Angular, React or Vue).

NOTE: You can also start the application in debug mode in VS Code by opening the project root folder in VS Code and pressing F5 or by selecting Debug -> Start Debugging from the top menu. Running in debug mode allows you to attach breakpoints to pause execution and step through the application code.

Testing the ASP.NET Core Basic Authentication API with Postman

Postman is a great tool for testing APIs, you can download it at https://www.getpostman.com/.

Below are instructions on how to use Postman to authenticate a user with the api, and then make an authenticated request with basic authentication credentials to retrieve a list of users from the api.

How to authenticate a user with Postman

To authenticate a user with the basic authentication api and follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.

  2. Change the http request method to "POST" with the dropdown selector on the left of the URL input field.

  3. In the URL field enter the address to the authenticate route of your local API - http://localhost:4000/users/authenticate.

  4. Select the "Body" tab below the URL field, change the body type radio button to "raw", and change the format dropdown selector to "JSON (application/json)".

  5. Enter a JSON object containing the test username and password in the "Body" textarea:

    {
        "username": "test",
        "password": "test"
    }
    
  6. Click the "Send" button, you should receive a "200 OK" response containing the user details in the response body, this indicates that the username and password are correct.

Here's a screenshot of Postman after the request is sent and the user has been authenticated:
ASP.NET Core 3.0 - Basic Authentication Tutorial with Example API

How to make an authenticated request to retrieve all users

To make an authenticated request using basic authentication credentials, follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.
  2. Change the http request method to "GET" with the dropdown selector on the left of the URL input field.
  3. In the URL field enter the address to the users route of your local API - http://localhost:4000/users.
  4. Select the "Authorization" tab below the URL field, change the type to "Basic Auth" in the type dropdown selector, enter test into the "Username" field and test into the "Password" field.
  5. Click the "Send" button, you should receive a "200 OK" response containing a JSON array with all the user records in the system (just the one test user in the example).

Here's a screenshot of Postman after making an authenticated request to get all users:
ASP.NET Core 3.0 - Basic Authentication Tutorial with Example API

Running an Angular 8 client app with the ASP.NET Core Basic Auth API

For full details about the example Angular 8 application see the tutorial Angular 8 - Basic HTTP Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the Angular 8 tutorial code from https://github.com/cornflourblue/angular-6-basic-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the line below the comment // provider used to create fake backend located in the /src/app/app.module.ts file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the Angular example application and it should be hooked up with the ASP.NET Core Basic Authentication API that you already have running.
Running a React client app with the ASP.NET Core Basic Auth API

For full details about the example React application see the post React - Basic HTTP Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the React tutorial code from https://github.com/cornflourblue/react-basic-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.jsx file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the React example application and it should be hooked up with the ASP.NET Core Basic Authentication API that you already have running.
Running a Vue.js client app with the ASP.NET Core Basic Auth API

For full details about the example Vue.js application see the post Vue.js - Basic HTTP Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the VueJS tutorial code from https://github.com/cornflourblue/vue-basic-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.js file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the VueJS example application and it should be hooked up with the ASP.NET Core Basic Authentication API that you already have running.
ASP.NET Core Basic Authentication Project Structure

The tutorial project is organised into the following folders:
Controllers - define the end points / routes for the web api, controllers are the entry point into the web api from client applications via http requests.
Models - represent request and response models for controller methods, request models define the parameters for incoming requests, and response models can be used to define what data is returned.
Services - contain business logic, validation and data access code.
Entities - represent the application data.
Helpers - anything that doesn't fit into the above folders.

Click any of the below links to jump down to a description of each file along with its code:

ASP.NET Core Users Controller

Path: /Controllers/UsersController.cs

The ASP.NET Core users controller defines and handles all routes / endpoints for the api that relate to users, this includes authentication and standard CRUD operations. Within each route the controller calls the user service to perform the action required, this enables the controller to stay 'lean' and completely separated from the business logic and data access code.

The controller actions are secured with basic authentication using the [Authorize] attribute, with the exception of the Authenticate method which allows public access by overriding the [Authorize] attribute on the controller with the [AllowAnonymous] attribute on the action method. I chose this approach so any new action methods added to the controller will be secure by default unless explicitly made public.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using WebApi.Services;
using System.Threading.Tasks;
using WebApi.Models;

namespace WebApi.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [AllowAnonymous]
        [HttpPost("authenticate")]
        public async Task<IActionResult> Authenticate([FromBody]AuthenticateModel model)
        {
            var user = await _userService.Authenticate(model.Username, model.Password);

            if (user == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(user);
        }

        [HttpGet]
        public async Task<IActionResult> GetAll()
        {
            var users = await _userService.GetAll();
            return Ok(users);
        }
    }
}
ASP.NET Core User Entity

Path: /Entities/User.cs

The user entity class represents the data for a user in the application. Entity classes are used to pass data between different parts of the application (e.g. between services and controllers) and can be used to return http response data from controller action methods.

namespace WebApi.Entities
{
    public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
    }
}
ASP.NET Core Basic Authentication Handler

Path: /Helpers/BasicAuthenticationHandler.cs

The basic authentication handler is asp.net core middleware that handles request authentication by inheriting from the asp.net core AuthenticationHandler base class and overriding the HandleAuthenticateAsync() method.

Basic authentication logic is implemented in the HandleAuthenticateAsync() method by verifying the username and password received in the HTTP Authorization header, verification is done by calling _userService.Authenticate(username, password). On successful authentication the method returns AuthenticateResult.Success(ticket) which makes the request authenticated and sets the HttpContext.User to the currently logged in user.

The basic authentication middleware is configured in the application inside the ConfigureServices(IServiceCollection services) method in the application Startup file below.

using System;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using WebApi.Entities;
using WebApi.Services;

namespace WebApi.Helpers
{
    public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
    {
        private readonly IUserService _userService;

        public BasicAuthenticationHandler(
            IOptionsMonitor<AuthenticationSchemeOptions> options,
            ILoggerFactory logger,
            UrlEncoder encoder,
            ISystemClock clock,
            IUserService userService)
            : base(options, logger, encoder, clock)
        {
            _userService = userService;
        }

        protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
        {
            if (!Request.Headers.ContainsKey("Authorization"))
                return AuthenticateResult.Fail("Missing Authorization Header");

            User user = null;
            try
            {
                var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
                var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
                var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
                var username = credentials[0];
                var password = credentials[1];
                user = await _userService.Authenticate(username, password);
            }
            catch
            {
                return AuthenticateResult.Fail("Invalid Authorization Header");
            }

            if (user == null)
                return AuthenticateResult.Fail("Invalid Username or Password");

            var claims = new[] {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.Username),
            };
            var identity = new ClaimsIdentity(claims, Scheme.Name);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, Scheme.Name);

            return AuthenticateResult.Success(ticket);
        }
    }
}
ASP.NET Core Extension Methods

Path: /Helpers/ExtensionMethods.cs

Extension methods are used to add convenience methods and extra functionality to existing types in C#.

The extension methods class adds a couple of simple convenience methods for removing passwords from User instances and IEnumerable<User> collections. These methods are called by the Authenticate and GetAll methods in the UserService to ensure the user objects returned don't include passwords.

using System.Collections.Generic;
using System.Linq;
using WebApi.Entities;

namespace WebApi.Helpers
{
    public static class ExtensionMethods
    {
        public static IEnumerable<User> WithoutPasswords(this IEnumerable<User> users) {
            return users.Select(x => x.WithoutPassword());
        }

        public static User WithoutPassword(this User user) {
            user.Password = null;
            return user;
        }
    }
}
ASP.NET Core Authenticate Model

Path: /Models/AuthenticateModel.cs

The authenticate model defines the parameters for incoming requests to the /users/authenticate route of the api, because it is set as the parameter to the Authenticate method of the UsersController. When an HTTP POST request is received to the route, the data from the body is bound to an instance of the AuthenticateModel, validated and passed to the method.

ASP.NET Core Data Annotations are used to automatically handle model validation, the [Required] attribute sets both the username and password as required fields so if either are missing a validation error message is returned from the api.

using System.ComponentModel.DataAnnotations;

namespace WebApi.Models
{
    public class AuthenticateModel
    {
        [Required]
        public string Username { get; set; }

        [Required]
        public string Password { get; set; }
    }
}
ASP.NET Core Basic Auth User Service

Path: /Services/UserService.cs

The user service contains a method for authenticating user credentials, and a method for getting all users in the application.

I hardcoded the array of users in the example to keep it focused on basic http authentication, in a production application it is recommended to store user records in a database with hashed passwords. For an extended example that includes support for user registration and stores data with Entity Framework Core check out ASP.NET Core 3.0 - Simple API for Authentication, Registration and User Management.

The top of the file contains an interface that defines the user service, below that is the concrete user service class that implements the interface.

On successful authentication the Authenticate method returns the user details, the client application should then include the base64 encoded user credentials in the HTTP Authorization header of subsequent api requests to access secure endpoints.

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApi.Entities;
using WebApi.Helpers;

namespace WebApi.Services
{
    public interface IUserService
    {
        Task<User> Authenticate(string username, string password);
        Task<IEnumerable<User>> GetAll();
    }

    public class UserService : IUserService
    {
        // users hardcoded for simplicity, store in a db with hashed passwords in production applications
        private List<User> _users = new List<User>
        {
            new User { Id = 1, FirstName = "Test", LastName = "User", Username = "test", Password = "test" }
        };

        public async Task<User> Authenticate(string username, string password)
        {
            var user = await Task.Run(() => _users.SingleOrDefault(x => x.Username == username && x.Password == password));

            // return null if user not found
            if (user == null)
                return null;

            // authentication successful so return user details without password
            return user.WithoutPassword();
        }

        public async Task<IEnumerable<User>> GetAll()
        {
            return await Task.Run(() => _users.WithoutPasswords());
        }
    }
}
ASP.NET Core App Settings (Development)

Path: /appsettings.Development.json

Configuration file with application settings that are specific to the development environment.

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}
ASP.NET Core App Settings

Path: /appsettings.json

Root configuration file containing application settings for all environments.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
ASP.NET Core Program

Path: /Program.cs

The program class is a console app that is the main entry point to start the application, it configures and launches the web api host and web server using an instance of IHostBuilder. ASP.NET Core applications require a host in which to execute.

Kestrel is the web server used in the example, it's a new cross-platform web server for ASP.NET Core that's included in new project templates by default. Kestrel is fine to use on it's own for internal applications and development, but for public facing websites and applications it should sit behind a more mature reverse proxy server (IIS, Apache, Nginx etc) that will receive HTTP requests from the internet and forward them to Kestrel after initial handling and security checks.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>()
                        .UseUrls("http://localhost:4000");
                });
    }
}
ASP.NET Core Startup

Path: /Startup.cs

The startup class configures the request pipeline of the application and how all requests are handled.

The basic authentication handler is configured for the application in the ConfigureServices(IServiceCollection services) method.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WebApi.Helpers;
using WebApi.Services;
using Microsoft.AspNetCore.Authentication;

namespace WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();

            // configure basic authentication 
            services.AddAuthentication("BasicAuthentication")
                .AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

            // configure DI for application services
            services.AddScoped<IUserService, UserService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints => endpoints.MapControllers());
        }
    }
}
ASP.NET Core Basic Authentication Web Api csproj

Path: /WebApi.csproj

The csproj (C# project) is an MSBuild based file that contains target framework and NuGet package dependency information for the application.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
</Project>

The tutorial project is available on GitHub at https://github.com/cornflourblue/aspnet-core-3-basic-authentication-api.

ASP.NET Core 3.0 - JWT Authentication Tutorial with Example API

ASP.NET Core 3.0 - JWT Authentication Tutorial with Example API

In this tutorial we'll go through a simple example of how to implement JWT (JSON Web Token) authentication in an ASP.NET Core 3.0 API with C#.

In this tutorial we'll go through a simple example of how to implement JWT (JSON Web Token) authentication in an ASP.NET Core 3.0 API with C#.

The example API has just two endpoints/routes to demonstrate authenticating with JWT and accessing a restricted route with JWT:

  • /users/authenticate - public route that accepts HTTP POST requests containing the username and password in the body. If the username and password are correct then a JWT authentication token and the user details are returned.
  • /users - secure route that accepts HTTP GET requests and returns a list of all the users in the application if the HTTP Authorization header contains a valid JWT token. If there is no auth token or the token is invalid then a 401 Unauthorized response is returned.

The tutorial project is available on GitHub at https://github.com/cornflourblue/aspnet-core-3-jwt-authentication-api.

Tutorial Contents

  • Tools required to develop ASP.NET Core 3.0 applications
  • Running the example API locally
  • Testing the ASP.NET Core API with Postman
  • Running an Angular 8 app with the ASP.NET Core API
  • Running a React app with the ASP.NET Core API
  • Running a Vue.js app with the ASP.NET Core API
  • ASP.NET Core JWT API project structure
Tools required to run the ASP.NET Core 3.0 JWT Example Locally

To develop and run ASP.NET Core applications locally, download and install the following:

  • .NET Core SDK - includes the .NET Core runtime and command line tools
  • Visual Studio Code - code editor that runs on Windows, Mac and Linux
  • C# extension for Visual Studio Code - adds support to VS Code for developing .NET Core applications
Running the ASP.NET Core JWT Authentication API Locally
  1. Download or clone the tutorial project code from https://github.com/cornflourblue/aspnet-core-3-jwt-authentication-api
  2. Start the api by running dotnet run from the command line in the project root folder (where the WebApi.csproj file is located), you should see the message Now listening on: http://localhost:4000. Follow the instructions below to test with Postman or hook up with one of the example single page applications available (Angular, React or Vue).

NOTE: You can also start the application in debug mode in VS Code by opening the project root folder in VS Code and pressing F5 or by selecting Debug -> Start Debugging from the top menu. Running in debug mode allows you to attach breakpoints to pause execution and step through the application code.

Testing the ASP.NET Core JWT Auth API with Postman

Postman is a great tool for testing APIs, you can download it at https://www.getpostman.com/.

Below are instructions on how to use Postman to authenticate a user to get a JWT token from the api, and then make an authenticated request with the JWT token to retrieve a list of users from the api.

How to authenticate a user with Postman

To authenticate a user with the api and get a JWT token follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.

  2. Change the http request method to "POST" with the dropdown selector on the left of the URL input field.

  3. In the URL field enter the address to the authenticate route of your local API - http://localhost:4000/users/authenticate.

  4. Select the "Body" tab below the URL field, change the body type radio button to "raw", and change the format dropdown selector to "JSON (application/json)".

  5. Enter a JSON object containing the test username and password in the "Body" textarea:

    {
        "username": "test",
        "password": "test"
    }
    
  6. Click the "Send" button, you should receive a "200 OK" response with the user details including a JWT token in the response body, make a copy of the token value because we'll be using it in the next step to make an authenticated request.

Here's a screenshot of Postman after the request is sent and the user has been authenticated:

This is image title

This is image title

How to make an authenticated request to retrieve all users

To make an authenticated request using the JWT token from the previous step, follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.
  2. Change the http request method to "GET" with the dropdown selector on the left of the URL input field.
  3. In the URL field enter the address to the users route of your local API - http://localhost:4000/users.
  4. Select the "Authorization" tab below the URL field, change the type to "Bearer Token" in the type dropdown selector, and paste the JWT token from the previous authenticate step into the "Token" field.
  5. Click the "Send" button, you should receive a "200 OK" response containing a JSON array with all the user records in the system (just the one test user in the example).

Here's a screenshot of Postman after making an authenticated request to get all users:

This is image title

This is image title

Running an Angular 8 client app with the ASP.NET Core JWT Auth API

For full details about the example Angular 8 application see the post Angular 8 - JWT Authentication Example & Tutorial. But to get up and running quickly just follow the below steps.

  1. Download or clone the Angular 8 tutorial code from https://github.com/cornflourblue/angular-8-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the line below the comment // provider used to create fake backend located in the /src/app/app.module.ts file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the Angular example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
Running a React client app with the ASP.NET Core JWT Auth API

For full details about the example React application see the post React - JWT Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the React tutorial code from https://github.com/cornflourblue/react-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.jsx file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the React example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
Running a Vue.js client app with the ASP.NET Core JWT Auth API

For full details about the example VueJS JWT application see the post Vue.js + Vuex - JWT Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the VueJS tutorial code from https://github.com/cornflourblue/vue-vuex-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.js file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the VueJS example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
ASP.NET Core JWT Authentication Project Structure

The tutorial project is organised into the following folders:
Controllers - define the end points / routes for the web api, controllers are the entry point into the web api from client applications via http requests.
Models - represent request and response models for controller methods, request models define the parameters for incoming requests, and response models can be used to define what data is returned.
Services - contain business logic, validation and data access code.
Entities - represent the application data.
Helpers - anything that doesn't fit into the above folders.

ASP.NET Core JWT Users Controller
**Path: /Controllers/UsersController.cs**

The ASP.NET Core users controller defines and handles all routes / endpoints for the api that relate to users, this includes authentication and standard CRUD operations. Within each route the controller calls the user service to perform the action required, this enables the controller to stay 'lean' and completely separated from the business logic and data access code.

The controller actions are secured with JWT using the [Authorize] attribute, with the exception of the Authenticate method which allows public access by overriding the [Authorize] attribute on the controller with [AllowAnonymous] attribute on the action method. I chose this approach so any new action methods added to the controller will be secure by default unless explicitly made public.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using WebApi.Services;
using WebApi.Models;
using System.Linq;

namespace WebApi.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [AllowAnonymous]
        [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody]AuthenticateModel model)
        {
            var user = _userService.Authenticate(model.Username, model.Password);

            if (user == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(user);
        }

        [HttpGet]
        public IActionResult GetAll()
        {
            var users = _userService.GetAll();
            return Ok(users);
        }
    }
}
ASP.NET Core JWT User Entity
**Path: /Entities/User.cs**

The user entity class represents the data for a user in the application. Entity classes are used to pass data between different parts of the application (e.g. between services and controllers) and can be used to return http response data from controller action methods. If multiple types of entities or other custom data is required to be returned from a controller method then a custom model class should be created in the Models folder for the response.

namespace WebApi.Entities
{
    public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string Token { get; set; }
    }
}
ASP.NET Core JWT App Settings
**Path: /Helpers/AppSettings.cs**

The app settings class contains properties defined in the appsettings.json file and is used for accessing application settings via objects that are injected into classes using the ASP.NET Core built in dependency injection (DI) system. For example the User Service accesses app settings via an IOptions<AppSettings> appSettings object that is injected into the constructor.

Mapping of configuration sections to classes is done in the ConfigureServices method of the Startup.cs file.

namespace WebApi.Helpers
{
    public class AppSettings
    {
        public string Secret { get; set; }
    }
}
ASP.NET Core JWT Extension Methods
**Path: /Helpers/ExtensionMethods.cs**

Extension methods are used to add convenience methods and extra functionality to existing types in C#.

The extension methods class adds a couple of simple convenience methods for removing passwords from User instances and IEnumerable<User> collections. These methods are called by the Authenticate and GetAll methods in the UserService to ensure the user objects returned don't include passwords.

using System.Collections.Generic;
using System.Linq;
using WebApi.Entities;

namespace WebApi.Helpers
{
    public static class ExtensionMethods
    {
        public static IEnumerable<User> WithoutPasswords(this IEnumerable<User> users) {
            return users.Select(x => x.WithoutPassword());
        }

        public static User WithoutPassword(this User user) {
            user.Password = null;
            return user;
        }
    }
}
ASP.NET Core JWT Authenticate Model
**Path: /Models/AuthenticateModel.cs**

The authenticate model defines the parameters for incoming requests to the /users/authenticate route of the api, because it is set as the parameter to the Authenticate method of the UsersController. When an HTTP POST request is received to the route, the data from the body is bound to an instance of the AuthenticateModel, validated and passed to the method.

ASP.NET Core Data Annotations are used to automatically handle model validation, the [Required] attribute sets both the username and password as required fields so if either are missing a validation error message is returned from the api.

using System.ComponentModel.DataAnnotations;

namespace WebApi.Models
{
    public class AuthenticateModel
    {
        [Required]
        public string Username { get; set; }

        [Required]
        public string Password { get; set; }
    }
}
[Back to top](#projectstructure)
 
ASP.NET Core JWT User Service
**Path: /Services/UserService.cs**

The user service contains a method for authenticating user credentials and returning a JWT token, and a method for getting all users in the application.

I hardcoded the array of users in the example to keep it focused on JWT authentication, in a production application it is recommended to store user records in a database with hashed passwords. For an extended example that includes support for user registration and stores data with Entity Framework Core check out ASP.NET Core 2.2 - Simple API for Authentication, Registration and User Management.

The top of the file contains an interface that defines the user service, below that is the concrete user service class that implements the interface.

On successful authentication the Authenticate method generates a JWT (JSON Web Token) using the JwtSecurityTokenHandler class which generates a token that is digitally signed using a secret key stored in appsettings.json. The JWT token is returned to the client application which must include it in the HTTP Authorization header of subsequent requests to secure routes.

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WebApi.Entities;
using WebApi.Helpers;

namespace WebApi.Services
{
    public interface IUserService
    {
        User Authenticate(string username, string password);
        IEnumerable<User> GetAll();
    }

    public class UserService : IUserService
    {
        // users hardcoded for simplicity, store in a db with hashed passwords in production applications
        private List<User> _users = new List<User>
        { 
            new User { Id = 1, FirstName = "Test", LastName = "User", Username = "test", Password = "test" } 
        };

        private readonly AppSettings _appSettings;

        public UserService(IOptions<AppSettings> appSettings)
        {
            _appSettings = appSettings.Value;
        }

        public User Authenticate(string username, string password)
        {
            var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);

            // return null if user not found
            if (user == null)
                return null;

            // authentication successful so generate jwt token
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[] 
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            user.Token = tokenHandler.WriteToken(token);

            return user.WithoutPassword();
        }

        public IEnumerable<User> GetAll()
        {
            return _users.WithoutPasswords();
        }
    }
}
ASP.NET Core JWT App Settings (Development)
**Path: /appsettings.Development.json**

Configuration file with application settings that are specific to the development environment.

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}
ASP.NET Core JWT App Settings
**Path: /appsettings.json**

Root configuration file containing application settings for all environments.

IMPORTANT: The "Secret" property is used by the api to sign and verify JWT tokens for authentication, update it with your own random string to ensure nobody else can generate a JWT to gain unauthorised access to your application.

{
  "AppSettings": {
    "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
ASP.NET Core JWT Program
**Path: /Program.cs**

The program class is a console app that is the main entry point to start the application, it configures and launches the web api host and web server using an instance of IHostBuilder. ASP.NET Core applications require a host in which to execute.

Kestrel is the web server used in the example, it's a new cross-platform web server for ASP.NET Core that's included in new project templates by default. Kestrel is fine to use on it's own for internal applications and development, but for public facing websites and applications it should sit behind a more mature reverse proxy server (IIS, Apache, Nginx etc) that will receive HTTP requests from the internet and forward them to Kestrel after initial handling and security checks.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>()
                        .UseUrls("http://localhost:4000");
                });
    }
}
ASP.NET Core JWT Startup
**Path: /Startup.cs**

The startup class configures the request pipeline of the application and how all requests are handled.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WebApi.Helpers;
using WebApi.Services;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();

            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

            // configure DI for application services
            services.AddScoped<IUserService, UserService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
            });
        }
    }
}
ASP.NET Core JWT Web Api csproj
**Path: /WebApi.csproj**

The csproj (C# project) is an MSBuild based file that contains target framework and NuGet package dependency information for the application.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0" />
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.5.0" />
  </ItemGroup>
</Project>
Thank for reading! Please share if you liked it!