Как задать новый базовый класс для cshtml в asp.net core, не используя _ViewImports.cshtml и @inherits?
Собственно, сабж. Искомое надо сделать на уровне кода, не влезая в представления, поэтому _ViewImports и @inherited отпадают. Я знаю, что они удобнее, но всё же.
В asp.net mvc можно было переопределить MvcWebPageRazorHost и задать в нем параметры представлений, можно было переопределить RazorBuildProvider и сделать аналогичное в нем. Что подобное есть в asp.net core?
Собственно, вот одно из решений вопроса. Полный текст типового класса Startup.cs плюс изменения.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using CompilationTagHelperFeature = Microsoft.CodeAnalysis.Razor.CompilationTagHelperFeature;
using DefaultTagHelperDescriptorProvider = Microsoft.CodeAnalysis.Razor.DefaultTagHelperDescriptorProvider;
namespace WebApplication4
{
public abstract class RazorPageCustom<TModel> : RazorPage<TModel>
{
}
public abstract class RazorPageCustom : RazorPageCustom<dynamic>
{
}
public sealed class NewBaseClassPass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
{
protected override void ExecuteCore(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
var @class = documentNode.FindPrimaryClass();
if (@class == null) return;
var type_ = typeof(RazorPageCustom<>);
@class.BaseType = type_.FullName.Replace("`1", "<TModel>");
}
public override int Order => 4;
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton(s =>
{
// Всё внутри лямбды скопировано из MvcRazorMvcCoreBuilderExtensions, кроме добавления NewBaseClassPass.
var fileSystem = s.GetRequiredService<RazorProjectFileSystem>();
var projectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, builder =>
{
RazorExtensions.Register(builder);
// Roslyn + TagHelpers infrastructure
var metadataReferenceFeature = s.GetRequiredService<LazyMetadataReferenceFeature>();
builder.Features.Add(metadataReferenceFeature);
builder.Features.Add(new CompilationTagHelperFeature());
// TagHelperDescriptorProviders (actually do tag helper discovery)
builder.Features.Add(new DefaultTagHelperDescriptorProvider());
builder.Features.Add(new ViewComponentTagHelperDescriptorProvider());
builder.Features.Add(new NewBaseClassPass());
builder.Phases.Add(new DebugRazorEnginePhase());
});
return projectEngine;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}