Tag Archives: .Net Core

IConfiguration does not contain a definition for GetValue

When I search for something, I typically start with pmichaels.net [tab] [search term] – especially if I know I’ve come across a problem before. This post is one such problem: it’s not hard to find the solution, but it is hard to find the solution on this site (because until now, it wasn’t here).

The error (which is also in the title):

IConfiguration does not contain a definition for GetValue

Typically appears when you’re using IConfiguration outside of an Asp.Net Core app. In fact, GetValue is an extension method, so the solution is to simply add the following package:

Install-Package Microsoft.Extensions.Configuration.Binder

References

https://stackoverflow.com/questions/54767718/iconfiguration-does-not-contain-a-definition-for-getvalue

Installing .Net on Ubuntu… on Windows

With the new Windows Subsystem for Linux, and the Windows Terminal, comes the ability to run .Net programs on Linux from your Windows machine.

Here I wrote briefly about how you can install and run Linux on your Windows machine. In this post, I’ll cover how to install .Net.

If you don’t have the Windows Terminal, then you can install it here.

The installation process is pretty straightforward, and the first step is to launch the Windows Terminal. Once that’s running, open a Linux tab, and run the following two scripts (if you’re interested in where these came from, follow the link in the References section below):

wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb

Then run:

sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y dotnet-sdk-3.1

That should do it. To verify that it has:

dotnet --version

And you should see:

References

https://docs.microsoft.com/en-us/dotnet/core/install/linux-ubuntu

Upgrade a .Net Framework WPF Application to .Net Core 3.x

One of the main things that was introduced as part of .Net Core 3 was the ability to upgrade your WinForms or WPF application to use Core. I have an example of such an application here. This was upgraded using the side-by-side method. If you are upgrading, you essentially have 2 options: Big Bang and Side-by-Side.

Big Bang Upgrade

This is the process by which you edit your csproj file on the framework app, and convert that file to use .Net Core 3. This means potentially less work, and is suited for a situation where you know that you will never need the original application again. For a personal project this may be fine, but realistically, it too big a risk for most companies, who would want the security of a gradual rollout, and the ability to fix bugs and make interim releases in the meantime.

Side-by-Side Upgrade

There are three ways to do this, but essentially, what you’re doing here is creating a second project that is running .Net Core. The benefit here is that the two applications can continue to run, and you can gradually discontinue the Framework app as and when you see fit. The work involved can be greater; but it varies depending on your methodology and requirements.

1. Copy and Paste

This is the simplest method: create a brand new .Net Core WPF application, and copy the entire contents of your directory across. You’ll need to convert the packages (covered later), but other than that, you should be good to go. Obviously, that depends hugely on the complexity of your project.

The downside here is that if you fix a bug, or make a change to one of these projects, you either need to do it twice, or have them get out of sync.

2. Two Projects One Directory

This seems to be Microsoft’s preferred approach: the idea being that you create a new .Net Core project inside the same directory as the .Net Framework app. This means that all the files just appear in your framework app. You’ll need to convert the packages, and exclude the csproj, and other .Net Framework specific files from the .Net Core project. This, and the following approach both give you the ability to change the code in both files simultaneously.

3. Two Projects Linked Files

This is my personal preference. You create your .Net Core project it a different directory and just link the files and directories. You get all the benefits of having the projects in the same directory, but without the hassle of trying to manage files being there that you don’t want.

The downside to this approach is that you need to include the files yourself.

Two Projects Linked Files Upgrade

The following steps, whilst for this particular approach, are not specific to it, unless stated.

1. Start by installing the UWP Workload in Visual Studio, assuming you haven’t already.

2. In your WPF Framework app, convert your packages.config, as that doesn’t exist in .Net Core:

3. Create a new project. Whilst this is specific to this approach, you will need a new project for any of the side-by-side methods.

For this method, the project needs to be in a different directory; my suggestion is that you put it inside the solution directory, under its own folder; for example, in the example above, you might create: WpfCoreApp1:

The directory structure might look like this:

4. Copy the package references from your packages.config directly into the new csproj file (following step 1, this should be a simple copy and paste).

5. Gut the new project by removing MainWindow.xaml and App.xaml (from here on in, all of the steps are specific to this method):

