RazorCore 1.0.0
dotnet add package RazorCore --version 1.0.0
NuGet\Install-Package RazorCore -Version 1.0.0
<PackageReference Include="RazorCore" Version="1.0.0" />
<PackageVersion Include="RazorCore" Version="1.0.0" />
<PackageReference Include="RazorCore" />
paket add RazorCore --version 1.0.0
#r "nuget: RazorCore, 1.0.0"
#:package RazorCore@1.0.0
#addin nuget:?package=RazorCore&version=1.0.0
#tool nuget:?package=RazorCore&version=1.0.0
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: <script>alert('XSS')</script>
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 | Versions 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. |
-
net10.0
- Microsoft.AspNetCore.Mvc.Razor.Extensions (>= 6.0.36)
- Microsoft.CodeAnalysis.CSharp (>= 4.14.0)
- Microsoft.CodeAnalysis.Razor (>= 6.0.36)
- Microsoft.Extensions.Caching.Abstractions (>= 9.0.9)
- Microsoft.Extensions.Caching.Memory (>= 9.0.9)
- Microsoft.Extensions.DependencyInjection (>= 9.0.9)
-
net8.0
- Microsoft.AspNetCore.Mvc.Razor.Extensions (>= 6.0.36)
- Microsoft.CodeAnalysis.CSharp (>= 4.14.0)
- Microsoft.CodeAnalysis.Razor (>= 6.0.36)
- Microsoft.Extensions.Caching.Abstractions (>= 9.0.9)
- Microsoft.Extensions.Caching.Memory (>= 9.0.9)
- Microsoft.Extensions.DependencyInjection (>= 9.0.9)
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 |