Just a very quick one with Preview5.

I encountered this gotcha whereby the project’s name in the solution explorer doesn’t match that of the folder name.

I’d had a change of heart on the project name but of course the folder on disk doesn’t change automatically.

Once I’d renamed the folder and then proceeded to fix the path in the .sln file this error went away.

tl;dr project folder name and project name in the solution explorer seemingly have to match up at present

Using GitLab to host both the source control and perform CI/CD, we will take a blazor project and build it and then proceed to deploy it on Netlify.

This article presumes that you have some familiarity with the following:

  1. GitLab for source control (See here)
  2. GitLab for CI/CD (See here)
  3. Netlify CLI for deployment (See here)

1. Using the current SDK 3.0.100-preview4-011223 (See here), create a new blazor (client-side) project called ‘testproj’:

mkdir testproj
cd testproj
dotnet new blazor

2. Now create a file called .gitlab-ci.yml and add it to the project root with the following content.

stages:
    - build
    - deploy

build:
    image: mcr.microsoft.com/dotnet/core/sdk:3.0.100-preview4-alpine3.9
    stage: build
    script:
        - dotnet restore
        - dotnet publish -o build
    artifacts:
        paths:
            - build/testproj/dist/

deploy:
    image: node:latest
    stage: deploy
    script:
        - node --version
        - npm --version
        - npm install netlify-cli -g
        - netlify deploy --dir=build/testproj/dist/ --prod

3. Create a manual site on Netlify and obtain your personal Netlify auth token (from User settings) and your site’s API ID (Site settings > Site details > API ID) to be added to the CI/CD for “testproj”

4. Create a project on GitLab for ‘testproj’ and add the variables from before as NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID respectively and then hit ‘Save variables’ once completed.

5. After setting up the source control and committing the previous code, you should have a pretty basic but serviceable build system performing CI/CD of a client-side Blazor app to Netlify.

On the odd occasion you wish to debug Seed method code which has been executed from the Package Manager Console using the Update-Database command, a quick and dirty method is to add the following code:

if (!System.Diagnostics.Debugger.IsAttached)
{
	System.Diagnostics.Debugger.Launch();
}

Yes it’s dirty! It will however fire up a new Visual Studio debug window and allow you to see what’s going on inside.

When running an ASP.NET Core website in IIS, you may experience the following error:

“HTTP Error 500.19 – Internal Server Error” (Code: 0x8007000d)

The following article describes the error as being “This problem occurs because the ApplicationHost.config file or the Web.config file contains a malformed XML element.”:

This comes down to the presence of the following tag:

<aspNetCore processPath=".\MyWebsite.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />

You’ll need to install the “ASP.NET Core/.NET Core: Runtime & Hosting Bundle” on to the server. This is found on the .NET downloads website and can be located by following the link at “Can’t find the file you want? Find more in .NET Core 2.2 downloads.”.

Here’s a small code snippet to use Http Range Requests with ASP.NET Core butchered from this now outdated MSDN article:

using System.IO;
using System.Text;
using Microsoft.AspNetCore.Mvc;

namespace WebApiRangeTest.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class RangeController : ControllerBase
    {
        private static readonly byte[] _content = Encoding.UTF8.GetBytes("abcdefghijklmnopqrstuvwxyz");

        public IActionResult Get()
        {
            MemoryStream stream = new MemoryStream(_content);

            if (stream == null)
            {
                return NotFound();
            }

            return File(stream, "text/plain", enableRangeProcessing: true);
        }
    }
}

 

The “Request.Headers.Range” method has now been replaced by opting in for this functionality using the enableRangeProcessing boolean when returning a FileStreamResult object.

Have fun!

Step 1 – Starting with the Tools menu item from the top navigation menu, navigate through the menus as follows:

Tools > Options > Text Editor > C# > Code Style > Naming

Step 2 – Click the green Plus icon to open the following dialogue box:

Step 3 – Now add the following:

Step 4 – Create the configuration to use the naming style we’ve just created.

Step 5 – Use the “Create and initialize field”option as normal and you’ll see the following.

The tutorial for React and Webpack at typescriptlang.org is one of the better tutorials out there, although with the introduction of Webpack 4 and wanting the hot reload support, I sought to seek out a more modern tutorial. I found the tutorial at AppDividend but still wanted the familiar experience of the one at typescriptlang.org.

  1. https://www.typescriptlang.org/docs/handbook/react-&-webpack.html
  2. https://appdividend.com/2018/03/18/how-to-setup-typescript-with-webpack-4/

The credit of course goes to the authors of each respective article.

 

1. Install TypeScript & Webpack-cli:

npm install -g typescript
npm install -g webpack-cli

 

2. Create directory structure

mkdir react-typescript-webpack4
cd react-typescript-webpack4

mkdir src
cd src
mkdir components
cd ..

 

3. Initialise NPM

 

First initialise the project:

npm init -y

 

Next add the packages we’ll need:

npm install webpack webpack-cli webpack-dev-server --save-dev
npm install typescript ts-loader --save-dev
npm install react react-dom @types/react @types/react-dom --save-dev

 

4. Create tsconfig.json

{
	"compilerOptions":
	{
		"outDir": "./dist/",
		"sourceMap": true,
		"noImplicitAny": true,
		"module": "commonjs",
		"target": "es5",
		"jsx": "react"
	},
	"include": [
		"./src/**/*"
	]
}

 

5. Create webpack.config.js

const path = require('path');

module.exports =
{
	entry: path.join(__dirname, '/src/index.tsx'),
	output:
	{
		filename: 'bundle.js',
		path: __dirname + "/dist",
		publicPath: "/dist/"
	},
	module:
	{
		rules: [
			{
				test: /\.tsx?$/,
				loader: 'ts-loader',
				exclude: /node_modules/,
			},
		]
	},
	resolve:
	{
		extensions: [".tsx", ".ts", ".js"]
	},
	// When importing a module whose path matches one of the following, just
	// assume a corresponding global variable exists and use that instead.
	// This is important because it allows us to avoid bundling all of our
	// dependencies, which allows browsers to cache those libraries between builds.
	externals:
	{
		"react": "React",
		"react-dom": "ReactDOM"
	},
};

 

6. Create Components

 

Index.tsx

import * as React from "react";
import * as ReactDOM from "react-dom";

import { Hello } from "./components/Hello";

ReactDOM.render(
    <Hello compiler="TypeScript" framework="React" />,
    document.getElementById("example")
);

 

Hello.tsx

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

// 'HelloProps' describes the shape of props.
// State is never set so we use the '{}' type.
export class Hello extends React.Component<HelloProps, {}> {
    render() {
        return <h1>Hello from {this.props.compiler} and {this.props.framework}!</h1>;
    }
}

 

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="example"></div>

        <!-- Dependencies -->
        <script src="./node_modules/react/umd/react.development.js"></script>
        <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>

        <!-- Main -->
        <script src="./dist/bundle.js"></script>
    </body>
</html>

 

Add the following “start” scrip to the scripts section in package.json to look as follows:

"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"start": "webpack-dev-server --mode development"
},