openAPISwaggerUI–part 4–adding tests

This is how I made

https://nuget.org/packages/OpenAPISwaggerUI in order to see the UI for an ASP.NET 9 project.

And hey, if you have any feedback, don’t be shy! Drop by https://github.com/ignatandrei/openAPISwaggerUI/ and let me know.

For testing, I have created a new ASP.NET Core 9 project that can be used to run

app.MapOpenApi();
app.UseOpenAPISwaggerUI();

public partial class Program { }

And I want to see that /swagger endpoint exists . And more, to have pictures with the different UIs.

The WebApplicationFactory is used to create a test server that can be used to test the application. But I need more – to have a real server that can be used to test the application.

I have found this link that show how to start Kestrel server in a test project : https://danieldonbavand.com/2022/06/13/using-playwright-with-the-webapplicationfactory-to-test-a-blazor-application/

And now the code for having the pre-requisites for testing is as easy as pie.

static CustomWebApplicationFactory factory;
[AssemblyInitialize]
public static void AssemblyInit(TestContext context)
{
    
    var exitCode = Microsoft.Playwright.Program.Main(new[] { "install" });
    if (exitCode != 0)
    {
        throw new Exception($"Playwright exited with code {exitCode}");
    }
    factory = new ();
    var url = factory.ServerAddress;
    Console.WriteLine($"Server address: {url}");
}

And we can test the weatherforecast endpoint – because who doesn’t love knowing the weather, right?

[TestMethod]
public async Task TestWeHaveRealWebServer()
{
    
    using var client = factory.CreateDefaultClient();
    var response = await client.GetAsync("/weatherforecast");
    response.EnsureSuccessStatusCode();
    var baseAddress = factory.ServerAddress;
    if(!baseAddress.EndsWith("/"))
    {
        baseAddress += "/";    
    }
    using var playwright = await Playwright.CreateAsync();
    var request = await playwright.APIRequest.NewContextAsync();
        
    var response1 = await request.GetAsync(baseAddress+"weatherforecast");
    Assert.IsTrue(response1.Ok);
}

And to test the endpoints for my library , OpenAPISwaggerUI

[TestMethod]
public async Task TestIntegrationWorks()
{

    var baseAddress = factory.ServerAddress;
    if (!baseAddress.EndsWith("/"))
    {
        baseAddress += "/";
    }
    using var playwright = await Playwright.CreateAsync();
    var request = await playwright.APIRequest.NewContextAsync();

    await using var browser = await playwright.Chromium.LaunchAsync();
    var context = await browser.NewContextAsync(new()
    {
        //RecordVideoDir = curDirVideos
    });
    var page = await browser.NewPageAsync();
    var pageSwagger = await page.GotoAsync(baseAddress + "swagger");
    await page.ScreenshotAsync(new PageScreenshotOptions { Path = "swagger.png" });
    var content= await page.ContentAsync();
    var hrefs = await page.Locator("a").AllAsync();
    
    Assert.IsTrue(hrefs.Count > 0);
    foreach (var li in hrefs)
    {
        var text= await li.TextContentAsync();
        var href = await li.GetAttributeAsync("href");
        ArgumentNullException.ThrowIfNull(href);
        if(href.StartsWith("/"))
        {
            href =  href[1..];
        }
        var pageNew = await browser.NewPageAsync();
        await pageNew.GotoAsync(baseAddress+ href);
        await pageNew.WaitForLoadStateAsync(LoadState.NetworkIdle);
        await pageNew.ScreenshotAsync(new PageScreenshotOptions { Path = $"{text}.png" });


    }
}

openAPISwaggerUI–part 3–add UI for all

This is how I made

https://nuget.org/packages/OpenAPISwaggerUI in order to see the UI for an ASP.NET 9 project.

And hey, if you have any feedback, don’t be shy! Drop by https://github.com/ignatandrei/openAPISwaggerUI/ and let me know.

Now I want the users of my ASP.NET 9 project to have a buffet of Swagger UIs (Swashbuckle, Redoc, Scalar, NSwag, VisualAutomation) and let them pick their favorite flavor.

