Alexicon
Alexicon
CC#
Created by Alexicon on 6/20/2024 in #help
Strange seemingly new behavior of docker-compose with dot net C# solution
I have a solution with multiple C# projects in it. I have a docker-compose.yml which up until today worked. Now however, when I attempt to build this solution in Azure DevOps with docker it is giving me the error
##[error]invalid project name "My.Solution": must consist only of lowercase alphanumeric characters, hyphens, and underscores as well as start with a letter or number
##[error]invalid project name "My.Solution": must consist only of lowercase alphanumeric characters, hyphens, and underscores as well as start with a letter or number
Surly I do not need to rename all of my actual C# projects to be all lowercase and remove the periods? That seems ridiculous considering I believe it is C# convention to have projects be capitalized. Additionally, this worked just the other day, I must have made a change somewhere or something for this to happen. I have already attempted to use
name: “my_solution”
name: “my_solution”
In the docker-compose.yml but it seems to have no effect. Any insight would be appreciated since google is giving me nothing. Here is what my docker-compose.yml looks like:
version: '3.4'
name: "my_solution" #Was not originally here but added hoping it would fix this issue

services:
myproject-1:
image: ${REGISTRY:-mysolution}/my-solution/myproject-1:${TAG:-latest}
build:
context: .
dockerfile: ./My.Solution.MyProject1/Dockerfile

myproject-2:
image: ${REGISTRY:-mysolution}/my-solution/myproject-2:${TAG:-latest}
build:
context: .
dockerfile: ./My.Solution.MyProject2/Dockerfile

myproject-3:
image: ${REGISTRY:-mysolution}/my-solution/myproject-3:${TAG:-latest}
build:
context: .
dockerfile: ./My.Solution.MyProject3/Dockerfile
version: '3.4'
name: "my_solution" #Was not originally here but added hoping it would fix this issue

services:
myproject-1:
image: ${REGISTRY:-mysolution}/my-solution/myproject-1:${TAG:-latest}
build:
context: .
dockerfile: ./My.Solution.MyProject1/Dockerfile

myproject-2:
image: ${REGISTRY:-mysolution}/my-solution/myproject-2:${TAG:-latest}
build:
context: .
dockerfile: ./My.Solution.MyProject2/Dockerfile

myproject-3:
image: ${REGISTRY:-mysolution}/my-solution/myproject-3:${TAG:-latest}
build:
context: .
dockerfile: ./My.Solution.MyProject3/Dockerfile
13 replies
CC#
Created by Alexicon on 10/31/2023 in #help
❔ Git Hub Actions Dot Net Push keeps trying to use 1.0.0.nupkg but that file should not exist
I have an established GitHub workflow I have been using for a while that builds, tests and pushes NuGet packages for a large C# library solution.
name: Build and Publish Nuget Packages

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: windows-latest

steps:
- uses: actions/checkout@v2

- name: Install .NET 7
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.x

- name: Restore
run: dotnet restore

- name: Build
run: dotnet build --configuration Release --no-restore /p:VersionPrefix=7.0.$env:GITHUB_RUN_NUMBER

- name: Test
run: dotnet test --verbosity normal

- name: Push
run: dotnet nuget push */**/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
name: Build and Publish Nuget Packages

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: windows-latest

steps:
- uses: actions/checkout@v2

- name: Install .NET 7
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.x

- name: Restore
run: dotnet restore

- name: Build
run: dotnet build --configuration Release --no-restore /p:VersionPrefix=7.0.$env:GITHUB_RUN_NUMBER

- name: Test
run: dotnet test --verbosity normal

