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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | < 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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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(); |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 |
1 2 3 4 5 6 7 8 | namespace WebApiExportToFile; public static partial class Extensions { static partial void AddReturnTypesFromGenerator(){ MiddlewareExportToFile.AddReturnType( typeof (RSCG_WebAPIExportsDemo.WeatherForecast[])); } } |
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 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 ; } 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
Leave a Reply