The master plan? Create an endpoint (let’s call it /swagger) that showcases all these UIs like a proud parent at a talent show.

But wait, there’s more! I want to sprinkle in some custom info – project version, UI links, and other goodies.

Enter the RazorBlade NuGet package, my trusty sidekick for crafting a Razor page.

So I used the RazorBlade nuget package to create a Razor page .

<ItemGroup>
	<PackageReference Include="RazorBlade" Version="0.7.0" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
</ItemGroup>

And voilà, the SwaggerData.cshtml Razor page is born:

@using OpenAPISwaggerUI
@inherits RazorBlade.PlainTextTemplate<SwaggerUIData>

<html>
<body>
    <h1>Swagger UI</h1>
    <h2>
        <a href="@Model.SwaggerEndpoint" target="_blank">SwaggerEndpoint</a>
    </h2>
    <ul>
        <li>
            <a href="@Model.Swashbuckle" target="_blank">Swashbuckle</a>
        </li>
        <li>
            <a href="@Model.NSwag" target="_blank">NSwag</a>
        </li>
        <li>
            <a href="@Model.ReDoc" target="_blank">Redoc</a>
        </li>
        <li>
            <a href="@Model.Scalar" target="_blank">Scalar</a>
        </li>
        <li>
            <a href="@Model.Blockly" target="_blank">VisualAutomation</a>
        </li>
    </ul>
    <small>
        Generated by <a href="https://www.nuget.org/packages/OpenAPISwaggerUI" target="_blank"> @Model.AssemblyName : @Model.MyName</a>
    </small>
</body>
</html>

openAPISwaggerUI–part 2 – add ui for all

This is how I made

https://nuget.org/packages/OpenAPISwaggerUI in order to see the UI for an ASP.NET 9 project.

And hey, if you have any feedback, don’t be shy! Drop by https://github.com/ignatandrei/openAPISwaggerUI/ and let me know.

Step one in this epic quest: add all the mystical references (a.k.a. NuGet packages) to the project file.

	<ItemGroup>
		<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
		<PackageReference Include="NetCore2Blockly" Version="9.2024.1206.813" />
		<PackageReference Include="NSwag.AspNetCore" Version="14.2.0" />
		<PackageReference Include="RSCG_NameGenerator" Version="2024.26.8.2002" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
		<PackageReference Include="Scalar.AspNetCore" Version="1.2.56" />
		<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="7.2.0" />
		<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.2.0" />
	</ItemGroup>

Next, I had to figure out how to register these mystical packages to reveal the UI

public static WebApplication UseOpenAPISwaggerUI(this WebApplication app)
{
     
//goto /swagger-Swashbuckle
app.UseSwaggerUI(options =>
{
    options.SwaggerEndpoint("/openapi/v1.json", "v1");
    options.RoutePrefix = "swagger-Swashbuckle";
});
//scalar
//goto swagger-scalar/v1
app.MapScalarApiReference(opt =>
{
    opt.EndpointPathPrefix = "/swagger-scalar/{documentName}";
});
//redoc
//goto /api-docs
app.UseReDoc(options =>
{
    options.SpecUrl("/openapi/v1.json");
    options.RoutePrefix = "swagger-redoc";
});

//goto /nswag-swagger
app.UseSwaggerUi(options =>
{
    options.DocumentPath = "/openapi/v1.json";
    options.Path = "/swagger-nswag";
});
//goto /blocklyautomation
app.UseBlocklyUI(app.Environment);
app.UseBlocklyAutomation();
}

After this it was simple to use the extension in program.cs

app.MapOpenApi();
app.UseOpenAPISwaggerUI();

openAPISwaggerUI–part 1- idea

In .NET 9, Microsoft decided to play a little game of “Hide and Seek” with OpenAPI / Swagger JSON generation, leaving the UI part for us to figure out.

So, how do we choose the best UI for our project without turning it into a guessing game?

Well, I thought, why not create a project that lets you try all the options at once? It’s like a buffet, but for UIs!

You can grab it from https://nuget.org/packages/OpenAPISwaggerUI or install it with `dotnet add package OpenAPISwaggerUI`.