- name: Push
run: dotnet nuget push */**/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
This workflow has been working for ages doing exactly what I want which is to package all the projects into NuGet packages for me, where the version of those packages is 7.0.[run number]. However I just recently added a new C# class library project to the solution, and I am getting a frustrating issue with this workflow. Now even though the new project is set up identically to all the others it keeps trying to push a myproject.1.0.0.nupkg file instead of one with the 7.0.[run number].
Pushing MyProject.1.0.0.nupkg to 'https://www.nuget.org/api/v2/package'...
Pushing MyProject.1.0.0.nupkg to 'https://www.nuget.org/api/v2/package'...
Whats odd is that this file should not even exist since as you saw in the workflow, I specify that the version prefix should end with the GitHub run number and start with 7.0.
/p:VersionPrefix=7.0.$env:GITHUB_RUN_NUMBER
/p:VersionPrefix=7.0.$env:GITHUB_RUN_NUMBER
[continued below]
47 replies
CC#
Created by Alexicon on 5/11/2023 in #help
❔ Docker dotnet msbuild fails when using source generator reference
I have a solution with two projects. An aspnet api 'MyApiProject' and a regular class library 'MyLibraryProject'. The library project references a source generator NuGet package 'MyGenerator' I created in a separate solution. When I build and run the solution in visual studio everything works fine but when I build it through docker it is failing because the class file that is generated "could not be found". Relevant extract from the docker output:
...

MSBuild version 17.3.2+561848881 for .NET
Determining projects to restore...
Restored /src/MyLibraryProject/MyLibraryProject.csproj (in 435 ms).
Restored /src/MyApiProject/MyApiProject.csproj (in 205 ms).
CSC : warning CS9057: The analyzer assembly '/root/.nuget/packages/MyGenerator/1.20230412.1/analyzers/dotnet/cs/MyGenerator.dll' references version '4.5.0.0' of the compiler, which is newer than the currently running version '4.3.0.0'. [/src/MyLibraryProject/MyLibraryProject.csproj]
/src/MyLibraryProject/SomeService.cs(113,21): error CS0246: The type or namespace name 'MyGeneratedClass' could not be found (are you missing a using directive or an assembly reference?) [/src/MyLibraryProject/MyLibraryProject.csproj]

...
...

MSBuild version 17.3.2+561848881 for .NET
Determining projects to restore...
Restored /src/MyLibraryProject/MyLibraryProject.csproj (in 435 ms).
Restored /src/MyApiProject/MyApiProject.csproj (in 205 ms).
CSC : warning CS9057: The analyzer assembly '/root/.nuget/packages/MyGenerator/1.20230412.1/analyzers/dotnet/cs/MyGenerator.dll' references version '4.5.0.0' of the compiler, which is newer than the currently running version '4.3.0.0'. [/src/MyLibraryProject/MyLibraryProject.csproj]
/src/MyLibraryProject/SomeService.cs(113,21): error CS0246: The type or namespace name 'MyGeneratedClass' could not be found (are you missing a using directive or an assembly reference?) [/src/MyLibraryProject/MyLibraryProject.csproj]

...
Relevant parts of my docker file looks like this:
FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS base
RUN apt-get update

...

WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
WORKDIR /src
COPY ["MyApiProject/MyApiProject.csproj", "MyApiProject/"]
COPY ["MyLibraryProject/MyLibraryProject.csproj", "MyLibraryProject/"]
COPY ["NuGet.config", ""]
RUN dotnet restore --configfile NuGet.config "MyApiProject/MyApiProject.csproj"

COPY . .
WORKDIR "/src/MyApiProject"
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app

FROM base AS final
WORKDIR /app

...

