RazorCore 1.0.0

dotnet add package RazorCore --version 1.0.0
                    
NuGet\Install-Package RazorCore -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RazorCore" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RazorCore" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RazorCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RazorCore --version 1.0.0
                    
#r "nuget: RazorCore, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RazorCore@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RazorCore&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RazorCore&version=1.0.0
                    
Install as a Cake Tool

RazorCore - 独立 Razor 模板引擎

版本: v1.0.0
状态: ✅ 生产就绪
命名空间: RazorCore
项目: RazorCore


📋 目录


概述

RazorCore 是一个独立的 Razor 模板引擎,专为非 ASP.NET 环境设计。它使用 Roslyn 动态编译技术,支持完整的 Razor 语法,包括 @model@functions@code 块等。

设计目标

  • 独立运行 - 无需 ASP.NET Core 环境
  • 完整语法 - 支持所有 Razor 语法特性
  • 匿名类型 - 支持匿名类型 Model(业界首创)
  • 高性能 - 模板缓存和编译优化
  • 易使用 - 简单的 API,最小化配置

核心特性

独立引擎 - 可在控制台、WinForms、WPF 等环境使用
匿名类型支持 - 通过 InternalsVisibleTo 实现(业界首创)
多种模板源 - 字符串、文件、嵌入资源、自定义 Provider
灵活编码 - HTML、Raw、自定义编码器
完整语法 - @model@functions@code、Partial Views
模板缓存 - 自动缓存编译结果


快速开始

安装

dotnet add package RazorCore

最简示例

using RazorCore;

var engine = new RazorEngine();
var template = "Hello, @Model.Name!";
var result = await engine.RenderStringAsync(template, new { Name = "World" });

Console.WriteLine(result);
// 输出: Hello, World!

完整示例

var engine = new RazorEngine();

var template = @"
@model User
<!DOCTYPE html>
<html>
<head>
    <title>User Profile</title>
</head>
<body>
    <h1>@Model.Name</h1>
    <p>Email: @Model.Email</p>
    <p>Member since: @Model.JoinDate.ToString(""yyyy-MM-dd"")</p>
    
    @if (Model.IsActive)
    {
        <span class=""badge"">Active</span>
    }
    
    <h2>Recent Orders</h2>
    <ul>
    @foreach (var order in Model.Orders)
    {
        <li>Order #@order.Id - @order.Total.ToString(""C"")</li>
    }
    </ul>
</body>
</html>";

var user = new User
{
    Name = "Alice",
    Email = "alice@example.com",
    JoinDate = DateTime.Now.AddYears(-1),
    IsActive = true,
    Orders = new List<Order>
    {
        new Order { Id = 1, Total = 99.99m },
        new Order { Id = 2, Total = 149.99m }
    }
};

var html = await engine.RenderStringAsync(template, user);

模板源

RazorCore 支持多种模板源。

1. 字符串模板(直接渲染)

var template = "Hello, @Model.Name!";
var result = await engine.RenderStringAsync(template, new { Name = "World" });

// 使用缓存键提高性能(避免重复编译)
var result = await engine.RenderStringAsync(template, new { Name = "World" }, cacheKey: "greeting");

2. 文件模板

using RazorCore.Providers;

var engine = new RazorEngine(
    templateProvider: new FileSystemTemplateProvider(@"C:\Templates"));

// 渲染 C:\Templates\Email.cshtml
var result = await engine.RenderAsync("Email", model);

// 支持子目录
var result = await engine.RenderAsync("Shared/_Header", model);

Email.cshtml:

@model EmailModel
<h1>@Model.Subject</h1>
<p>@Model.Body</p>

3. 嵌入资源模板

using RazorCore.Providers;
using System.Reflection;

var engine = new RazorEngine(
    templateProvider: new EmbeddedTemplateProvider(
        assembly: Assembly.GetExecutingAssembly(),
        @namespace: "MyApp.Templates"
    ));

// 渲染 MyApp.Templates.Welcome.cshtml(资源名称)
var result = await engine.RenderAsync("Welcome", model);

项目结构:

MyApp/
├── Templates/
│   └── Welcome.cshtml (EmbeddedResource)
└── Program.cs