The UI I have found are from

Swashbuckle

NSwag

Redoc

Scalar

Visual Automation ( disclosure  : a project of mine )

And hey, if you have any feedback, don’t be shy! Drop by https://github.com/ignatandrei/openAPISwaggerUI/ and let me know.

[Interface2NullObject]Debugger and Converter–part 5

 

It will be interesting to see the Null Object in the debugger with properties generated from interface -see  https://www.nuget.org/packages/rscg_Interface_to_null_object

 

This is not very difficult to generate once you have the interface with properties

The code for generating

public string DebuggerDisplay()  
{
    StringBuilder sb = new StringBuilder("[System.Diagnostics.DebuggerDisplay(");
    sb.Append("\"");
    foreach (var item in props)
    {
        sb.Append(item.Name);
        sb.Append(" = {");
        sb.Append(item.Name);
        sb.Append("} " );
    }
    sb.Append("\")]");
    return sb.ToString();
}

 

and the code generated is

 

[System.Diagnostics.DebuggerDisplay("FirstName = {FirstName} LastName = {LastName} Department = {Department} ")]
public partial class Employee_null : global::IntegrationConsole.IEmployee

 

More interesting is to have a converter in order to obtain from the JSON string the interface, not the object .

 

The code for generating is

 

public class @(Model.Name + "Converter") : System.Text.Json.Serialization.JsonConverter<@(Model.FullName)>
    {
    public override @Model.FullName Read(ref System.Text.Json.Utf8JsonReader reader, System.Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
    {
    // Deserialize the JSON to the concrete type @Model.Name
    return System.Text.Json.JsonSerializer.Deserialize<@nameClass>
        (ref reader, options);
        }

        public override void Write(System.Text.Json.Utf8JsonWriter writer, @Model.FullName value, System.Text.Json.JsonSerializerOptions options)
        {
        // Serialize the concrete type @Model.Name
        System.Text.Json.JsonSerializer.Serialize(writer, (@nameClass)value, options);
        }
        }


and the code generated is

//serialize and deserialize
var empString = JsonSerializer.Serialize(employee);
Console.WriteLine(empString);
//deserialize

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    DefaultBufferSize = 128
};
options.Converters.Add(new IDepartmentConverter());
options.Converters.Add(new IEmployeeConverter());

var emp2 = JsonSerializer.Deserialize<IEmployee>(empString,options);
ArgumentNullException.ThrowIfNull(emp2);
Console.WriteLine(emp2.FirstName);
Console.WriteLine(emp2.Department.Name);
Debug.Assert(emp2.FirstName == "Andrei");

[Interface2NullObject]Replace default-part 4

So for https://github.com/ignatandrei/rscg_Interface_to_null_object we put the default return value as the default for the return type. For properties, it is enough easy to modify the data.  But for functions ?  Let’s say we return an array

public IEmployee[] Employees();

The default value is null – so it will be throwing an error when do “foreach ” .

So – I should think about a way to register default values for different methods.
I have the idea to register into the .csproj – so here it is

<ItemGroup>
	<CompilerVisibleProperty Include="I2NO_String" />
	<CompilerVisibleProperty Include="I2NO_IntegrationConsole_IEmployee_Array" />
	<CompilerVisibleProperty Include="I2NO_System_Collections_Generic_IAsyncEnumerable_Of_IntegrationConsole_IEmployee_EndOf" />
</ItemGroup>
<ItemGroup>
  <PackageReference Include="System.Linq.Async" Version="6.0.1" />
</ItemGroup>
<PropertyGroup>
	<I2NO_String>return ""</I2NO_String>
	<I2NO_IntegrationConsole_IEmployee_Array>return []</I2NO_IntegrationConsole_IEmployee_Array>
	<I2NO_System_Collections_Generic_IAsyncEnumerable_Of_IntegrationConsole_IEmployee_EndOf>return AsyncEnumerable.Empty_Of_IntegrationConsole.IEmployee_EndOf();</I2NO_System_Collections_Generic_IAsyncEnumerable_Of_IntegrationConsole_IEmployee_EndOf>
</PropertyGroup>