COPY --from=publish /app .
ENTRYPOINT ["dotnet", "MyApiProject.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS base
RUN apt-get update

...

WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
WORKDIR /src
COPY ["MyApiProject/MyApiProject.csproj", "MyApiProject/"]
COPY ["MyLibraryProject/MyLibraryProject.csproj", "MyLibraryProject/"]
COPY ["NuGet.config", ""]
RUN dotnet restore --configfile NuGet.config "MyApiProject/MyApiProject.csproj"

COPY . .
WORKDIR "/src/MyApiProject"
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app

FROM base AS final
WORKDIR /app

...

COPY --from=publish /app .
ENTRYPOINT ["dotnet", "MyApiProject.dll"]
All of this makes me think that its not running the source code generator during the build.
7 replies
CC#
Created by Alexicon on 3/14/2023 in #help
❔ Debugging Roslyn Components in newer visual studio versions?
2 replies
CC#
Created by Alexicon on 3/4/2023 in #help
❔ Suppress Visual Studio IDE0270 style rule without adding '.editorconfig'
fg. 1
9 replies
CC#
Created by Alexicon on 1/23/2023 in #help
✅ Simple way to push a C# project as a NuGet package within a GitHub workflow yml
I am not sure if there is a better place to ask this question as its really only C# adjacent, but maybe someone here knows the answer. Does anyone have a simple and up to date example of how to push a C# project as a NuGet package for GitHub actions? There are a lot of examples online but all of the ones I can find seem to be out of date or use a third-party workflow which I would like to avoid. If I was using Azure DevOps I would simply add the following to my yml file:
- task: DotNetCoreCLI@2
displayName: Pack myproject
inputs:
command: pack
packagesToPack: '**/myproject.csproj'
configuration: release
versioningScheme: byBuildNumber

- task: DotNetCoreCLI@2
displayName: Push NuGet packages
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
inputs:
command: push
versioningScheme: byPrereleaseNumber
- task: DotNetCoreCLI@2
displayName: Pack myproject
inputs:
command: pack
packagesToPack: '**/myproject.csproj'
configuration: release
versioningScheme: byBuildNumber

- task: DotNetCoreCLI@2
displayName: Push NuGet packages
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
inputs:
command: push
versioningScheme: byPrereleaseNumber
however, the GitHub actions equivalent seems to elude me.
21 replies
CC#
Created by Alexicon on 1/13/2023 in #help
❔ Is there a better way to insert a configuration source before the appsettings files?
I have an AspNetCore web API where I am using the appsettings.json and appsettings.Development.json, which are automatically added to the configuration manager when you call
WebApplication.CreateBuilder(args);
WebApplication.CreateBuilder(args);
however I am also adding a azure key vault as another configuration source like this:
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureKeyVault(...);
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureKeyVault(...);
The issue is that the key vault and appsettings.Development both contain the same connection string key but with different values. Because the appsettings are added before the azure key vault, the key vault connection string is always used, however I want to use the connection string from the appsettings.Development when its available. So the obvious solution is to do the following:
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureKeyVault(...);

if (builder.Environment.IsDevelopment())
{
builder.Configuration.AddJsonFile("appsettings.Development.json");
}
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureKeyVault(...);

if (builder.Environment.IsDevelopment())
{
builder.Configuration.AddJsonFile("appsettings.Development.json");
}
And this works but I was wondering if there is a more elegant or correct way that I could simply insert the azure key vault before the appsettings configuration. I suspect there isnt anything better based on what I can find but I figured I would ask just in case.
3 replies
CC#
Created by Alexicon on 12/11/2022 in #help
Newtonsoft JsonConverter to replicate the serialization of the JsonObjectAttribute on an IEnumerable
Can someone help me create a Newtonsoft.Json.JsonConverter that will write an IEnumerable the same way one is written if the class has the JsonObjectAttribute? For example, given this class:
public class MyEnumerable<T> : IEnumerable<T>
{
public int TotalCount { get; set; }
public IEnumerable<T> Values { get; set; }

public IEnumerator<T> GetEnumerator() => Values.GetEnumerator();
Enumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class MyEnumerable<T> : IEnumerable<T>
{
public int TotalCount { get; set; }
public IEnumerable<T> Values { get; set; }

public IEnumerator<T> GetEnumerator() => Values.GetEnumerator();
Enumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
I need the result from this:
var me = new MyEnumerable<string>
{
TotalCount = 2,
Values = new List<string>
{
"a",
"b"
}
}
JsonConvert.SerializeObject(obj, Formatting.Indented);
var me = new MyEnumerable<string>
{
TotalCount = 2,
Values = new List<string>
{
"a",
"b"
}
}
JsonConvert.SerializeObject(obj, Formatting.Indented);
To look like this:
{
"TotalCount": 2,
"Values": [
"a",
"b"
]
}
{
"TotalCount": 2,
"Values": [
"a",
"b"
]
}
Doing the above works fine if the class has the JsonObjectAttribute on it like this:
[JsonObject]
public class MyEnumerable<T> : IEnumerable<T>
{
...
}
[JsonObject]
public class MyEnumerable<T> : IEnumerable<T>
{
...
}
However without the JsonOjectAttribute the result will look like this:
[
"a",
"b"
]
[
"a",
"b"
]
But I cannot use the attribute since I do not own the class I am trying to serialize in this way, Thus I need to write a converter to do this same thing but I am struggling to figure out how. I tried googling this but I could not find any similar examples and everyone just seems to suggest using the JsonObject attribute, which I can't and do not want to use. Any assistance would be appreciated.
3 replies
CC#
Created by Alexicon on 11/24/2022 in #help
Using the new INumber interface to determine if an object is a number without having the generic arg
With .net7 we now have the INumber<TSelf> interface which is pretty cool, and I thought I found a place where I might be able to use it for the first time. However, I am running into some trouble. I am wondering if there is any way to know if some ‘object’ is a number and return the ‘One’ abstract static property from the INumber<TSelf> interface it would implement. The issue is I do not have a generic argument to plug in for TSelf, and I cannot add one in this case since the method I am working on is an override of a method outside of my control and it does not have a T generic argument. Here is a cut-down example as a x-unit test of what I am doing and what I have tried.
[Theory]
[InlineData(1)]
[InlineData(2.2)]
[InlineData("not a number")]
public object? MyMethod(object something)
{
Type numberType = typeof(INumber<>);
Type somethingType = something.GetType();

//this fails if something is not a number since TSelf must implement INumber<TSelf> :(
Type genericNumberType = numberType.MakeGenericType(somethingType);

bool isNumber = something
.GetType()
.IsAssignableTo(genericNumberType);

if (isNumber)
{
//all of these and more result in nothing
//i have tried many diffrent permutations of BindingFlags for each of these
var nothing = genericNumberType.GetProperties(BindingFlags.Static);
var alsoNothing = genericNumberType.GetMembers(BindingFlags.Static);
var againNothing = something.GetType().GetMembers(BindingFlags.Static);

//the crux of what i want:
//INumber<int>.One = 1
//INumber<double>.One = 1.0
object? result = somethingType
.GetProperty("One")?
.GetValue(something);

return result;
}

return null;
}
[Theory]
[InlineData(1)]
[InlineData(2.2)]
[InlineData("not a number")]
public object? MyMethod(object something)
{
Type numberType = typeof(INumber<>);
Type somethingType = something.GetType();

//this fails if something is not a number since TSelf must implement INumber<TSelf> :(
Type genericNumberType = numberType.MakeGenericType(somethingType);

bool isNumber = something
.GetType()
.IsAssignableTo(genericNumberType);

if (isNumber)
{
//all of these and more result in nothing
//i have tried many diffrent permutations of BindingFlags for each of these
var nothing = genericNumberType.GetProperties(BindingFlags.Static);
var alsoNothing = genericNumberType.GetMembers(BindingFlags.Static);
var againNothing = something.GetType().GetMembers(BindingFlags.Static);

//the crux of what i want:
//INumber<int>.One = 1
//INumber<double>.One = 1.0
object? result = somethingType
.GetProperty("One")?
.GetValue(something);

return result;
}

return null;
}
Unfortunately, with INumber<TSelf> being so new there is not a lot of information about it online so before I give up, I figured I would see if anyone here knows how to achieve this.
7 replies