TARGETDIR property is ignored during application install

The C# Setup.msi installer can take an argument, TARGETDIR to set the install location of the application.

 msiexec.exe /i "Setup.msi" /qn /norestart TARGETDIR="D:\MY_APP_DIRECTORY"

If the application is already installed on the computer, and we try to change the install location without first uninstalling it, the installer ignores the value in the TARGETDIR property.

To be able to install the application at a new location, first uninstall the application and run the Setup.msi again.

Turn off “If the running task does not end when requested, force it to stop” with PowerShell

Windows scheduled tasks are used to automatically execute processes on a set schedule.

To allow a long running process to continue, even if the scheduled task would start it again before the process completion, we need to uncheck the “If the running task does not end when requested, force it to stop” option.

When we use PowerShell to create the scheduled task, in the New-ScheduledTaskSettingsSet command use the -DisallowHardTerminate option.

    $settings = New-ScheduledTaskSettingsSet `
        -AllowStartIfOnBatteries `
        -DontStopIfGoingOnBatteries `
        -StartWhenAvailable `
        -RunOnlyIfNetworkAvailable:$false `
        -ExecutionTimeLimit (New-TimeSpan -Hours 12) `
        -MultipleInstances IgnoreNew `
        -DisallowHardTerminate

Working with SSIS packages in Visual Studio

To be able to create, edit, and test MSSQL SSIS package solutions in Visual Studio Community edition we need to install the SQL Server Data Tools under Data storage and processing in the list of workloads.

  • Start the Visual Studio Installer from the Windows Start Menu,
  • Select the installed Visual Studio instance you want to update,
  • In the Web and Cloud section select the Data storage and processing panel,
  • On the right side check SQL Server Data Tools

  • At the bottom of the page click the Modify button.

Creating SQL Server Integration Services (SSIS) projects

SSIS extension download locations

Installation

  • Open a command window as Administrator
  • Execute the downloaded installer package

See Integration Services (SSIS) Projects and Solutions for more information

RuntimeIdentifier is required for native compilation. Try running dotnet publish with the -r option value specified.

When a C# project moved from an earlier version of Visual Studio to Visual Studio 2022, AOT (Ahead Of Time) publish starts to fail with the error message

RuntimeIdentifier is required for native compilation. Try running dotnet publish with the -r option value specified.

This is cuased by old settings in the project. To eliminate the problem

  • Open the ~\.nuget\packages\microsoft.dotnet.ilcompiler\8.0.15\build directory in File Explorer
  • Rename the file Microsoft.NETCore.Native.Publish.targets to Microsoft.NETCore.Native.Publish.targets.OLD
  • At the bottom of the Microsoft.NETCore.Native.targets file delete the line
      <Import Project="$(MSBuildThisFileDirectory)Microsoft.NETCore.Native.Publish.targets" Condition="'$(NativeCompilationDuringPublish)' != 'false'" />
  • Right-click the project, select Publish
  • On the Publish page click the Publish button

Debug a C# application in Visual Studio with command line arguments

To use command line arguments during debugging in Visual Studio Community Edition we will create project profiles.

Create the project profile

  • Right-click the project and select Properties
  • In the top toolbar click the small arrow next to the outlined (Start without debugging) run button and select …Debug Properties

  • In the upper right corner of the Launch Profiles window click the Create a new profile button

  • Select the Project option

  • Select the new profile and click the Rename selected profile button

  • Enter the command line argument you want to pass to the application. Ignore the warning, the application will be able to read the arguments.

  • There is no save button, close the window with the X in the upper right corner

Select the project profile

To debug the application with a specific project profile

  • In the top toolbar click the small arrow next to the outlined (Start without debugging) run button and select the project profile you want to use to debug the application

Comment2GPT AI extension in Visual Studio for multiple models

Visual Studio Community Edition is a free, popular IDE to develop C# business applications. AI assistance can enhance the development process and do the boilerplate creation.

As of writing, the most popular free extension that supports multiple AI models is Comment2GPT by Merry Yellow.

Installation

  • In Visual Studio Community Edition in the Extensions menu select Manage Extensions

  • On the Extension Manager’s Browse tab enter gemini into the search field

  • On the Comment2GPT panel click the Install button

For more information visit the Comment2GPT Visual Studio Marketplace page at Comment2GPT

Configuration

This extension supports multiple AI models, so we can select the best for our purpose, or the one that is allowed on by our company.

Google Gemini

Create the Gemini API key

To use Gemini in Commenct2GPT, we need to create a free Google Gemini API key.

  • In your web browser navigate to Get a Gemini API key
  • Click the Get a Gemini APi key in Google AI Studio

  • In the upper right cornet click the Create API key button

  • Follow the instructions and save the API key at a secure location
Select the model you want to use

For the list of Gemini model versions and IDs visit Gemini models. We will need the ID of the model to configure Comment2GPT.

For our example we will use the Gemini 2.5 Flash Preview 05-20 model with the ID: gemini-2.5-flash-preview-05-20 model as it provides free, balanced performance. Currently, the free tier allows 10 requests per minute (RPM), 250,000 tokens per minute (TPM) and 500 requests per day (RPD). This should be enough for software development.
Before you start to configure Comment2GPT, get the ID of the latest model you want to use.

PageURL
List of models to get the the model IDGemini models
PricingGemini Developer API Pricing
Rate limitsRate limits
Billing infoBilling
Configure Comment2GPT
  • In Visual Studio Community Edition in the Tools menu select Options

  • Collapse the Environment element, and in the Comment2GPT section select the General tab. Set the Platform to Google AI (Gemini)

  • On the Authentication tab paste the API key into the Google AI API Key field

  • On the Request tab enter the model ID into the set the Gemini Model field.

Using Comment2GPT

To ask Comment2GPT to generate code for you

  • Create a comment starting with the letters // gpt and type your request. For example:
// gpt write a function to retrieve aws canary results from cloudwatch

How it works

On the Comment2GPT Request tab the Instruction message fields contain long explanation for the model to process the Add, Chant, Complete and Edit requests. Copy the contents to a text editor to view the entire text. Very interesting read.

It is interesting, two identical requests generated entirely different results, one with 65 lines, the second with 196 lines of code.

Data is Null. This method or property cannot be called on Null values.

When the .NET Entity Framework retrieves data from the database and parses it into the structure that we specify in our code, we have to make sure nullable columns are modeled with nullable properties in our code.

When null values are retrieved and the structure in the code does not allow null value in any property, we get the System.Data.SqlTypes.SqlNullValueException exception

Data is Null. This method or property cannot be called on Null values.

Make sure all nullable columns are modeled with nullable properties.

CREATE TABLE [dbo].[task](
	[id] [int] IDENTITY(1,1) NOT NULL,
	[filenames] [nvarchar](max) NULL,
	[source_path] [nvarchar](255) NULL,
	[target_path] [nvarchar](255) NULL


    public class task
    {
        public int id { get; set; }
        public string? filenames { get; set; }
        public string? source_path { get; set; }
        public string? target_path { get; set; }
    }

Build a standalone Windows executable in Visual Studio

Standalone Windows executables are compiled ahead of time (AOT) and distributed as three executable files (.exe, .dll, .runtimeconfig.json). This format is ideal for small executables called from the command line or from other applications.

To create an AOT Windows executable in Visual Studio 2022 or later

Start a new project

  • Create a C# console app

  • Name the app

  • Select .NET 8.0 or later framework, and Enable native AOT publish

  • To test the application we will write some temporary code in Program.cs
// See https://aka.ms/new-console-template for more information
Console.WriteLine("Test executable started");

// Read the command line arguments into an array
string[] arguments = args;
Console.WriteLine($"Number of command line arguments {arguments.Length}");

if (arguments != null && arguments.Length > 0)
{
    var firstArgument = arguments[0];
    Console.WriteLine($"First argument = {firstArgument}");

    if (firstArgument == "ERROR" )
    {
        Console.WriteLine("Throw divide by zero exception");
        int a = 0;
        int b = 1 / a;
    }

}

Console.WriteLine("Test executable exited without error");  

Build the executable

Prerequisites

To be able to build, link and publish the standalone executable we need to install the “Desktop development with C++” Visual Studio workload.

  • In the Tools menu select Get Tools and Features

  • Install the Desktop development with C++ workload

Publish the executable

  • In the Solution Explorer right-click the project and select Publish

  • Select Folder as the target

  • Select Folder again for the specific target

  • Select the target location and click Finish

  • Close the dialog when the build has been completed

Running the standalone executable

By default the output is placed in the bin\Debug\net8.0 directory

To run the (not really) “standalone” application, we need the following three files in the same directory:

  • .exe
  • .dll
  • .runtimeconfig.json

Setup project

To access the .msi file

  • Build the Setup project
  • The file is saved at Setup/[PROJECT_CONFIGURATION]/Setup.msi

See Visual Studio Installer Projects Extension and .NET on creating a Setup project

Troubleshooting

See RuntimeIdentifier is required for native compilation. Try running dotnet publish with the -r option value specified. in case you get this error during publishing.

Developing a secure .NET 8 (core) console application

In this post we will develop a .NET 8 console application which reads the configuration values from environment variables. This enables us deploy the application in an EKS cluster and read the config values from any secure secret storage.

The develoment environment

Docker configuration

To prevent Visual Studio from debugging in Docker containers

Debugging in Docker containers provides a stable, production like environment for your application, but larger applications can take a long time to build into containers. To stop Visual Studio debugging in Docker containers see Prevent Visual Studio 2022 from debugging in Docker. Official documentation is at Project warmup.

To allow Visual Studio to debug in Docker containers

If you want to debug in Docker containers to see how your application will run in production

Enable Docker Desktop execution

To be able to start Docker Desktop on Windows your user id has to be in the docker-users local user group. To add your user to the group

  • Open a command prompt as Administrator
  • Get the username:
whoami

Add the user to the docker-users user group:

net localgroup docker-users "your-user-id" /ADD

Log out and log in into Windows for the change to take effect.

Enable WSL (Windows Subsystem for Linux) for better performance with Docker Desktop

If Docker Desktop recommends using WSL instead of Hyper-V and WSL is not installed on your computer

  • Open an Administrator PowerShell window and execute
Enable-WindowsOptionalFeature -Online -FeatureName $("VirtualMachinePlatform", "Microsoft-Windows-Subsystem-Linux")

Restart the computer for the change to take effect.

You may need to install and enable the WSL2 Linux kernel. See Step 4 – Download the Linux kernel update package for details. Don’t forget to activate the WSL2 kernel with

wsl --set-default-version 2

Application settings

Create the application

  • Start Visual Studio 2022 community edition or newer
  • Create a new Console application using the C# programming language

Create the git repository

IMPORTANT!!!
To exclude the .env file and other temporary and build files from the Git commit create the .gitignore file

  • Open a terminal in the root directory of the repository and execute the commands
  • Create the .gitignore file
dotnet new gitignore
  • Create the Git repository
git init

Read the environment variables

Environment variables are the safest and most flexible way to store sensitive configuration values. This way those are never committed to source control.

Install the NuGet packages

To be able to access environment variables we need to install the following NuGet packages

  • Microsoft.Extensions.Configuration.EnvironmentVariables – to read environment variables
  • DotNetEnv – to load environment variables from .env files on the developer workstation

To install the packages from the command line, open a terminal in the project directory and execute

dotnet add package DotNetEnv
dotnet add package Microsoft.Extensions.Configuration.EnvironmentVariables

Create the local .env file

Create the .env file in the solution directory and add a key value pair

ENVIRONMENT=local

Write the code

Create the Settings.cs class to store the configuration values

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MY_NAMESPACE
{
    internal class Settings
    {
        public string? Environment { get; set; }
        public string? AppName { get; set; }
    }

    public class ConnectionStrings
    {
        public string? SQLServer { get; set; }
    }
}

Create the Configuration.cs class to read the configuration values form the environment variables

using DotNetEnv;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MY_NAMESPACE
{
    internal class Configuration
    {
        /// <summary>
        /// Reads the config values from the environment variables and returns the Settings object
        /// </summary>
        /// <returns></returns>
        public static Settings BuildAppSettings()
        {
            // Try to load the environment variables from the .env file for local development
            // Place the .env file in the root folder of the solution
            DotNetEnv.Env.TraversePath().Load();

            // Read the environment variables
            var environmentConfiguration = new ConfigurationBuilder()
                .AddEnvironmentVariables().Build();

            // Instantiate and populate the Settings object
            var settings = new Settings()
            {
                Environment = environmentConfiguration["ENVIRONMENT"],
                AppName = environmentConfiguration["APPNAME"]
            };

            // Return the Settings object
            return settings;
        }
    }
}

In the Program.cs file call Configuration to load the Settings object from the environment variables.

// See https://aka.ms/new-console-template for more information

using MY_APPLICATION;
using DotNetEnv;
using Microsoft.Extensions.Configuration;

// args is a string array that contains the command line arguments
string[] arguments = args;
Console.WriteLine($"Number of command line arguments {arguments.Length}");

// Read the configuration values
Settings settings = Configuration.BuildAppSettings();
Console.WriteLine($"Envronment: {settings.Environment}");
Console.WriteLine($"AppName: {settings.AppName}");