在.NET Core中在MVC之外使用Razor


71

我想将Razor用作我在.NET Core中编写的.NET控制台应用程序中的模板引擎。

我遇到的独立Razor引擎(RazorEngine,RazorTemplates)都需要完整的.NET。我正在寻找一种适用于.NET Core的解决方案。


2
github.com/aspnet/Razor只需要核心运行时(使用.NET标准库)
haim770 '16

Answers:


46

最近,我创建了一个名为RazorLight的库。

它没有多余的依赖性,例如ASP.NET MVC部件,可以在控制台应用程序中使用。目前,它仅支持.NET Core(NetStandard1.6)-但这正是您所需要的。

这是一个简短的示例:

IRazorLightEngine engine = EngineFactory.CreatePhysical("Path-to-your-views");

// Files and strong models
string resultFromFile = engine.Parse("Test.cshtml", new Model("SomeData")); 

// Strings and anonymous models
string stringResult = engine.ParseString("Hello @Model.Name", new { Name = "John" }); 

3
这很容易实现,但是性能却很差。我创建了一个循环,该循环生成了大约1000行html。每次花费大约12秒。仅创建一个包含200行的页面大约需要1-2秒。在MVC项目中,一页耗时约20毫秒。因此,如果您不担心性能,这是一个可行的选择。
DeadlyChambers

好吧,如果您使用ParseString-模板不会被缓存,这就是您遇到性能问题的原因。可以使用Parse代替适当的模板管理器(用于文件或嵌入式资源)-这样,模板将只编译一次,而下一次将从缓存中获取。而且您会看到与MVC项目中相同的数字
Toddams

8
更新:2.0版缓存从字符串构建的模板
Toddams

