diff --git a/demos/XReports.Demos/Controllers/CustomWriters/RazorWriterController.cs b/demos/XReports.Demos/Controllers/CustomWriters/RazorWriterController.cs new file mode 100644 index 0000000..0b6601a --- /dev/null +++ b/demos/XReports.Demos/Controllers/CustomWriters/RazorWriterController.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Bogus; +using Microsoft.AspNetCore.Mvc; +using XReports.Converter; +using XReports.Demos.Models.Shared; +using XReports.Demos.XReports; +using XReports.Html; +using XReports.SchemaBuilders; +using XReports.Table; + +namespace XReports.Demos.Controllers.CustomWriters; + +public class RazorWriterController : Controller +{ + private const int RecordsCount = 10; + + private readonly IServiceProvider serviceProvider; + + public RazorWriterController(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public async Task Index() + { + IReportTable reportTable = this.BuildReport(); + IReportTable htmlReportTable = this.ConvertToHtml(reportTable); + string tableHtml = await this.WriteHtmlReportToStringAsync(htmlReportTable); + + return this.View(new ReportViewModel() { ReportTableHtml = tableHtml }); + } + + private IReportTable BuildReport() + { + ReportSchemaBuilder reportBuilder = new(); + reportBuilder.AddColumn("Name", e => e.Name); + reportBuilder.AddColumn("Score", e => e.Score); + + IReportTable reportTable = reportBuilder.BuildVerticalSchema().BuildReportTable(this.GetData()); + return reportTable; + } + + private IReportTable ConvertToHtml(IReportTable reportTable) + { + ReportConverter htmlConverter = new(Array.Empty>()); + + return htmlConverter.Convert(reportTable); + } + + private Task WriteHtmlReportToStringAsync(IReportTable htmlReportTable) + { + return new RazorWriter(this.serviceProvider) + .WriteAsync(htmlReportTable, "~/Views/RazorWriter/Report.cshtml"); + } + + private IEnumerable GetData() + { + return new Faker() + .RuleFor(e => e.Name, f => f.Name.FullName()) + .RuleFor(e => e.Score, f => f.Random.Decimal(0, 100)) + .Generate(RecordsCount); + } + + private class Entity + { + public string Name { get; set; } + + public decimal Score { get; set; } + } +} diff --git a/demos/XReports.Demos/Views/RazorWriter/Index.cshtml b/demos/XReports.Demos/Views/RazorWriter/Index.cshtml new file mode 100644 index 0000000..235685b --- /dev/null +++ b/demos/XReports.Demos/Views/RazorWriter/Index.cshtml @@ -0,0 +1,73 @@ +@model XReports.Demos.Models.Shared.ReportViewModel + +@{ + ViewBag.Title = "Razor Writer"; + Layout = "_DemoPageLayout"; +} + +@section Description +{ +

This example writer shows how to use Razor syntax for rendering report.

+} + +@section ReportTable +{ +@Html.Raw(Model.ReportTableHtml) +} + +@section Code +{ + public class RazorWriter + { + private readonly ICompositeViewEngine viewEngine; + private readonly ITempDataProvider tempDataProvider; + private readonly IServiceProvider serviceProvider; + + public RazorWriter(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + this.viewEngine = this.serviceProvider.GetRequiredService<ICompositeViewEngine>(); + this.tempDataProvider = this.serviceProvider.GetRequiredService<ITempDataProvider>(); + } + + public Task<string> WriteAsync(IReportTable<HtmlReportCell> report, string viewName) + { + return this.RenderSimpleViewToStringAsync(viewName, report); + } + + private async Task<string> RenderSimpleViewToStringAsync<TModel>(string viewName, TModel model) + { + ViewEngineResult viewResult = this.viewEngine.GetView( + executingFilePath: null, + viewPath: viewName, + isMainPage: true); + if (!viewResult.Success) + { + throw new ArgumentException($"Could not find view: {viewName}", nameof(viewName)); + } + + await using StringWriter writer = new(); + ViewDataDictionary<TModel> viewDictionary = new(new EmptyModelMetadataProvider(), new ModelStateDictionary()) + { + Model = model, + }; + ViewContext viewContext = new( + new ActionContext( + new DefaultHttpContext() + { + RequestServices = this.serviceProvider, + }, + new RouteData(), + new ActionDescriptor()), + viewResult.View, + viewDictionary, + new TempDataDictionary(new DefaultHttpContext(), this.tempDataProvider), + writer, + new HtmlHelperOptions() + ); + await viewResult.View.RenderAsync(viewContext); + + return writer.ToString(); + } + } +} diff --git a/demos/XReports.Demos/Views/RazorWriter/Report.cshtml b/demos/XReports.Demos/Views/RazorWriter/Report.cshtml new file mode 100644 index 0000000..457b3fc --- /dev/null +++ b/demos/XReports.Demos/Views/RazorWriter/Report.cshtml @@ -0,0 +1,68 @@ +@using XReports.Html +@using Microsoft.AspNetCore.Html +@using System.Text +@using System.Net + +@model XReports.Table.IReportTable + +@{ + Layout = null; +} + +@functions +{ + public static HtmlString WriteAttributes(HtmlReportCell cell) + { + StringBuilder sb = new(); + if (cell.CssClasses.Count > 0) + { + sb + .Append(" class=\"") + .AppendJoin(' ', cell.CssClasses) + .Append('"'); + } + + if (cell.Styles.Count > 0) + { + sb + .Append(" style=\"") + .AppendJoin(';', cell.Styles.Select(s => $"{s.Key}:{s.Value}")) + .Append('"'); + } + + if (cell.Attributes.Count > 0) + { + sb + .AppendJoin( + ' ', + cell.Attributes.Select(a => $"{a.Key}=\"{WebUtility.HtmlEncode(a.Value)}\"")); + } + + return new HtmlString(sb.ToString()); + } +} + + + + @foreach (IEnumerable row in Model.HeaderRows) + { + + @foreach (HtmlReportCell cell in row) + { + + } + + } + + + @foreach (IEnumerable row in Model.Rows) + { + + @foreach (HtmlReportCell cell in row) + { + + } + + } + +
@(cell.IsHtml ? Html.Raw(cell.GetValue()) : cell.GetValue())
@(cell.IsHtml ? Html.Raw(cell.GetValue()) : cell.GetValue())
diff --git a/demos/XReports.Demos/Views/Shared/_Layout.cshtml b/demos/XReports.Demos/Views/Shared/_Layout.cshtml index 9297a47..195a473 100644 --- a/demos/XReports.Demos/Views/Shared/_Layout.cshtml +++ b/demos/XReports.Demos/Views/Shared/_Layout.cshtml @@ -68,6 +68,12 @@ Named Converters + diff --git a/demos/XReports.Demos/XReports/RazorWriter.cs b/demos/XReports.Demos/XReports/RazorWriter.cs new file mode 100644 index 0000000..a03d9a7 --- /dev/null +++ b/demos/XReports.Demos/XReports/RazorWriter.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.ViewEngines; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using XReports.Html; +using XReports.Table; + +namespace XReports.Demos.XReports; + +public class RazorWriter +{ + private readonly ICompositeViewEngine viewEngine; + private readonly ITempDataProvider tempDataProvider; + private readonly IServiceProvider serviceProvider; + + public RazorWriter(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + this.viewEngine = this.serviceProvider.GetRequiredService(); + this.tempDataProvider = this.serviceProvider.GetRequiredService(); + } + + public Task WriteAsync(IReportTable report, string viewName) + { + return this.RenderSimpleViewToStringAsync(viewName, report); + } + + private async Task RenderSimpleViewToStringAsync(string viewName, TModel model) + { + ViewEngineResult viewResult = this.viewEngine.GetView( + executingFilePath: null, + viewPath: viewName, + isMainPage: true); + if (!viewResult.Success) + { + throw new ArgumentException($"Could not find view: {viewName}", nameof(viewName)); + } + + await using StringWriter writer = new(); + ViewDataDictionary viewDictionary = new(new EmptyModelMetadataProvider(), new ModelStateDictionary()) + { + Model = model, + }; + ViewContext viewContext = new( + new ActionContext( + new DefaultHttpContext() + { + RequestServices = this.serviceProvider, + }, + new RouteData(), + new ActionDescriptor()), + viewResult.View, + viewDictionary, + new TempDataDictionary(new DefaultHttpContext(), this.tempDataProvider), + writer, + new HtmlHelperOptions() + ); + await viewResult.View.RenderAsync(viewContext); + + return writer.ToString(); + } +}