So this is the result

        public virtual string Name { get; set; } = default(string);
    
        public virtual IntegrationConsole.IEmployee[] Employees() {  return [] ; }
    
        public virtual System.Collections.Generic.IAsyncEnumerable<IntegrationConsole.IEmployee> EmployeesAsync() {  return AsyncEnumerable.Empty<IntegrationConsole.IEmployee>() ; }

[ADCES] Mock the Wire & How your .NET software supply chain is open to attack

Details

Presentation 1 : Mock the Wire, with WireMock.NET: Simplifying API Testing in .NET
Presenter : Cosmin Vladutu, https://www.linkedin.com/in/cosmin-vladutu/
Description : WireMock.NET offers an easy and flexible way to mock external dependencies, making API testing in .NET more reliable and efficient. It bridges the gap between integration and contract testing, allowing developers to validate service interactions without relying on real external services.

This presentation is based on a real-world experience—how our project evolved before and after introducing WireMock.NET, and the challenges that led us to explore this solution.

We’ll also take a brief look at alternative tools and collaborate on building a pros-and-cons list based on our collective experiences.

Whether working with microservices, serverless architectures, or legacy web APIs, WireMock.NET helps simplify and improve testing strategies.

Presentation 2: How your .NET software supply chain is open to attack : and how to fix it
Presenter : Andrei Epure, https://andreiepure.ro/
Description : Software supply chain attacks can be catastrophic. For instance, the 2020 SolarWinds hack was considered an attack against the entire government and private sector of the United States of America.

Security researchers have shown that all significant package managers are vulnerable to supply chain attacks like typosquatting and dependency confusion. NuGet is vulnerable by design in its default configuration.

First, you will see how typosquatting and dependency confusion attacks can compromise .NET supply chains that rely on the default NuGet configuration. Second, I will show how you can secure your NuGet configuration to thwart evil hackers.

This talk will assume attendees have some basic knowledge of NuGet and MSBuild.

What I use for a csproj for a Roslyn Code Generator

My csproj file looks like this

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

	<PropertyGroup>
		<TargetFramework>netstandard2.0</TargetFramework>
		<LangVersion>12.0</LangVersion>
		<Nullable>enable</Nullable>
		<ImplicitUsings>enable</ImplicitUsings>
		<IsRoslynComponent>true</IsRoslynComponent>
		<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
		<!--<IncludeBuildOutput>false</IncludeBuildOutput>-->
	</PropertyGroup>
	<PropertyGroup>

		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
			<PrivateAssets>all</PrivateAssets>
			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
		</PackageReference>

		<PackageReference Include="System.CodeDom" PrivateAssets="all" GeneratePathProperty="true" Version="8.0.0" />
		<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
		<None Remove="bin\Debug\netstandard2.0\\*.dll" />
		<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />


	</ItemGroup>


	<PropertyGroup>
		<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
		<WarningsNotAsErrors>CS0436</WarningsNotAsErrors>
	</PropertyGroup>


	<ItemGroup>
		<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
		<None Include="../../README.md" Pack="true" PackagePath="\" />
		<None Include="../../readme.txt">
			<Pack>True</Pack>
			<PackagePath></PackagePath>
		</None>
		<None Include="../../LICENSE" Pack="true" PackagePath="\" />
	</ItemGroup>
	<PropertyGroup>
		<Description>Interface to null object - common</Description>
		<Copyright>MIT</Copyright>
		<NeutralLanguage>en-US</NeutralLanguage>
		<CurrentDate>$([System.DateTime]::Now.ToString(yyyyMMdd))</CurrentDate>
		<Authors>Andrei Ignat</Authors>
		<Title>A C# source-generated class library for generating null objects from interface</Title>
		<PackageTags>dotnet;dotnetcore;csharp;generators;sourcegen;roslyn;</PackageTags>
		<PackageProjectUrl>https://github.com/ignatandrei/rscg_Interface_to_null_object</PackageProjectUrl>
		<PublishRepositoryUrl>true</PublishRepositoryUrl>
		<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
		<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
		<IncludeSymbols>true</IncludeSymbols>
		<IncludeSource>true</IncludeSource>
		<NoWarn>NU5125;NU5039;CS0436</NoWarn>
		<!--<Version>8.$([System.DateTime]::Now.ToString(yyyy.1MMdd.1HHss))</Version>-->
		<!--<Version>$([System.DateTime]::Now.ToString(8.yyyy.1MMdd.1HHmm))</Version>-->
		<Version>2025.119.1910</Version>

		<!--<Optimize Condition="'$(Configuration)'=='Release'">true</Optimize>-->
		<RepositoryUrl>https://github.com/ignatandrei/rscg_Interface_to_null_object</RepositoryUrl>
		<PackageLicenseFile>LICENSE</PackageLicenseFile>
		<RepositoryType>git</RepositoryType>
		<EmbedUntrackedSources>true</EmbedUntrackedSources>
		<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
		<PackageReadmeFile>README.md</PackageReadmeFile>
		<IsPackable>true</IsPackable>
		<!--<PackageIcon>logo.png</PackageIcon>-->
	</PropertyGroup>


	<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
		<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
		<SourceLinkCreate>true</SourceLinkCreate>
		<SourceLinkOriginUrl>https://github.com/ignatandrei/rscg_Interface_to_null_object</SourceLinkOriginUrl>
	</PropertyGroup>
	
	
	
	<ItemGroup>
		<PackageReference Include="RazorBlade" Version="0.6.0" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
		<PackageReference Include="RSCG_NameGenerator" Version="2024.11.11.1830">
			<OutputItemType>Analyzer</OutputItemType>
			<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
		</PackageReference>

	</ItemGroup>