2
@Toddams这将无法在生产环境中使用,因为视图是在发布时预编译的。您能否添加支持生产(预编译视图)和开发环境的mvc项目示例。我无法使其在两种环境下都能一起工作:((
Freshblood

1
@Toddams我在同一条船上以浏览预编译的视图;当我们用来构建应用程序时,RazorLight根本无法工作dotnet publish
bchhun

38

这是一个示例代码,仅取决于Razor(用于解析和C#代码生成)和Roslyn(用于C#代码编译,但您也可以使用旧的CodeDom)。

这段代码中没有MVC,因此,没有View,没有.cshtml文件,没有Controller,只有Razor源代码解析和编译的运行时执行。尽管仍然存在模型的概念。

您只需要添加以下nuget软件包:(已Microsoft.AspNetCore.Razor.Language通过v3.1.7测试),Microsoft.AspNetCore.Razor.Runtime(已通过v2.2.0测试)和Microsoft.CodeAnalysis.CSharp(已通过v3.7.0测试)nuget。

此C#源代码与NETCore 3.1(对于较旧的版本,请查看此答案的历史记录),NETStandard 2和.NET Framework兼容。要对其进行测试,只需创建一个.NET框架或.NET核心控制台应用程序,将其粘贴,添加nuget并手动创建hello.txt文件即可。

using System;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Hosting;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace RazorTemplate
{
    class Program
    {
        static void Main(string[] args)
        {
            // points to the local path
            var fs = RazorProjectFileSystem.Create(".");

            // customize the default engine a little bit
            var engine = RazorProjectEngine.Create(RazorConfiguration.Default, fs, (builder) =>
            {
                // InheritsDirective.Register(builder); // in .NET core 3.1, compatibility has been broken (again), and this is not needed anymore...
                builder.SetNamespace("MyNamespace"); // define a namespace for the Template class
            });

            // get a razor-templated file. My "hello.txt" template file is defined like this:
            //
            // @inherits RazorTemplate.MyTemplate
            // Hello @Model.Name, welcome to Razor World!
            //

            var item = fs.GetItem("hello.txt", null);

            // parse and generate C# code
            var codeDocument = engine.Process(item);
            var cs = codeDocument.GetCSharpDocument();

            // outputs it on the console
            //Console.WriteLine(cs.GeneratedCode);

            // now, use roslyn, parse the C# code
            var tree = CSharpSyntaxTree.ParseText(cs.GeneratedCode);

            // define the dll
            const string dllName = "hello";
            var compilation = CSharpCompilation.Create(dllName, new[] { tree },
                new[]
                {
                    MetadataReference.CreateFromFile(typeof(object).Assembly.Location), // include corlib
                    MetadataReference.CreateFromFile(typeof(RazorCompiledItemAttribute).Assembly.Location), // include Microsoft.AspNetCore.Razor.Runtime
                    MetadataReference.CreateFromFile(Assembly.GetExecutingAssembly().Location), // this file (that contains the MyTemplate base class)

                    // for some reason on .NET core, I need to add this... this is not needed with .NET framework
                    MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "System.Runtime.dll")),

                    // as found out by @Isantipov, for some other reason on .NET Core for Mac and Linux, we need to add this... this is not needed with .NET framework
                    MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location), "netstandard.dll"))
                },
                new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); // we want a dll


            // compile the dll
            string path = Path.Combine(Path.GetFullPath("."), dllName + ".dll");
            var result = compilation.Emit(path);
            if (!result.Success)
            {
                Console.WriteLine(string.Join(Environment.NewLine, result.Diagnostics));
                return;
            }

            // load the built dll
            Console.WriteLine(path);
            var asm = Assembly.LoadFile(path);

            // the generated type is defined in our custom namespace, as we asked. "Template" is the type name that razor uses by default.
            var template = (MyTemplate)Activator.CreateInstance(asm.GetType("MyNamespace.Template"));

            // run the code.
            // should display "Hello Killroy, welcome to Razor World!"
            template.ExecuteAsync().Wait();
        }
    }

    // the model class. this is 100% specific to your context
    public class MyModel
    {
        // this will map to @Model.Name
        public string Name => "Killroy";
    }

    // the sample base template class. It's not mandatory but I think it's much easier.
    public abstract class MyTemplate
    {
        // this will map to @Model (property name)
        public MyModel Model => new MyModel();

        public void WriteLiteral(string literal)
        {
            // replace that by a text writer for example
            Console.Write(literal);
        }

        public void Write(object obj)
        {
            // replace that by a text writer for example
            Console.Write(obj);
        }

        public async virtual Task ExecuteAsync()
        {
            await Task.Yield(); // whatever, we just need something that compiles...
        }
    }
}

2
做得好,谢谢!为了使其在Mac和Linux上的netcore2应用程序中运行的netstandard 2.0类库中正常工作,我不得不添加对netstandard dll的附加引用:MetadataReference.CreateFromFile(Path.Combine(Path.GetDirectoryName(typeof(object).Assembly.Location),"netstandard.dll")),
Isantipov

2
@Isantipov-好的,谢谢指出,我没有在Windows以外的其他平台上对此进行测试。我已经更新了答案。
西蒙·穆里尔

剃刀引擎会自动找到“ _ViewImports.cshtml”文件,还是我自己必须按照这种方法查找布局,查看导入等文件?另外,视图中的“ ViewContext”和其他相关属性又如何-剃刀引擎如何知道如何设置这些属性?还是它们为空?
詹姆斯·威尔金斯

2
好吧,如果我记得,实际的RazorViewEngine是在MVC中的,所以我想这使Razor不过是我猜想的解析器和编译器。;)
詹姆斯·威尔金斯

1
@Dave-我已经更新了答案。现在应该可以使用最新版本。
西蒙·穆里尔

21

对于2020年或之后的所有人:我已经开始https://github.com/adoconnection/RazorEngineCore

它具有最新的ASP.NET Core 3.1.1 Razor及其语法功能。

用法与RazorEngine完全相同:

RazorEngine razorEngine = new RazorEngine();
RazorEngineCompiledTemplate template = razorEngine.Compile("Hello @Model.Name");