4. 自定义 Provider

using RazorCore.Providers;

public class DatabaseTemplateProvider : ITemplateProvider
{
    private readonly DbContext _db;
    
    public DatabaseTemplateProvider(DbContext db)
    {
        _db = db;
    }
    
    public string GetTemplate(string name)
    {
        // 同步获取模板(ITemplateProvider 接口要求)
        var template = _db.Templates.FirstOrDefault(t => t.Name == name);
        return template?.Content;
    }
}

var engine = new RazorEngine(templateProvider: new DatabaseTemplateProvider(dbContext));

编码器

RazorCore 支持多种编码器。

1. HTML 编码器(默认)

自动转义 HTML 特殊字符,防止 XSS 攻击。

using RazorCore.Encoders;

var engine = new RazorEngine(templateProvider: null, encoder: HtmlEncoder.Default);
var template = "User input: @Model.Input";
var result = await engine.RenderStringAsync(template, new { Input = "<script>alert('XSS')</script>" });

// 输出: User input: &lt;script&gt;alert(&#39;XSS&#39;)&lt;/script&gt;

2. Raw 编码器

不进行任何编码,直接输出。

using RazorCore.Encoders;

var engine = new RazorEngine(templateProvider: null, encoder: RawEncoder.Default);
var template = "HTML: @Model.Html";
var result = await engine.RenderStringAsync(template, new { Html = "<b>Bold</b>" });

// 输出: HTML: <b>Bold</b>

注意: 使用 Raw 编码器时要确保数据来源可信,避免 XSS 风险。


3. SQL 编码器

防止 SQL 注入,转义单引号。

using RazorCore.Encoders;

var engine = new RazorEngine(templateProvider: null, encoder: SqlEncoder.Default);
var template = "INSERT INTO Users (Name) VALUES ('@Model.Name')";
var result = await engine.RenderStringAsync(template, new { Name = "O'Brien" });

// 输出: INSERT INTO Users (Name) VALUES ('O''Brien')

4. 自定义编码器

public class MarkdownEncoder : ITextEncoder
{
    public string Encode(string text)
    {
        // 将 Markdown 转换为 HTML
        return Markdown.ToHtml(text);
    }
}

var engine = new RazorEngine(encoder: new MarkdownEncoder());
var template = "@Model.Content";
var result = await engine.RenderAsync(template, new { Content = "# Hello\n\nWorld" });

// 输出: <h1>Hello</h1>\n<p>World</p>

高级特性

1. 匿名类型 Model(业界首创)

RazorCore 支持匿名类型作为 Model,这在其他 Razor 引擎中是不可能的。

原理: 使用 InternalsVisibleTo 特性,允许动态生成的程序集访问匿名类型。

var engine = new RazorEngine();
var template = @"
    Name: @Model.Name
    Age: @Model.Age
    City: @Model.City
";

var result = await engine.RenderStringAsync(template, new
{
    Name = "Alice",
    Age = 30,
    City = "Beijing"
});

// 输出:
// Name: Alice
// Age: 30
// City: Beijing

2. ViewData 支持

ViewData 在模板间共享数据,特别是在使用 Partial 时。

var template = @"
    @model User
    <h1>@Model.Name</h1>
    <p>Page Title: @ViewData[""Title""]</p>
";

var sharedViewData = new Dictionary<string, object>
{
    ["Title"] = "User Profile",
    ["CurrentYear"] = 2025
};

var result = await engine.RenderStringAsync(template, user, cacheKey: null, sharedViewData, encoder: null);

3. Partial Views

在模板中调用 PartialAsync 方法渲染其他模板:

using RazorCore.Providers;

// Main.cshtml
var mainTemplate = @"
    @model User
    <h1>@Model.Name</h1>
    @await PartialAsync(""_UserInfo"", Model)
";

// _UserInfo.cshtml
var partialTemplate = @"
    @model User
    <p>Email: @Model.Email</p>
    <p>Phone: @Model.Phone</p>
";

// 设置文件模板提供者
var provider = new FileSystemTemplateProvider(@"C:\Templates");
var engine = new RazorEngine(templateProvider: provider);

