aspnetcore:如何从中间件返回视图

时间:2017-10-16 19:20:32

标签: razor asp.net-core .net-core asp.net-core-2.0

我在aspnetcore2.0的中间件上工作,我想执行一些剃刀视图。
实际上我需要一个错误处理中间件,它会显示来自剃刀视图的漂亮页面。我知道可以根据状态代码对UseStatusCodePagesWithReExecute进行操作。但是我需要一种更通用的方法 - 在我的中间件中处理异常,以便将它(在某些情况下)委托给错误视图。

我意识到DeveloperExceptionPageMiddleware做了类似我需要的事情。但即使在深入研究其来源之后,我也无法理解它是如何运作的。

以下是该中间件返回视图的位置 - https://github.com/aspnet/Diagnostics/blob/dev/src/Microsoft.AspNetCore.Diagnostics/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs#L206

但我无法理解它是什么样的观点。它既不是 razor页面(因为它没有@page指令)也不是 mvc视图(但我不确定)。

在该项目中,该视图包含两个文件:ErrorPage.cshtmlErrorPage.Designer.cs。 Designer.cs是如何创建的?它看起来像生成的文件。但是由于它,项目(ErrorPage)中的普通类可以显式使用。它从Microsoft.Extensions.RazorViews.BaseView包继承Microsoft.Extensions.RazorViews.Sources类。

因此中间件只执行该视图:

var errorPage = new ErrorPage(model);
return errorPage.ExecuteAsync(context);

如何在我的项目中实现?

1 个答案:

答案 0 :(得分:5)

更新[2018.06]:请注意,该帖子是针对.NET Core 2.0编写的,其中包含了针对.NET Core 2.1中RazorEngine的更改。

事实证明,这很容易做到。 Aspnet prjoect有一个名为RazorPageGenerator的内部工具(参见https://github.com/aspnet/Razor/tree/dev/src/RazorPageGenerator),可用于编译视图。使用此工具编译后,我们将获得可用于中间件的普通类。

但在我们需要获得RazorPageGenerator并稍微定制它之前。

1.创建一个新的控制台项目

dotnet new console -o MyRazorGenerator

2.在此文件夹中输入NuGet.config

<configuration>
  <config>
    <add key="globalPackagesFolder" value="./packages" />
  </config>
  <packageSources>
    <add key="aspnetcore-dev" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json " />
  </packageSources>
</configuration>

3.在csprj中添加以下内容(因为dotnet add package不支持安装pre-prelease软件包)

<ItemGroup>
  <PackageReference Include="RazorPageGenerator" Version="2.1.0-*" />
  <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.Extensions" Version="2.1.0-*" />
  <PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="2.1.0-*" />
</ItemGroup>

4.restore dotnet restore检查你是否有RazorPageGenerator

5.add into Program.cs

    public static int Main(string[] args)
    {
        if (args == null || args.Length < 1)
        {
            Console.WriteLine("Invalid argument(s).");
            return 1;
        }

        var rootNamespace = args[0];
        var targetProjectDirectory = args.Length > 1 ? args[1] : Directory.GetCurrentDirectory();

        var razorEngine = RazorPageGenerator.Program.CreateRazorEngine(rootNamespace, builder => {
            FunctionsDirective.Register(builder);
            InheritsDirective.Register(builder);
            SectionDirective.Register(builder);
        });
        var results = RazorPageGenerator.Program.MainCore(razorEngine, targetProjectDirectory);

        foreach (var result in results)
        {
            File.WriteAllText(result.FilePath, result.GeneratedCode);
        }

        Console.WriteLine();
        Console.WriteLine($"{results.Count} files successfully generated.");
        Console.WriteLine();
        return 0;
    }

6.现在我们有自己的生成器,可以编译视图

7.创建一个Razor视图(.cshtml)

8.运行我们的生成器来编译视图:

dotnet run --project .\MyRazorPageGenerator\MyRazorPageGenerator.csproj Croc.XFW3.Web .\Middleware

这里我假设视图位于Middleware\Views文件夹内。

9.Generator创建一个像ErrorPage.Designer.cs(如果视图是ErrorPage.cshtml)的文件,我们可以使用它:

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next.Invoke(context);
            if (context.Response.StatusCode == StatusCodes.Status404NotFound)
            {
                var statusCodeFeature  = context.Features.Get<IStatusCodePagesFeature>();
                if (statusCodeFeature == null || !statusCodeFeature.Enabled)
                {
                    if (!context.Response.HasStarted)
                    {
                        var view = new ErrorPage(new ErrorPageModel());
                        await view.ExecuteAsync(context);
                    }
                }
            }
        }
    }

我们在404错误和没有StatusCodePagesMiddleware的情况下返回我们的视图。对于libs中的嵌入式UI非常有用。

生成的代码使用应添加到项目中的人员。为了得到它,我们需要获得nuget包Microsoft.Extensions.RazorViews.Sources。再次,它不在nuget.org上,所以我们需要从https://dotnet.myget.org/feed/aspnetcore-dev/package/nuget/Microsoft.Extensions.RazorViews.Sources安装它。