string result = template.Run(new
{
    Name = "Alex"
});

Console.WriteLine(result);

快速保存和加载

// save to file
template.SaveToFile("myTemplate.dll");

//save to stream
MemoryStream memoryStream = new MemoryStream();
template.SaveToStream(memoryStream);
var template1 = RazorEngineCompiledTemplate.LoadFromFile("myTemplate.dll");
var template2 = RazorEngineCompiledTemplate.LoadFromStream(myStream);

1
当.NET Framework调用它时,这似乎不起作用(可能是因为.net核心与框架之间的剃须刀渲染器根本不同?)。有 System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.CSharp' or one of its dependencies. The system cannot find the file specified.此工作了.NET框架的任何机会呢?
thalacker

3
它从未打算在NET Framework中工作,有一个众所周知的github.com/Antaris/RazorEngine软件包
ADOConnection

PreserveCompilationContext在项目设置中是否也需要?如果可能的话,我宁愿避免这种情况。
Tyrrrz

@Tyrrrz不,它不是必需的
ADOConnection

1
@thalacker v2020.9.1获得了NET 4.7.2支持
ADOConnection

18

.aspnet / Entropy / samples / Mvc.RenderViewToString中有一个.NET Core 1.0的工作示例。由于这可能会改变或消失,因此我将在这里详细说明我在自己的应用程序中使用的方法。

Tl; dr -Razor在MVC之外效果很好!尽管我将在下面演示一个简单的示例,但是该方法可以处理更复杂的渲染方案,例如局部视图,以及将对象注入视图。


核心服务如下所示:

RazorViewToStringRenderer.cs

using System;
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;

namespace RenderRazorToString
{
    public class RazorViewToStringRenderer
    {
        private readonly IRazorViewEngine _viewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public RazorViewToStringRenderer(
            IRazorViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _viewEngine = viewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public async Task<string> RenderViewToString<TModel>(string name, TModel model)
        {
            var actionContext = GetActionContext();

            var viewEngineResult = _viewEngine.FindView(actionContext, name, false);

            if (!viewEngineResult.Success)
            {
                throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", name));
            }

            var view = viewEngineResult.View;

            using (var output = new StringWriter())
            {
                var viewContext = new ViewContext(
                    actionContext,
                    view,
                    new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
                    {
                        Model = model
                    },
                    new TempDataDictionary(
                        actionContext.HttpContext,
                        _tempDataProvider),
                    output,
                    new HtmlHelperOptions());

                await view.RenderAsync(viewContext);

                return output.ToString();
            }
        }

        private ActionContext GetActionContext()
        {
            var httpContext = new DefaultHttpContext
            {
                RequestServices = _serviceProvider
            };

            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
        }
    }
}

一个简单的测试控制台应用程序只需初始化服务(和一些支持服务),然后调用它:

Program.cs

using System;
using System.Diagnostics;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.PlatformAbstractions;

namespace RenderRazorToString
{
    public class Program
    {
        public static void Main()
        {
            // Initialize the necessary services
            var services = new ServiceCollection();
            ConfigureDefaultServices(services);
            var provider = services.BuildServiceProvider();

            var renderer = provider.GetRequiredService<RazorViewToStringRenderer>();

            // Build a model and render a view
            var model = new EmailViewModel
            {
                UserName = "User",
                SenderName = "Sender"
            };
            var emailContent = renderer.RenderViewToString("EmailTemplate", model).GetAwaiter().GetResult();

            Console.WriteLine(emailContent);
            Console.ReadLine();
        }