var result = await engine.RenderAsync("Main", user);

4. @functions 和 @code 块

var template = @"
    @model List<int>
    
    @functions {
        private string FormatNumber(int num)
        {
            return num.ToString(""N0"");
        }
    }
    
    <ul>
    @foreach (var item in Model)
    {
        <li>@FormatNumber(item)</li>
    }
    </ul>
";

var numbers = new List<int> { 1000, 2000, 3000 };
var result = await engine.RenderStringAsync(template, numbers);

// 输出:
// <ul>
//     <li>1,000</li>
//     <li>2,000</li>
//     <li>3,000</li>
// </ul>

5. Raw 内容输出

使用 Raw() 方法或 RawContent 输出未编码的 HTML:

var template = @"
    @model Article
    <h1>@Model.Title</h1>
    <div class=""content"">
        @Raw(Model.HtmlContent)
    </div>
";

var article = new Article
{
    Title = "My Article",
    HtmlContent = "<p>This is <strong>HTML</strong> content.</p>"
};

var result = await engine.RenderStringAsync(template, article);

注意Raw() 方法返回 RawContent 对象,不会被编码器处理。


6. 模板缓存和编译管理

RazorCore 自动缓存已编译的模板,提高性能。

var engine = new RazorEngine();

// 预编译模板(可选,提升首次渲染性能)
await engine.CompileAsync("UserProfile");

// 清除所有缓存
engine.ClearCache();

// 清除特定模板缓存
engine.RemoveFromCache("UserProfile");

// 获取编译后的模板类型(高级用法)
var templateType = await engine.GetCompiledTemplateAsync("UserProfile");

最佳实践

var engine = new RazorEngine();

// 第一次渲染:编译 + 缓存 var result1 = await engine.RenderAsync("Hello, @Model.Name!", new { Name = "Alice" });

// 第二次渲染:直接从缓存获取,无需重新编译 var result2 = await engine.RenderAsync("Hello, @Model.Name!", new { Name = "Bob" });