</Project>



And now a detailed explanation

Project Sdk

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

This tag specifies the SDK to use for the project. The Microsoft.NET.Sdk is a general-purpose SDK for .NET projects.

PropertyGroup

<PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <LangVersion>12.0</LangVersion>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <IsRoslynComponent>true</IsRoslynComponent>
    <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
  • TargetFramework: Targets .NET Standard 2.0, ensuring compatibility with a wide range of .NET implementations.
  • LangVersion: Specifies the C# language version to use.
  • Nullable: Enables nullable reference types to improve null safety.
  • ImplicitUsings: Automatically includes commonly used namespaces.
  • IsRoslynComponent: Indicates that this project is a Roslyn component, useful for source generators.
  • EnforceExtendedAnalyzerRules: Enforces extended analyzer rules to maintain code quality.

Emit Compiler Generated Files

<PropertyGroup>
    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
    <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
  • EmitCompilerGeneratedFiles: Emits compiler-generated files for debugging and analysis.
  • CompilerGeneratedFilesOutputPath: Specifies the output path for compiler-generated files.

Package References

<ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
        <PrivateAssets>all</PrivateAssets>
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="System.CodeDom" PrivateAssets="all" GeneratePathProperty="true" Version="8.0.0" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
    <None Remove="bin\Debug\netstandard2.0\\*.dll" />
    <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
  • Microsoft.CodeAnalysis.Analyzers: Adds a reference to the Microsoft.CodeAnalysis.Analyzers package, which provides code analysis tools.
  • System.CodeDom: Adds a reference to the System.CodeDom package, useful for code generation.
  • Microsoft.CodeAnalysis.CSharp: Adds a reference to the Microsoft.CodeAnalysis.CSharp package, necessary for Roslyn-based projects.
  • None Remove: Removes unnecessary DLLs from the build output.
  • None Include: Includes the generated DLL in the NuGet package under the specified path.

Treat Warnings as Errors

<PropertyGroup>
    <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
    <WarningsNotAsErrors>CS0436</WarningsNotAsErrors>
</PropertyGroup>
  • TreatWarningsAsErrors: Treats all warnings as errors to ensure code quality.
  • WarningsNotAsErrors: Excludes specific warnings from being treated as errors.

Source Link and Additional Files

<ItemGroup>
    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
    <None Include="../../README.md" Pack="true" PackagePath="\" />
    <None Include="../../readme.txt">
        <Pack>True</Pack>
        <PackagePath></PackagePath>
    </None>
    <None Include="../../LICENSE" Pack="true" PackagePath="\" />