6. Edit the new csproj file. Depending on your directory structure, the following may differ, but broadly speaking you need the following code in your new csproj file:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>
  <ItemGroup>
    <ApplicationDefinition Include="..\WpfApp1\App.xaml" Link="App.xaml">
      <Generator>MSBuild:Compile</Generator>
    </ApplicationDefinition>
    <Compile Include="..\WpfApp1\App.Xaml.cs" Link="App.Xaml.cs" />
    <Page Include="..\WpfApp1\MainWindow.xaml" Link="MainWindow.xaml">
      <Generator>MSBuild:Compile</Generator>
    </Page>
    <Compile Include="..\WpfApp1\MainWindow.Xaml.cs" Link="MainWindow.Xaml.cs" />
  </ItemGroup>
</Project>

If, for example, you were to have a directory that you wished to bring across, you could use something similar to the following:

  <ItemGroup>
    <Compile Include="..\WpfApp1\Helpers\**">
      <Link>Helpers\%(Filename)%(Extension)</Link>
    </Compile>
</ItemGroup>

That’s it – you should now be able to set your new .Net Core project as start-up and run it. The code is the same code as that running the Framework app, and should you change either, it will affect the other.

As an addendum, here is a little chart that I think should help you decide which approach to take for an upgrade:

The “LegacyFrameworkPackages” parameter is not supported by the “ResolveFrameworkReferences” task

I got this error recently while updating a project that I’m working on. It had been ported from WinForm to .Net Core 3.0, and worked fine – but suddenly I started getting errors where it claimed to not know what Form was. The output showed the error:

The “LegacyFrameworkPackages” parameter is not supported by the “ResolveFrameworkReferences” task

Unbeknownst to me, MS have changed the namespace for desktop apps; where previously your csproj might look like this:

<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <NullableReferenceTypes>true</NullableReferenceTypes>
    
    <AssetTargetFallback>uap10.0.18362</AssetTargetFallback>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

It now needs to look reference the WindowsDesktop SDK:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

My XUnit Tests won’t run in a .Net Standard 2.0 Class Library

Firstly, this isn’t a bug, or something that you might have done wrong; it’s intentional. Essentially, you can’t run a .Net Standard Library, so your tests aren’t runnable.

Okay – so I want to convert to .Net Core 3.0!

Yep – that’s exactly what you want, and it’s this easy; open up the csproj file – it’ll look like this:

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

And replace it with this:

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

And that’s it – your tests should now run!

Creating a Windows Service using .Net Core 2.2

Up until very recently, creating a Windows Service was the domain of the .Net Framework. However, since the release of the Windows Compatibility Pack that has all changed. In this article, we’ll create a .Net Core Windows Service from scratch.

I’m using the preview version of Visual Studio 2019 for this post. As far as I’m aware, there is absolutely no functional difference between this and VS2017; however, the initial New Project screen does look a little different.

Create the Project

There are no “New Windows Service (.Net Core)” options in Visual Studio, so we’re just going to create a console application (everything is a console application in .Net Core):

The .Net Core application can target .Net Core 2.2:

Windows Compatibility

The next step is to install the Windows Compatibility NuGet package:

Install-Package Microsoft.Windows.Compatibility

Write the Service

Let’s start with the main method:

static void Main(string[] args)
{
    using (var service = new TestSevice())
    {
        ServiceBase.Run(service);
    }
}

You’ll need to Ctrl-. ServiceBase. TestService doesn’t exist yet, so let’s create that:

internal class TestSevice : ServiceBase
{
    public TestSevice()
    {
        ServiceName = "TestService";
    }

    protected override void OnStart(string[] args)
    {
        string filename = CheckFileExists();
        File.AppendAllText(filename, $"{DateTime.Now} started.{Environment.NewLine}");
    }

    protected override void OnStop()
    {
        string filename = CheckFileExists();
        File.AppendAllText(filename, $"{DateTime.Now} stopped.{Environment.NewLine}");
    }

    private static string CheckFileExists()
    {
        string filename = @"c:\tmp\MyService.txt";
        if (!File.Exists(filename))
        {
            File.Create(filename);
        }

        return filename;
    }

}

Not exactly a complicated service, I’ll grant you.

Installing

For Framework apps, you could use InstallUtil, but if you try that on a Core app, you get an annoyingly vague error! Instead, you need to find the place where the binary has been compiled; for example:

C:\Users\pcmic\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.2

Now, launch a command prompt as admin, and type the following:

>sc create [service name] binpath=[full path to binary]

For example:

>sc create pcmtestservice binpath=C:\Users\pcmic\source\repos\ConsoleApp3\ConsoleApp3\bin\Debug\netcoreapp2.2\ConsoleApp3.exe

