RSCG – SourceGenerator.Helper.CopyCode

RSCG – SourceGenerator.Helper.CopyCode
 
 

name SourceGenerator.Helper.CopyCode
nuget https://www.nuget.org/packages/SourceGenerator.Helper.CopyCode/
link https://github.com/LokiMidgard/SourceGenerator.Helper.CopyCode
author Patrick Kranz

Transform Code to string

 

This is how you can use SourceGenerator.Helper.CopyCode .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="SourceGenerator.Helper.CopyCode" Version="0.0.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

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


The code that you will use is


Console.WriteLine(SourceGenerator.Helper.CopyCode.Copy.SourceGenerator_Helper_CopyCodeDemoNumberAttribute);
Console.WriteLine(SourceGenerator.Helper.CopyCode.Copy.SourceGenerator_Helper_CopyCodeDemoPerson);




namespace SourceGenerator_Helper_CopyCodeDemo;
[SourceGenerator.Helper.CopyCode.Copy]
[System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
internal sealed class NumberAttribute : Attribute
{
    public int ID;
}

[SourceGenerator.Helper.CopyCode.Copy]
internal class Person
{
    public int Id { get; set; }
}


 

The code that is generated is

// <auto-generated/>
#nullable enable

namespace SourceGenerator.Helper.CopyCode
{
	[global::System.CodeDom.Compiler.GeneratedCodeAttribute("SourceGenerator.Helper.CopyCode", "0.0.1.0")]
	[global::System.AttributeUsage(global::System.AttributeTargets.Enum | global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Interface, AllowMultiple = false)]
	internal sealed class CopyAttribute : global::System.Attribute
	{
	}
}

// <auto-generated/>
#nullable enable
namespace SourceGenerator.Helper.CopyCode;
internal  static partial class Copy {
    public const string SourceGenerator_Helper_CopyCodeDemoNumberAttribute = """
        // <auto-generated/>
        #nullable enable
        
        namespace SourceGenerator_Helper_CopyCodeDemo;
        [System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)]
        internal sealed class NumberAttribute : Attribute
        {
            public int ID;
        }
        """;
}

// <auto-generated/>
#nullable enable
namespace SourceGenerator.Helper.CopyCode;
internal  static partial class Copy {
    public const string SourceGenerator_Helper_CopyCodeDemoPerson = """
        // <auto-generated/>
        #nullable enable
        
        namespace SourceGenerator_Helper_CopyCodeDemo;
        internal class Person
        {
            public int Id { get; set; }
        }
        """;
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/SourceGenerator.Helper.CopyCode

RSCG – ThisAssembly_Resources

RSCG – ThisAssembly_Resources
 
 

name ThisAssembly_Resources
nuget https://www.nuget.org/packages/ThisAssembly.Resources/
link https://www.clarius.org/ThisAssembly/
author Daniel Cazzulino

Embed resources to file

 

This is how you can use ThisAssembly_Resources .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
	<ItemGroup>
		<EmbeddedResource Include="Content/mytext.sql" />
	</ItemGroup>
	<ItemGroup>
	  <PackageReference Include="ThisAssembly.Resources" Version="1.4.1">
	    <PrivateAssets>all</PrivateAssets>
	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	  </PackageReference>
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


Console.WriteLine(ThisAssembly.Resources.Content.mytext.Text);



This is from file

 

The code that is generated is

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Resources: 1.4.1
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.IO;

partial class ThisAssembly
{
    public static partial class Resources
    {
        public static partial class Content
        {
            /// <summary>
            /// => @"Content\mytext.sql"
            /// </summary>
            public static partial class mytext
            {
                private static string text;
                public static string Text => text ??= EmbeddedResource.GetContent(@"Content\mytext.sql");

                public static byte[] GetBytes() => EmbeddedResource.GetBytes(@"Content\mytext.sql");
                public static Stream GetStream() => EmbeddedResource.GetStream(@"Content\mytext.sql");
            }
        }
    }
}
using System;
using System.IO;
using System.Linq;
using System.Reflection;

static class EmbeddedResource
{
    static readonly string baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "";

    public static string GetContent(string relativePath)
    {
        using var stream = GetStream(relativePath);
        using var reader = new StreamReader(stream);
        return reader.ReadToEnd();
    }

    public static byte[] GetBytes(string relativePath)
    {
        using var stream = GetStream(relativePath);
        var bytes = new byte[stream.Length];
        stream.Read(bytes, 0, bytes.Length);
        return bytes;
    }

    public static Stream GetStream(string relativePath)
    {
        var filePath = Path.Combine(baseDir, Path.GetFileName(relativePath));
        if (File.Exists(filePath))
            return File.OpenRead(filePath);

        var baseName = Assembly.GetExecutingAssembly().GetName().Name;
        var resourceName = relativePath
            .TrimStart('.')
            .Replace('/', '.')
            .Replace('\\', '.');

        var manifestResourceName = Assembly.GetExecutingAssembly()
            .GetManifestResourceNames().FirstOrDefault(x => x.EndsWith(resourceName));

        if (string.IsNullOrEmpty(manifestResourceName))
            throw new InvalidOperationException($"Did not find required resource ending in '{resourceName}' in assembly '{baseName}'.");

        return
            Assembly.GetExecutingAssembly().GetManifestResourceStream(manifestResourceName) ??
            throw new InvalidOperationException($"Did not find required resource '{manifestResourceName}' in assembly '{baseName}'.");
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/ThisAssembly_Resources

RSCG – RSCG_Utils_Memo

RSCG – RSCG_Utils_Memo
 
 

name RSCG_Utils_Memo
nuget https://www.nuget.org/packages/rscgutils
link https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation
author Ignat Andrei

Memo the function result

 

This is how you can use RSCG_Utils_Memo .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="rscgutils" Version="2023.914.2016" OutputItemType="Analyzer" ReferenceOutputAssembly="false"  />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using DemoRSCG_UtilsMemo;

fibTest f = new();
Console.Write("start calculating, see output");
Console.WriteLine("first time result:" + f.Test());
Console.WriteLine("memo, no output");
Console.WriteLine("second time result:" + f.Test());
var dt = DateTime.Now;
Console.WriteLine("no memo :" + await f.fib(5) );
Console.WriteLine(" in  " + DateTime.Now.Subtract(dt).TotalSeconds.ToString("0#"));
dt = DateTime.Now;
Console.WriteLine("memo :" + await f.fibonacci(5));
Console.WriteLine(" in  " + DateTime.Now.Subtract(dt).TotalSeconds.ToString("0#"));
dt = DateTime.Now;
Console.WriteLine("FAST memo :" + await f.fibonacci(5));
Console.WriteLine(" in  " + DateTime.Now.Subtract(dt).TotalSeconds.ToString("0#"));




namespace DemoRSCG_UtilsMemo;

internal partial class fibTest
{
    public long Test_MemoPure()
    {
        Console.WriteLine("calculating type");
        return this.GetType().ToString().GetHashCode();
    }
    public async Task<long> fib(long nr)
    {
        await Task.Delay(1000);
        //Console.WriteLine("calculated value for " + nr);
        if (nr <= 1) return 1;
        if (nr == 2) return 2;
        return await fib(nr - 1) + await fib(nr - 1);
    }

    public async Task<long> fibonacci_MemoPure(long nr)
    {
        if (nr <= 1) return 1;
        if (nr == 2) return 2;
        await Task.Delay(1000);
        return await fibonacci(nr - 1) + await fibonacci(nr - 1);

    }
}


 

The code that is generated is

using System.Collections.Concurrent;

//this is auto-generated by a tool
namespace DemoRSCG_UtilsMemo;
partial class fibTest 
{
    
    System.Collections.Concurrent.ConcurrentDictionary<Tuple<long > , long> __cache_DemoRSCG_UtilsMemo_fibTest_fibonacci_MemoPure =new System.Collections.Concurrent.ConcurrentDictionary<Tuple<long >, long>();
    //True 
    public async Task<long>  fibonacci (long nr ){
        var key= Tuple.Create(nr);
        if (__cache_DemoRSCG_UtilsMemo_fibTest_fibonacci_MemoPure.TryGetValue(key, out var result)) return result;
        //Console.WriteLine($"not in cache, calculating {key}");
        var data= await __wrap_fibonacci(key);
        return __cache_DemoRSCG_UtilsMemo_fibTest_fibonacci_MemoPure.GetOrAdd(key,data);
    }
    public async Task<long>  __wrap_fibonacci (Tuple<long > args){
        return await fibonacci_MemoPure (args.Item1);
    }
    
}

using System.Collections.Concurrent;

//this is auto-generated by a tool
namespace DemoRSCG_UtilsMemo;
partial class fibTest 
{
    
    System.Collections.Concurrent.ConcurrentDictionary<string , long > __cache_DemoRSCG_UtilsMemo_fibTest_Test_MemoPure =new System.Collections.Concurrent.ConcurrentDictionary<string, long >();
    //False 
    public  long  Test ( ){
        var key= string.Empty;
        if (__cache_DemoRSCG_UtilsMemo_fibTest_Test_MemoPure.TryGetValue(key, out var result)) return result;
        //Console.WriteLine($"not in cache, calculating {key}");
        var data=  __wrap_Test(key);
        return __cache_DemoRSCG_UtilsMemo_fibTest_Test_MemoPure.GetOrAdd(key,data);
    }
    public  long  __wrap_Test (string args){
        return  Test_MemoPure ();
    }
    
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/RSCG_Utils_Memo

RSCG – Roozie.AutoInterface

RSCG – Roozie.AutoInterface
 
 

name Roozie.AutoInterface
nuget https://www.nuget.org/packages/Roozie.AutoInterface/
link https://github.com/AlexRussak/Roozie.AutoInterface
author Alex Russak

Generating interfaces from project

 

This is how you can use Roozie.AutoInterface .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Roozie.AutoInterface" Version="0.6.1" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using Roozie.AutoInterfaceDemo;

IPerson p = new Person();
p.FirstName = "Andrei";
p.LastName = "Ignat";
Console.WriteLine(p.FullName() );


using Roozie.AutoInterface;

namespace Roozie.AutoInterfaceDemo;

[AutoInterface(IncludeMethods =true,IncludeProperties =true)]
public partial class Person
{
    public int ID { get; set; }
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string FullName()
    {
        return FirstName + " " + LastName;
    }
}


 

The code that is generated is

// <auto-generated>
// This file was generated by Roozie.AutoInterface v0.6.1.0
// </auto-generated>

using Roozie.AutoInterface;

namespace Roozie.AutoInterfaceDemo;

#nullable enable

public partial class Person : IPerson {}

public partial interface IPerson
{
    int ID { get; set; }

    string? FirstName { get; set; }

    string? LastName { get; set; }

    string FullName();

}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Roozie.AutoInterface

RSCG – M31.FluentAPI

RSCG – M31.FluentAPI
 
 

name M31.FluentAPI
nuget https://www.nuget.org/packages/M31.FluentAPI/
link https://www.m31coding.com/blog/fluent-api.html
author Kevin Schaal

Builder for your class. But the order counts – generates a new interface each time

 

This is how you can use M31.FluentAPI .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
	<ItemGroup>
		<PackageReference Include="M31.FluentApi" Version="1.0.0" PrivateAssets="all"/>
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using M31FluentAPIDemo;

Console.WriteLine("Hello, World!");
var p =CreatePerson
    //the order does matter
    .Named("Andrei","Ignat")
    .HasDOB(null);



using M31.FluentApi.Attributes;

namespace M31FluentAPIDemo;
[FluentApi]
internal class Person
{
    [FluentMember(0, "Named", 0)]
    public string FirstName { get; set; } = string.Empty;
    [FluentMember(0, "Named", 1)]
    public string? LastName { get; set; }

    [FluentMember(1, "HasDOB")]
    public DateTime? DOB { get; set; }
}


 

The code that is generated is

// <auto-generated/>
// This code was generated by the library M31.FluentAPI.
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.

#nullable enable

using M31.FluentApi.Attributes;

namespace M31FluentAPIDemo;

internal class CreatePerson : CreatePerson.IHasDOB
{
    private readonly Person person;

    private CreatePerson()
    {
        person = new Person();
    }

    public static IHasDOB Named(string firstName, string? lastName)
    {
        CreatePerson createPerson = new CreatePerson();
        createPerson.person.FirstName = firstName;
        createPerson.person.LastName = lastName;
        return createPerson;
    }

    public Person HasDOB(System.DateTime? dOB)
    {
        person.DOB = dOB;
        return person;
    }

    internal interface IHasDOB
    {
        Person HasDOB(System.DateTime? dOB);
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/M31.FluentAPI

RSCG – AutoDTO

RSCG – AutoDTO
 
 

name AutoDTO
nuget https://www.nuget.org/packages/AutoDTO/
link https://github.com/Ohorodnikov/AutoDto
author Ohorodnikov

Generate DTO classes from business/ef classes

 

This is how you can use AutoDTO .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AutoDto" Version="2.1.0" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


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

var d = new Department();
d.Name = "IT";
d.ID = 1;
d.Employees=new Employee[] { new Employee() };

var dto= new DepartmentDTO();
//it will be beneficial if it will have also a constructor
//for transfer properties
dto.Name = d.Name;
dto.ID = d.ID;


namespace AutoDTODemo;
public class Department
{
    public int ID { get; set; }
    public string? Name { get; set; }
    public Employee[]? Employees { get; set; }
}



using AutoDto.Setup;

namespace AutoDTODemo;

[DtoFrom(typeof(Department))]
[DtoIgnore(nameof(Department.Employees))]
public partial class DepartmentDTO { 
}


 

The code that is generated is

namespace AutoDTODemo;

public partial class DepartmentDTO
{
public System.Int32 ID { get; set; }
public System.String Name { get; set; }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/AutoDTO

RSCG – RSCG_WebAPIExports

RSCG – RSCG_WebAPIExports
 
 

name RSCG_WebAPIExports
nuget https://www.nuget.org/packages/RSCG_WebAPIExports/
link https://github.com/ignatandrei/RSCG_WebAPIExports/
author Andrei Ignat

Generating Excel from WebAPI json array

 

This is how you can use RSCG_WebAPIExports .

The code that you start with is


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

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
	<PackageReference Include="RSCG_WebAPIExports" Version="2023.8.16.1255" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
	<PackageReference Include="ArrayToExcel" Version="2.2.2" />

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


The code that you will use is


using RSCG_WebAPIExportsDemo;
using WebApiExportToFile;
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddExport();
var app = builder.Build();
app.UseExport();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(ct =>
    {
        ct.DocumentTitle = "try /WeatherForecast.xlsx";
        ct.HeadContent = "try /WeatherForecast.xlsx";
    });
}

//app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();



using Microsoft.AspNetCore.Mvc;

namespace RSCG_WebAPIExportsDemo.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

 

The code that is generated is

using Microsoft.AspNetCore.Rewrite;
namespace WebApiExportToFile;
#nullable enable
public static partial class Extensions
{
    static partial  void AddReturnTypesFromGenerator();
    public static IServiceCollection AddExport(this IServiceCollection services, params Type[]? typesReturnedByActions)
    {
        AddReturnTypesFromGenerator();
        //MiddlewareExportToFile.AddReturnType(typeof(Person[]));
        //MiddlewareExportToFile.AddReturnType(typeof(WeatherForecast[]));
        MiddlewareExportToFile.AddReturnTypes(typesReturnedByActions);

        return services.AddSingleton<MiddlewareExportToFile>();
    }
    public static IApplicationBuilder UseExport(this IApplicationBuilder app)
    {
        app.UseMiddleware<MiddlewareExportToFile>();
        var options = new RewriteOptions().Add(MiddlewareExportToFile.RewriteExtNeeded);
        app.UseRewriter(options);
        return app;
    }
}

#nullable disable
namespace WebApiExportToFile;

public static partial class Extensions
{
   static partial  void AddReturnTypesFromGenerator(){
       MiddlewareExportToFile.AddReturnType(typeof(RSCG_WebAPIExportsDemo.WeatherForecast[])); 
   }
}
using System.IO;
using System.Text;
using System;
using Microsoft.AspNetCore.Rewrite;
using System.Text.Json;
using ArrayToExcel;
using System.Text.Json.Serialization.Metadata;
using System.Runtime.CompilerServices;
#nullable enable
namespace WebApiExportToFile;
public class MiddlewareExportToFile : IMiddleware
{
    private static List<Type> types = new(); 
    static readonly string[] Extensions = new string[1] { ".xlsx" };
    static string key = "Export";
    public static void AddReturnTypes(params Type[]? typesReturnedByActions)
    {
        if (typesReturnedByActions?.Length > 0)
        {
            foreach (var type in typesReturnedByActions)
            {
                AddReturnType(type);
            }
        }
    }
    public static void AddReturnType(Type type)
    {
        types.Add(type);
    }
    public static void RewriteExtNeeded(RewriteContext context)
    {
        var request = context.HttpContext.Request;
        if (!(context.HttpContext.Items.ContainsKey(key) && context.HttpContext.Items[key]?.ToString() == "1"))
        {
            return;
        }
        var ext = Path.GetExtension(request.Path.Value);
        if (string.IsNullOrWhiteSpace(ext)) return;
        request.Path = request.Path.Value!.Substring(0, request.Path.Value.Length - ext.Length);

    }
    public bool ShouldIntercept(HttpContext context)
    {
        string path = context.Request.Path;
        var ext = Path.GetExtension(path);
        if (string.IsNullOrWhiteSpace(ext)) return false;
        if (!Extensions.Contains(ext, StringComparer.OrdinalIgnoreCase)) return false;
        return true;
    }
    //https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft
    static void AddMissingMemberHandling(JsonTypeInfo typeInfo)
    {
        if (typeInfo.Kind == JsonTypeInfoKind.Object &&
            typeInfo.Properties.All(prop => !prop.IsExtensionData) &&
            typeInfo.OnDeserialized is null)
        {
            // Dynamically attach dictionaries to deserialized objects.
            var cwt = new ConditionalWeakTable<object, Dictionary<string, object>>();

            JsonPropertyInfo propertyInfo =
                typeInfo.CreateJsonPropertyInfo(typeof(Dictionary<string, object>), "__extensionDataAttribute");
            propertyInfo.Get = obj => cwt.TryGetValue(obj, out Dictionary<string, object>? value) ? value : null;
            propertyInfo.Set = (obj, value) => cwt.Add(obj, (Dictionary<string, object>)value!);
            propertyInfo.IsExtensionData = true;
            typeInfo.Properties.Add(propertyInfo);
            typeInfo.OnDeserialized = obj =>
            {
                if (cwt.TryGetValue(obj, out Dictionary<string, object>? dict))
                {
                    cwt.Remove(obj);
                    throw new JsonException($"JSON properties {String.Join(", ", dict.Keys)} " +
                        $"could not bind to any members of type {typeInfo.Type}");
                }
            };
        }
    }
    public object[]? StrongDeserialize(string responseContent)
    {
        if(types.Count() == 0) throw new Exception("please add some types");
        foreach( var type in types)
        {
            try
            {
                var data = JsonSerializer.Deserialize(responseContent, type, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true,
                    TypeInfoResolver = new DefaultJsonTypeInfoResolver
                    {
                        Modifiers = { AddMissingMemberHandling }
                    }
                }) as object[];
                return data;
            }
            catch(JsonException)
            {
                //do nothing 
                
            }
            
        }
        throw new Exception("no type can deserialize " +responseContent);

    }
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        if (!ShouldIntercept(context))
        {
            await next(context);
            return;
        }
        var ext=Path.GetExtension(context.Request.Path.Value);
        var nameFile = context.Request.Path.Value?.Replace("/", "_");
        context.Items["Export"] = "1";
        var originalResponseBody = context.Response.Body;
        using var memoryStream = new MemoryStream();
        context.Response.Body = memoryStream;
        context.Response.Headers.Add("Content-Disposition", $"attachment; filename={nameFile}");
        await next(context);
        memoryStream.Seek(0, SeekOrigin.Begin);
        var responseContent = await new StreamReader(memoryStream).ReadToEndAsync();
        context.Response.Body = originalResponseBody;

        var data = StrongDeserialize(responseContent);
        ArgumentNullException.ThrowIfNull(data);
        using var excelStream = data.ToExcelStream();
        await excelStream.CopyToAsync(context.Response.Body);

        // No need to call the next middleware since the generated content has been sent
        return;
    }
    
}    

#nullable disable

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/RSCG_WebAPIExports

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.