**缓存配置**:
```csharp
var engine = new RazorEngine(
    cacheOptions: new CacheOptions
    {
        MaxCachedTemplates = 1000,
        SlidingExpiration = TimeSpan.FromHours(1)
    }
);

使用示例

示例 1: 邮件模板

var engine = new RazorEngine(new FileTemplateProvider(@"C:\EmailTemplates"));

var template = @"
@model OrderConfirmation
<!DOCTYPE html>
<html>
<head>
    <title>Order Confirmation</title>
</head>
<body>
    <h1>Thank you for your order!</h1>
    
    <p>Hi @Model.CustomerName,</p>
    <p>Your order #@Model.OrderId has been confirmed.</p>
    
    <h2>Order Details</h2>
    <table>
        <tr>
            <th>Product</th>
            <th>Quantity</th>
            <th>Price</th>
        </tr>
        @foreach (var item in Model.Items)
        {
            <tr>
                <td>@item.ProductName</td>
                <td>@item.Quantity</td>
                <td>@item.Price.ToString(""C"")</td>
            </tr>
        }
    </table>
    
    <p><strong>Total: @Model.Total.ToString(""C"")</strong></p>
    
    <p>Estimated delivery: @Model.EstimatedDelivery.ToString(""MMMM dd, yyyy"")</p>
</body>
</html>";

var order = new OrderConfirmation
{
    OrderId = 12345,
    CustomerName = "Alice",
    Items = new List<OrderItem>
    {
        new OrderItem { ProductName = "Laptop", Quantity = 1, Price = 999.99m },
        new OrderItem { ProductName = "Mouse", Quantity = 2, Price = 19.99m }
    },
    Total = 1039.97m,
    EstimatedDelivery = DateTime.Now.AddDays(3)
};

var emailHtml = await engine.RenderAsync(template, order);
await emailService.SendAsync("alice@example.com", "Order Confirmation", emailHtml);

示例 2: 报表生成

var engine = new RazorEngine();

var template = @"
@model SalesReport
<!DOCTYPE html>
<html>
<head>
    <title>Sales Report - @Model.Period</title>
    <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; }
        th { background-color: #4CAF50; color: white; }
    </style>
</head>
<body>
    <h1>Sales Report</h1>
    <p>Period: @Model.Period</p>
    <p>Generated: @DateTime.Now.ToString(""yyyy-MM-dd HH:mm"")</p>
    
    <h2>Summary</h2>
    <ul>
        <li>Total Sales: @Model.TotalSales.ToString(""C"")</li>
        <li>Total Orders: @Model.TotalOrders</li>
        <li>Average Order Value: @Model.AverageOrderValue.ToString(""C"")</li>
    </ul>
    
    <h2>Top Products</h2>
    <table>
        <tr>
            <th>Product</th>
            <th>Quantity Sold</th>
            <th>Revenue</th>
        </tr>
        @foreach (var product in Model.TopProducts)
        {
            <tr>
                <td>@product.Name</td>
                <td>@product.QuantitySold</td>
                <td>@product.Revenue.ToString(""C"")</td>
            </tr>
        }
    </table>
</body>
</html>";

var report = new SalesReport
{
    Period = "2024 Q4",
    TotalSales = 1500000m,
    TotalOrders = 5420,
    AverageOrderValue = 276.75m,
    TopProducts = new List<ProductSales>
    {
        new ProductSales { Name = "Laptop", QuantitySold = 1250, Revenue = 1249375m },
        new ProductSales { Name = "Mouse", QuantitySold = 3200, Revenue = 63968m }
    }
};

var reportHtml = await engine.RenderAsync(template, report);
File.WriteAllText("SalesReport.html", reportHtml);

示例 3: 配置文件生成

var engine = new RazorEngine();

var template = @"
@model AppConfig
{
  ""ConnectionStrings"": {
    ""DefaultConnection"": ""@Model.DatabaseServer;Database=@Model.DatabaseName;User=@Model.DatabaseUser;Password=@Model.DatabasePassword""
  },
  ""Logging"": {
    ""LogLevel"": {
      ""Default"": ""@Model.LogLevel""
    }
  },
  ""AppSettings"": {
    ""ApiUrl"": ""@Model.ApiUrl"",
    ""MaxRetries"": @Model.MaxRetries,
    ""EnableCache"": @(Model.EnableCache ? ""true"" : ""false"")
  }
}";

var config = new AppConfig
{
    DatabaseServer = "Server=localhost",
    DatabaseName = "MyApp",
    DatabaseUser = "admin",
    DatabasePassword = "password123",
    LogLevel = "Information",
    ApiUrl = "https://api.example.com",
    MaxRetries = 3,
    EnableCache = true
};

var json = await engine.RenderAsync(template, config);
File.WriteAllText("appsettings.json", json);

最佳实践

1. 模板缓存

启用模板缓存以提高性能:

var engine = new RazorEngine(
    cacheOptions: new CacheOptions
    {
        MaxCachedTemplates = 1000,
        SlidingExpiration = TimeSpan.FromHours(1)
    }
);

2. 使用强类型 Model

优先使用强类型 Model,而非匿名类型(尽管支持):

// ✅ 推荐
public class UserModel
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// ⚠️ 仅用于简单场景
var model = new { Name = "Alice", Age = 30 };

3. 模板组织

将模板组织到文件中,而非硬编码字符串:

Templates/
├── _Layout.cshtml
├── Emails/
│   ├── Welcome.cshtml
│   └── OrderConfirmation.cshtml
└── Reports/
    ├── Sales.cshtml
    └── Inventory.cshtml

4. 错误处理

try
{
    var result = await engine.RenderAsync(template, model);
}
catch (TemplateCompilationException ex)
{
    // 模板编译错误
    Console.WriteLine($"Compilation errors: {string.Join("\n", ex.Errors)}");
}
catch (TemplateNotFoundException ex)
{
    // 模板未找到
    Console.WriteLine($"Template not found: {ex.TemplateName}");
}
catch (TemplateRenderException ex)
{
    // 渲染错误
    Console.WriteLine($"Render error: {ex.Message}");
}

相关文档


RazorCore - 独立而强大的 Razor 引擎 🚀

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 85 6/14/2026