You should get the response:

[SC] CreateService SUCCESS

You can then either start the service from here:

>sc start pcmtestservice

Or locate it in the services utility and start it from there. You should now be able to start and stop the service and see it logging the events as you do so.

If you need to remove the service, use:

>sc delete pcmtestservice

References

https://stackoverflow.com/questions/7764088/net-console-application-as-windows-service

Web API Routing – The Basics

Working with API projects, it’s easy to miss some key rules about the routing. This post is basically the result of some that I missed, and subsequent the investigation. It covers some very basic routing rules, and it certainly not intended to be an exhaustive guide.

.Net Framework

Starting with a .Net Framework Web API, let’s create a new web app:

And add a new controller:

Here’s the code for the controller; as you will see, it’s massively complex, but the good news is that you only need to pay attention to the name of the action, and the code inside it:

public class TestController : ApiController
{
    [HttpGet]
    public IHttpActionResult TestAction()
    {
        return Ok("TestAction Performed");
    }
}

Let’s run the project and navigate to the URL:

How did I know that was the URL? It’s magic, and you can buy some of that magic by sending a cheque for the low, low price of $25 to the address shown at the bottom of the screen.

Actually, it’s defined in WebApiConfig.cs:

Parameters

Where there is more than a single function, one surprising (to me) feature is that the parameters that it accepts is more important to the routing than the name of the controller. Here’s a second action with a parameter:

[HttpGet]
public IHttpActionResult TestAction2(string test)
{
    return Ok("TestAction2 Performed");
}

… and here’s it working:

However, should I not give it the parameter that it craves, it hides away, and instead, we get the first function that’s no too fussy about parameters:

It doesn’t even matter whether I just put some drivel as the controller name; the first criteria is the parameter:

This is because, according to this it follows these criteria:

The default implementation is provided by the ApiControllerActionSelector class. To select an action, it looks at the following:
• The HTTP method of the request.
• The “{action}” placeholder in the route template, if present.
• The parameters of the actions on the controller.

So, if we add the {action} placeholder, that ensures that it uses the correct method:

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services
 
    // Web API routes
    config.MapHttpAttributeRoutes();
 
    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        //routeTemplate: "api/{controller}/{id}",
        routeTemplate: "api/{controller}/{action}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

Otherwise, we get a best guess based on the parameters.

.Net Core Web API

The rules have changed since switching to .Net Core; WebApiConfig has gone and, in its place, it a localised routing system.

Here, you tell the class how to handle routing; for example, the following:

[Route("api/[controller]")]

Will result anything decorated with HttpGet being called when the controller is called. The parameters must be explicitly decorated; so passing no parameters would look like this:

[HttpGet]
public string OneTest()
{
    return "TestOne";
}

Whereas, a single parameter would look like this:

[HttpGet("{id}")]
public string aaa(int id)
{
    return "value aaa";
}

If you duplicate the signatures then they are not found. As with the framework version, you can simply tell it to look to the action name that you give it:

[Route("api/[controller]/[action]")]
public class TestController : Controller
{
    [HttpGet]
    public IEnumerable<string> TestActionOne()
    {
        return new string[] { "one value1", "value2" };
    }
 
    [HttpGet]
    public string TestActionTwo()
    {
        return "two value";
    }

But, again, it pays no attention to parameters until you decorate it correctly.

References

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing

sdk\1.0.0-rc4-004771 Disappeared Creating a .Net Core project in VS2015

Error MSB4019 The imported project “C:\Program Files\dotnet\sdk\1.0.0-rc4-004771\Microsoft\VisualStudio\v14.0\DotNet\Microsoft.DotNet.Props” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk. MyProject C:\Users\Paul\documents\visual studio 14\Projects\MyProject\Myproject\MyProject.xproj

This issue, on initial investigation, looks like a problem with the VS Tools location (defined here in the xproj):

  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />

However, the fix was in the new file Global.json:

{
  "projects": [ "src", "test" ],
  "sdk": {
    "version": "1.0.0-preview2-003131"
  }
}

When the project was migrated to VS2017, the global.json was changed to look like this:

{"projects":["src","test"]}

So it looks like MS are moving away from the idea of these external project / solution state definition files. Which is a shame, because I really thought they were a good idea.

References

https://www.microsoft.com/net/download/core

https://jeremylindsayni.wordpress.com/2016/11/20/upgrading-from-net-core-1-0-t0-1-1-with-visual-studio-2015/