</ItemGroup>
  • Microsoft.SourceLink.GitHub: Adds SourceLink support for GitHub, enabling better debugging experiences.
  • README.md: Includes the README.md file in the NuGet package.
  • readme.txt: Includes the readme.txt file in the NuGet package.
  • LICENSE: Includes the LICENSE file in the NuGet package.

Package Metadata

<PropertyGroup>
    <Description>Interface to null object - common</Description>
    <Copyright>MIT</Copyright>
    <NeutralLanguage>en-US</NeutralLanguage>
    <CurrentDate>$([System.DateTime]::Now.ToString(yyyyMMdd))</CurrentDate>
    <Authors>Andrei Ignat</Authors>
    <Title>A C# source-generated class library for generating null objects from interface</Title>
    <PackageTags>dotnet;dotnetcore;csharp;generators;sourcegen;roslyn;</PackageTags>
    <PackageProjectUrl>https://github.com/ignatandrei/rscg_Interface_to_null_object</PackageProjectUrl>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
    <IncludeSymbols>true</IncludeSymbols>
    <IncludeSource>true</IncludeSource>
    <NoWarn>NU5125;NU5039;CS0436</NoWarn>
    <Version>2025.119.1910</Version>
    <RepositoryUrl>https://github.com/ignatandrei/rscg_Interface_to_null_object</RepositoryUrl>
    <PackageLicenseFile>LICENSE</PackageLicenseFile>
    <RepositoryType>git</RepositoryType>
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
    <PackageReadmeFile>README.md</PackageReadmeFile>
    <IsPackable>true</IsPackable>
</PropertyGroup>
  • Description: Provides a description for the NuGet package.
  • Copyright: Specifies the copyright information.
  • NeutralLanguage: Sets the neutral language for the assembly.
  • CurrentDate: Sets the current date, useful for versioning.
  • Authors: Specifies the author of the package.
  • Title: Provides a title for the NuGet package.
  • PackageTags: Specifies tags for the NuGet package to improve discoverability.
  • PackageProjectUrl: Provides the URL to the project repository.
  • PublishRepositoryUrl: Publishes the repository URL in the NuGet package metadata.
  • GenerateAssemblyInfo: Generates assembly information attributes.
  • GeneratePackageOnBuild: Disables automatic package generation on build.
  • IncludeSymbols: Includes symbol files in the NuGet package for debugging.
  • IncludeSource: Includes source files in the NuGet package for debugging.
  • NoWarn: Suppresses specific warnings.
  • Version: Sets the version of the NuGet package.
  • RepositoryUrl: Specifies the repository URL.
  • PackageLicenseFile: Specifies the license file for the package.
  • RepositoryType: Specifies the repository type.
  • EmbedUntrackedSources: Embeds untracked source files in the PDB for better debugging.
  • AllowedOutputExtensionsInPackageBuildOutputFolder: Allows PDB files in the package build output folder.
  • PackageReadmeFile: Specifies the README file for the package.
  • IsPackable: Indicates that the project is packable into a NuGet package.

GitHub Actions

<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'>
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
    <SourceLinkCreate>true</SourceLinkCreate>
    <SourceLinkOriginUrl>https://github.com/ignatandrei/rscg_Interface_to_null_object</SourceLinkOriginUrl>
</PropertyGroup>
  • ContinuousIntegrationBuild: Enables continuous integration build settings.
  • SourceLinkCreate: Enables SourceLink creation for better debugging.
  • SourceLinkOriginUrl: Specifies the SourceLink origin URL.

Additional Package References

<ItemGroup>
    <PackageReference Include="RazorBlade" Version="0.6.0" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
    <PackageReference Include="RSCG_NameGenerator" Version="2024.11.11.1830">
        <OutputItemType>Analyzer</OutputItemType>
        <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
    </PackageReference>
</ItemGroup>
  • RazorBlade: Adds a reference to the RazorBlade package, useful for code generation.
  • RSCG_NameGenerator: Adds a reference to the RSCG_NameGenerator package, useful for generating names in source code.

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.