        private static void ConfigureDefaultServices(IServiceCollection services)
        {
            var applicationEnvironment = PlatformServices.Default.Application;
            services.AddSingleton(applicationEnvironment);

            var appDirectory = Directory.GetCurrentDirectory();

            var environment = new HostingEnvironment
            {
                WebRootFileProvider = new PhysicalFileProvider(appDirectory),
                ApplicationName = "RenderRazorToString"
            };
            services.AddSingleton<IHostingEnvironment>(environment);

            services.Configure<RazorViewEngineOptions>(options =>
            {
                options.FileProviders.Clear();
                options.FileProviders.Add(new PhysicalFileProvider(appDirectory));
            });

            services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();

            var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
            services.AddSingleton<DiagnosticSource>(diagnosticSource);

            services.AddLogging();
            services.AddMvc();
            services.AddSingleton<RazorViewToStringRenderer>();
        }
    }
}

假设您有一个视图模型类:

EmailViewModel.cs

namespace RenderRazorToString
{
    public class EmailViewModel
    {
        public string UserName { get; set; }

        public string SenderName { get; set; }
    }
}

以及布局和查看文件:

视图/_Layout.cshtml

<!DOCTYPE html>

<html>
<body>
    <div>
        @RenderBody()
    </div>
    <footer>
Thanks,<br />
@Model.SenderName
    </footer>
</body>
</html>

视图/EmailTemplate.cshtml

@model RenderRazorToString.EmailViewModel
@{ 
    Layout = "_EmailLayout";
}

Hello @Model.UserName,

<p>
    This is a generic email about something.<br />
    <br />
</p>

2
@dustinmoris如果我没记错的话,它确实为您做了一些缓存。我已经有一段时间没有尝试过了。
Nate Barbettini

2
太棒了!但是,这在.net core 2.0中不起作用:(似乎无法加载依赖项: The type 'Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'-我不确定如何告诉razor加载它需要的所有依赖项-有什么想法吗?
Matt Roberts

1
该代码似乎在我们的项目中泄漏内存,但是我不确定确切的罪魁祸首是什么。
道格

2
对于任何收到The type 'Attribute' is defined in an assembly that is not referenced错误的人,添加即可<PreserveCompilationContext>true</PreserveCompilationContext>解决问题。
马克G

3
请注意,要与ASP.NET Core 3一起使用,您需要向IWebHostEnvironmentDI容器中添加一个实例,并使用MvcRazorRuntimeCompilationOptions该类提供文件提供程序而不是RazorViewEngineOptions该类。RazorViewToStringRenderer此处提供了一个详细的实例化示例:corstianboerman.com/2019-12-25/…
Corstian Boerman,

8

这是一个使Nate的答案在ASP.NET Core 2.0项目中用作范围服务的类。

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.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;

namespace YourNamespace.Services
{
    public class ViewRender : IViewRender
    {
        private readonly IRazorViewEngine _viewEngine;
        private readonly ITempDataProvider _tempDataProvider;
        private readonly IServiceProvider _serviceProvider;

        public ViewRender(
            IRazorViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _viewEngine = viewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public async Task<string> RenderAsync(string name)
        {
            return await RenderAsync<object>(name, null);
        }

        public async Task<string> RenderAsync<TModel>(string name, TModel model)
        {
            var actionContext = GetActionContext();

            var viewEngineResult = _viewEngine.FindView(actionContext, name, false);

            if (!viewEngineResult.Success)
            {
                throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", name));
            }

            var view = viewEngineResult.View;

            using (var output = new StringWriter())
            {
                var viewContext = new ViewContext(
                    actionContext,
                    view,
                    new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
                    {
                        Model = model
                    },
                    new TempDataDictionary(
                        actionContext.HttpContext,
                        _tempDataProvider),
                    output,
                    new HtmlHelperOptions());

                await view.RenderAsync(viewContext);

                return output.ToString();
            }
        }

        private ActionContext GetActionContext()
        {
            var httpContext = new DefaultHttpContext {RequestServices = _serviceProvider};
            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
        }
    }

    public interface IViewRender
    {
        Task<string> RenderAsync(string name);

        Task<string> RenderAsync<TModel>(string name, TModel model);
    }
}

在Startup.cs中

public void ConfigureServices(IServiceCollection services)
{
     services.AddScoped<IViewRender, ViewRender>();
}

在控制器中

public class VenuesController : Controller
{
    private readonly IViewRender _viewRender;

    public VenuesController(IViewRender viewRender)
    {
        _viewRender = viewRender;
    }

    public async Task<IActionResult> Edit()
    {
        string html = await _viewRender.RenderAsync("Emails/VenuePublished", venue.Name);
        return Ok();
    }
}

我无法使它正常工作。我收到错误消息:尝试激活“ Mvc.RenderViewToString.RazorViewToStringRenderer”时,无法解析类型为“ Microsoft.AspNetCore.Mvc.Razor.IRazorViewEngine”的服务。
肯森

1
这是一个非常简单的好答案,并且在很大程度上也很棒,因为它可以在Linux支持的Docker映像中使用。由于某些特定于Linux的问题,许多其他解决方案也不起作用。谢谢!这应该是ASPNET CORE 2+的答案
Piotr Kula

这是否完全使用缓存?
jjxtra

0

我花了几天时间剃光剃须刀,但是它有很多缺陷,例如没有html helper(@ Html。*)或url helper,以及其他一些怪癖。

这是一个封装在mvc应用程序外部使用的解决方案。它确实需要对aspnet core和mvc的程序包引用,但是它们很容易添加到服务或控制台应用程序中。无需控制器或Web服务器。RenderToStringAsync是用于将视图呈现为字符串的调用方法。

优点是您可以像在.net核心Web项目中一样编写视图。您可以使用相同的@Html和其他辅助函数和方法。

您可以使用自己的自定义提供程序在razor视图选项设置中替换或添加到物理文件提供程序,以从数据库,Web服务调用等加载视图。在Windows和Linux上使用.net core 2.2测试。

请注意,您的.csproj文件必须将其作为第一行:

<Project Sdk="Microsoft.NET.Sdk.Web">
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Internal;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ObjectPool;

namespace RazorRendererNamespace
{
    /// <summary>
    /// Renders razor pages with the absolute minimum setup of MVC, easy to use in console application, does not require any other classes or setup.
    /// </summary>
    public class RazorRenderer : ILoggerFactory, ILogger
    {
        private class ViewRenderService : IDisposable, ITempDataProvider, IServiceProvider
        {
            private static readonly System.Net.IPAddress localIPAddress = System.Net.IPAddress.Parse("127.0.0.1");

            private readonly Dictionary<string, object> tempData = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            private readonly IRazorViewEngine _viewEngine;
            private readonly ITempDataProvider _tempDataProvider;
            private readonly IServiceProvider _serviceProvider;
            private readonly IHttpContextAccessor _httpContextAccessor;

            public ViewRenderService(IRazorViewEngine viewEngine,
                IHttpContextAccessor httpContextAccessor,
                ITempDataProvider tempDataProvider,
                IServiceProvider serviceProvider)
            {
                _viewEngine = viewEngine;
                _httpContextAccessor = httpContextAccessor;
                _tempDataProvider = tempDataProvider ?? this;
                _serviceProvider = serviceProvider ?? this;
            }

            public void Dispose()
            {

            }

            public async Task<string> RenderToStringAsync<TModel>(string viewName, TModel model, ExpandoObject viewBag = null, bool isMainPage = false)
            {
                HttpContext httpContext;
                if (_httpContextAccessor?.HttpContext != null)
                {
                    httpContext = _httpContextAccessor.HttpContext;
                }
                else
                {
                    DefaultHttpContext defaultContext = new DefaultHttpContext { RequestServices = _serviceProvider };
                    defaultContext.Connection.RemoteIpAddress = localIPAddress;
                    httpContext = defaultContext;
                }
                var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
                using (var sw = new StringWriter())
                {
                    var viewResult = _viewEngine.FindView(actionContext, viewName, isMainPage);

                    if (viewResult.View == null)
                    {
                        viewResult = _viewEngine.GetView("~/", viewName, isMainPage);
                    }

                    if (viewResult.View == null)
                    {
                        return null;
                    }

                    var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                    {
                        Model = model
                    };
                    if (viewBag != null)
                    {
                        foreach (KeyValuePair<string, object> kv in (viewBag as IDictionary<string, object>))
                        {
                            viewDictionary.Add(kv.Key, kv.Value);
                        }
                    }
                    var viewContext = new ViewContext(
                        actionContext,
                        viewResult.View,
                        viewDictionary,
                        new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                        sw,
                        new HtmlHelperOptions()
                    );

                    await viewResult.View.RenderAsync(viewContext);
                    return sw.ToString();
                }
            }

            object IServiceProvider.GetService(Type serviceType)
            {
                return null;
            }

            IDictionary<string, object> ITempDataProvider.LoadTempData(HttpContext context)
            {
                return tempData;
            }

            void ITempDataProvider.SaveTempData(HttpContext context, IDictionary<string, object> values)
            {
            }
        }

        private readonly string rootPath;
        private readonly ServiceCollection services;
        private readonly ServiceProvider serviceProvider;
        private readonly ViewRenderService viewRenderer;

        public RazorRenderer(string rootPath)
        {
            this.rootPath = rootPath;
            services = new ServiceCollection();
            ConfigureDefaultServices(services);
            serviceProvider = services.BuildServiceProvider();
            viewRenderer = new ViewRenderService(serviceProvider.GetRequiredService<IRazorViewEngine>(), null, null, serviceProvider);
        }

        private void ConfigureDefaultServices(IServiceCollection services)
        {
            var environment = new HostingEnvironment
            {
                WebRootFileProvider = new PhysicalFileProvider(rootPath),
                ApplicationName = typeof(RazorRenderer).Assembly.GetName().Name,
                ContentRootPath = rootPath,
                WebRootPath = rootPath,
                EnvironmentName = "DEVELOPMENT",
                ContentRootFileProvider = new PhysicalFileProvider(rootPath)
            };
            services.AddSingleton<IHostingEnvironment>(environment);
            services.Configure<RazorViewEngineOptions>(options =>
            {
                options.FileProviders.Clear();
                options.FileProviders.Add(new PhysicalFileProvider(rootPath));
            });
            services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
            services.AddSingleton<ILoggerFactory>(this);
            var diagnosticSource = new DiagnosticListener(environment.ApplicationName);
            services.AddSingleton<DiagnosticSource>(diagnosticSource);
            services.AddMvc();
        }

        public void Dispose()
        {
        }

        public Task<string> RenderToStringAsync<TModel>(string viewName, TModel model, ExpandoObject viewBag = null, bool isMainPage = false)
        {
            return viewRenderer.RenderToStringAsync(viewName, model, viewBag, isMainPage);
        }

        void ILoggerFactory.AddProvider(ILoggerProvider provider)
        {

        }

        IDisposable ILogger.BeginScope<TState>(TState state)
        {
            throw new NotImplementedException();
        }

        ILogger ILoggerFactory.CreateLogger(string categoryName)
        {
            return this;
        }

        bool ILogger.IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel)
        {
            return false;
        }

        void ILogger.Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
        }
    }
}

使用Microsoft.NET.Sdk.Web表示该项目需要ASP.NET Core运行时才能运行。对于控制台/桌面应用程序,这可能非常繁琐且不必要。
Tyrrrz '20年

以我的经验,肿胀很小。从.net core 3.1开始的一个自包含.exe,具有整个asp.net core运行时并启用了修剪功能,约为80mb。如果您正在创建安装程序,这些文件将压缩到30mb左右并解压缩出来。如果您有微服务,那不是问题。对于独立的控制台应用程序,我建议切换到.net 5自包含的exe,否则您将拥有很多额外的dll文件和文件夹。
jjxtra
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.