c# - 在 ASP.NET Core 3.1 中运行时渲染视图
问题描述
我们正在将我们的 ASP.NET Core 1.0 Web 应用程序升级到 ASP.NET Core 3.1。
现在对我们不起作用的一件事是我们的导出服务,它用于从 cshtml 文件生成 PDF。此代码用于 ASP.NET Core 1 应用程序。这是将 cshtml 文件呈现为字符串的代码:
public async Task<string> Export(object viewModel, string reportName, eExportType exportType, PdfExportOptions options)
{
using (var writer = new StringWriter())
{
var viewEngine = _context.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
// Find the view
var viewResult = viewEngine.GetView($"~/Views/Reports/{reportName}.cshtml", $"~/Views/Reports/{reportName}.cshtml", false);
if (viewResult?.Success == false) // This is the line that's not working: Success equals false
{
throw new Exception($"The report {reportName} could not be found.");
}
// Build ViewContext
var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = viewModel
};
var tempData = new TempDataDictionary(_context, new SessionStateTempDataProvider(null));
var routingFeature = _context.Features[typeof(IRoutingFeature)] as RoutingFeature;
var actionContext = new ActionContext(_context, routingFeature?.RouteData, new ActionDescriptor());
var viewContext = new ViewContext(actionContext, viewResult?.View, viewData, tempData, writer, new HtmlHelperOptions());
// Render the view
if (viewResult?.View != null)
await viewResult.View?.RenderAsync(viewContext);
// Invoke the node.js service
var htmlContent = writer.GetStringBuilder().ToString();
var nodeServiceName = $"./NodeServices/{exportType.ToString().ToLower()}";
//var exportHandler = GetExportHandler(exportType, options); // TODO: Currently only works with PDF. Use export handlers for different export types
var result = await _nodeServices.InvokeAsync<byte[]>(nodeServiceName, htmlContent, options);
return Convert.ToBase64String(result);
}
}
由于某种原因 viewResult?.Success 总是错误的。我已经尝试了各种组合以使其发挥作用,例如viewEngine.GetView($"~/Views/Reports/{reportName}.cshtml", $"~/Views/Reports/{reportName}.cshtml", false)
,
viewEngine.GetView($"~/Views/Reports/{reportName}.cshtml", $"{reportName}.cshtml", false),
viewEngine.GetView($"Views/Reports/{reportName}.cshtml", $"{reportName}.cshtml", false)
等等,但它们都不起作用,Success 始终为 false,并且属性 viewResult.View 始终为空。
我在 StackOverflow 上看过很多帖子,比如这个和其他很多帖子,但没有一个能解决我们的问题。我怀疑我们在 Startup 类中可能做错了什么,因为上面的变量 routingFeature 也是空的,但我对此并不完全确定。但只是为了确保正确配置了 Startup 类,下面是它的代码:
public class Startup
{
public Startup(/*IHostingEnvironment env,*/ IConfiguration configuration)
{
Configuration = (IConfigurationRoot)configuration;
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.Configure<SmsProvidersSettings>(Configuration.GetSection("SmsProvidersSettings"));
// More configuration sections here, removed for brevity
services.AddControllers().AddNewtonsoftJson(options =>
{
// Use the default property (Pascal) casing
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddAuthorization();
var sessionTimeout = Convert.ToDouble(Configuration.GetSection("GlobalSettings")["SessionTimeout"]);
var manager = new ApplicationPartManager();
manager.ApplicationParts.Add(new AssemblyPart(typeof(Startup).Assembly));
services.AddSingleton(manager);
services.AddDistributedMemoryCache();
services.AddSession(options => options.IdleTimeout = TimeSpan.FromSeconds(sessionTimeout));
////services.AddMvc(options =>
////{
//// options.Filters.Add(new UserActionAuditFilterAttribute(new AuditHandler(Configuration["ConnectionStrings:Audit"])));
//// options.Filters.Add(new ApiValidationFilterAttribute());
//// options.Filters.Add(new GlobalExceptionFilter());
////});
//services.AddMemoryCache();
services.AddNodeServices(options => options.InvocationTimeoutMilliseconds = 60000);
services.Configure<RequestLocalizationOptions>(opts =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("he-IL")
};
opts.DefaultRequestCulture = new RequestCulture("he-IL", "he-IL");
opts.SupportedCultures = supportedCultures;
opts.SupportedUICultures = supportedCultures;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
if (Convert.ToBoolean(Configuration.GetSection("GlobalSettings")["UseScheduler"]))
{
services.AddHangfire(configuration =>
configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage(
Configuration["ConnectionStrings:DigitalRural"],
new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
UseRecommendedIsolationLevel = true,
PrepareSchemaIfNecessary = true, // Default value: true
EnableHeavyMigrations = true, // Default value: false
UsePageLocksOnDequeue = true,
DisableGlobalLocks = false
}));
}
services.AddTransient<IRecurringJobManager, RecurringJobManager>();
services.AddTransient<IActionSystemService, ActionSystemService>();
// More serivces here, removed for brevity
services.AddScoped<IUnitOfWork>(sp =>
{
var httpContextAccessor = sp.GetService<IHttpContextAccessor>();
var currentUser = httpContextAccessor.HttpContext?.Session.GetJson<SessionUser>(SessionStateKeys.CurrentUser);
int? userId = null;
if (currentUser != null)
userId = currentUser.UserId;
return new UnitOfWork(new DigitalRuralContext(Configuration["ConnectionStrings:DigitalRural"], userId), httpContextAccessor);
});
//
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime, IGlobalApplicationDataService applicationDataService)
{
//var applicationDataService = app.ApplicationServices.GetService(typeof(IGlobalApplicationDataService)) as IGlobalApplicationDataService;
applicationDataService?.GetApplicationDataVM();
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
// Don't cache index.html
context.Response.Headers.Add("Cache-Control", "no-cache, no-store");
context.Response.Headers.Add("Pragma", "no-cache");
}
await next();
// If there's no available file and the request doesn't contain an extension, we're probably trying to access a page.
// Rewrite request to use app root
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
{
context.Request.Path = "/"; // Put your Angular root page here
await next();
}
});
app.UseAuthentication();
app.UseAuthorization();
loggerFactory
.AddSerilog();
//// Ensure any buffered events are sent at shutdown
//appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
//if (env.IsDevelopment())
//{
// app.UseDeveloperExceptionPage();
// app.UseBrowserLink();
//}
//else
//{
// app.UseExceptionHandler("/Home/Error");
//}
////app.UseDefaultFiles();
//app.UseStaticFiles(new StaticFileOptions
//{
// OnPrepareResponse = context => { }
//});
////app.UseMvc();
if (Convert.ToBoolean(Configuration.GetSection("GlobalSettings")["UseScheduler"]))
{
app.UseHangfireDashboard("/scheduler", new DashboardOptions // Will be available at http://localhost:60209/scheduler
{
Authorization = new[] { new HangfireDashbordAuthorizationFilter() }
});
app.UseHangfireServer(new BackgroundJobServerOptions { StopTimeout = TimeSpan.FromSeconds(10) });
}
var applicationServices = app.ApplicationServices;
var httpContextAccessor = applicationServices.GetService<IHttpContextAccessor>();
app.UseFileServer(new FileServerOptions { FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "wwwroot")), RequestPath = "", EnableDefaultFiles = true });
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
}
}
那么你猜猜为什么我们的代码不起作用?
解决方案
推荐阅读
- aem - 如何在 AEM 中使用 HTL 有条件地添加数据属性?
- typescript - 键入以不同方式处理枚举子集的安全方法
- java - 使用正确的同步方式避免数据丢失
- azure - 如何使用 Azure CLI(az ad app)创建范围
- java - .java 使用或覆盖已弃用的 API。& 使用 -Xlint:deprecation 重新编译以获取详细信息
- javascript - 具有 Promises 的不同函数调用类型
- r - sub() 函数替换多个项目
- python - 如何按字段/字符串而不是按字符创建 csv.reader() 索引?
- java - setIconImage intellij 项目 javax.swing
- php - laravel LoginController 中的这个 traitLogout 函数