| | | 1 | | using Microsoft.AspNetCore.Mvc.Controllers; |
| | | 2 | | using Microsoft.AspNetCore.Mvc.ModelBinding; |
| | | 3 | | using Microsoft.AspNetCore.Mvc.Rendering; |
| | | 4 | | using Microsoft.AspNetCore.Mvc.ViewEngines; |
| | | 5 | | using Microsoft.AspNetCore.Mvc.ViewFeatures; |
| | | 6 | | using Microsoft.Extensions.DependencyInjection; |
| | | 7 | | |
| | | 8 | | namespace ZhEaIsNsAaBn.Utilities.PrintPDF; |
| | | 9 | | |
| | | 10 | | /// <summary>A Razor view (and model) to print with <see cref="ChromiumHandler.PrintPdfFromViewAsync"/>.</summary> |
| | | 11 | | public class ViewAsPdf : ViewResult |
| | | 12 | | { |
| | | 13 | | /// <summary>Creates a view to print; the view name defaults to the action name.</summary> |
| | | 14 | | /// <param name="viewData">Extra view data.</param> |
| | 0 | 15 | | public ViewAsPdf( ViewDataDictionary? viewData = null ) |
| | | 16 | | { |
| | 0 | 17 | | MasterName = string.Empty; |
| | 0 | 18 | | ViewName = string.Empty; |
| | 0 | 19 | | Model = null; |
| | 0 | 20 | | ViewData = viewData; |
| | 0 | 21 | | } |
| | | 22 | | |
| | | 23 | | /// <summary>Creates a view to print.</summary> |
| | | 24 | | /// <param name="viewName">The view name or path.</param> |
| | | 25 | | /// <param name="model">The model.</param> |
| | | 26 | | /// <param name="viewData">Extra view data.</param> |
| | 0 | 27 | | public ViewAsPdf( string viewName, object? model, ViewDataDictionary? viewData = null ) : this( viewData ) |
| | | 28 | | { |
| | 0 | 29 | | ViewName = viewName; |
| | 0 | 30 | | Model = model; |
| | 0 | 31 | | } |
| | | 32 | | |
| | | 33 | | /// <summary>Creates a view to print.</summary> |
| | | 34 | | /// <param name="viewName">The view name or path.</param> |
| | | 35 | | /// <param name="viewData">Extra view data.</param> |
| | 0 | 36 | | public ViewAsPdf( string viewName, ViewDataDictionary? viewData = null ) : this( viewData ) => ViewName = viewName; |
| | | 37 | | |
| | | 38 | | /// <summary>Creates a view to print, named after the action.</summary> |
| | | 39 | | /// <param name="model">The model.</param> |
| | | 40 | | /// <param name="viewData">Extra view data.</param> |
| | 0 | 41 | | public ViewAsPdf( object? model, ViewDataDictionary? viewData = null ) : this( viewData ) => Model = model; |
| | | 42 | | |
| | | 43 | | /// <summary>Creates a view to print with a layout.</summary> |
| | | 44 | | /// <param name="viewName">The view name or path.</param> |
| | | 45 | | /// <param name="masterName">The layout name (kept for callers; the view's own layout is used).</param> |
| | | 46 | | /// <param name="model">The model.</param> |
| | 0 | 47 | | public ViewAsPdf( string viewName, string masterName, object? model ) : this( viewName, model ) => MasterName = mast |
| | | 48 | | |
| | | 49 | | |
| | | 50 | | /// <summary>The view name or path; empty means the action name.</summary> |
| | | 51 | | public new string ViewName { get; init; } = string.Empty; |
| | | 52 | | |
| | | 53 | | /// <summary>The layout name.</summary> |
| | | 54 | | public string MasterName { get; init; } = string.Empty; |
| | | 55 | | |
| | | 56 | | /// <summary>The model.</summary> |
| | | 57 | | public new object? Model { get; init; } |
| | | 58 | | |
| | | 59 | | /// <summary>Extra view data copied into the render.</summary> |
| | | 60 | | public new ViewDataDictionary? ViewData { get; set; } |
| | | 61 | | |
| | | 62 | | |
| | | 63 | | /// <summary>Renders the view to an HTML string.</summary> |
| | | 64 | | /// <param name="context">The action context.</param> |
| | | 65 | | /// <returns>The HTML.</returns> |
| | | 66 | | /// <exception cref="InvalidOperationException">The view can't be found.</exception> |
| | | 67 | | protected internal virtual async Task<string> GetHtmlAsStringAsync( ActionContext context ) |
| | | 68 | | { |
| | 0 | 69 | | ArgumentNullException.ThrowIfNull( context ); |
| | | 70 | | |
| | 0 | 71 | | var viewName = string.IsNullOrEmpty( ViewName ) ? ( (ControllerActionDescriptor) context.ActionDescriptor ).Acti |
| | 0 | 72 | | var view = GetView( context, viewName, MasterName ).View!; |
| | | 73 | | |
| | | 74 | | |
| | 0 | 75 | | var tempDataProvider = context.HttpContext.RequestServices.GetService<ITempDataProvider>(); |
| | 0 | 76 | | var viewDataDictionary = new ViewDataDictionary( new EmptyModelMetadataProvider(), new ModelStateDictionary() ) |
| | | 77 | | |
| | 0 | 78 | | if ( ViewData is not null ) |
| | | 79 | | { |
| | 0 | 80 | | foreach ( var item in ViewData ) { viewDataDictionary.Add( item ); } |
| | | 81 | | } |
| | | 82 | | |
| | | 83 | | |
| | 0 | 84 | | using var output = new StringWriter(); |
| | 0 | 85 | | var tempDataDictionary = new TempDataDictionary( context.HttpContext, tempDataProvider! ); |
| | 0 | 86 | | var viewContext = new ViewContext( context, view, viewDataDictionary, tempDataDictionary, output, n |
| | | 87 | | |
| | 0 | 88 | | await view.RenderAsync( viewContext ).ConfigureAwait( false ); |
| | | 89 | | |
| | | 90 | | |
| | 0 | 91 | | return output.ToString(); |
| | 0 | 92 | | } |
| | | 93 | | |
| | | 94 | | /// <summary>Finds the view by path, then by name.</summary> |
| | | 95 | | /// <param name="context">The action context.</param> |
| | | 96 | | /// <param name="viewName">The view name or path.</param> |
| | | 97 | | /// <param name="masterName">The layout name.</param> |
| | | 98 | | /// <returns>The found view.</returns> |
| | | 99 | | /// <exception cref="InvalidOperationException">The view can't be found; the message lists the searched locations.</ |
| | | 100 | | protected virtual ViewEngineResult GetView( ActionContext context, string viewName, string masterName ) |
| | | 101 | | { |
| | 0 | 102 | | ArgumentNullException.ThrowIfNull( context ); |
| | | 103 | | |
| | 0 | 104 | | var engine = context.HttpContext.RequestServices.GetRequiredService<ICompositeViewEngine>(); |
| | | 105 | | |
| | | 106 | | |
| | 0 | 107 | | var getViewResult = engine.GetView( null, viewName, true ); |
| | | 108 | | |
| | 0 | 109 | | if ( getViewResult.Success ) { return getViewResult; } |
| | | 110 | | |
| | | 111 | | |
| | 0 | 112 | | var findViewResult = engine.FindView( context, viewName, true ); |
| | | 113 | | |
| | 0 | 114 | | if ( findViewResult.Success ) { return findViewResult; } |
| | | 115 | | |
| | | 116 | | |
| | 0 | 117 | | var searchedLocations = getViewResult.SearchedLocations.Concat( findViewResult.SearchedLocations ); |
| | | 118 | | |
| | | 119 | | |
| | 0 | 120 | | throw new InvalidOperationException( string.Join( Environment.NewLine, |
| | 0 | 121 | | new[] { $"Unable to find view '{viewName}'. The following loca |
| | | 122 | | } |
| | | 123 | | } |