通过jint+ es6 模块设计一个插件化系统代码简单说明
属于原型代码,比较粗糙,属于示例部分代码比较简单
代码结构
代码基于了ioc ,整体比较简单,核心是说明下设计思路以及一些简单代码实现
- 代码结构
├── MyDbContext.cs
├── Program.cs
├── QueryService.cs
├── jint-apps.csproj
└── modules
└── loginplugin
└── userlogin.js
- 参考玩法

比如了EF,暴露dbcontext 一些能力为dao,方便业务使用,然后暴露一些能力服务到@scope/platform-common es 6 模块中,对于开发的js plugin 直接导入common module,实现业务开发,更加合理的做法是对于js plugin 应该定义一套标准接口,这样调用也就比较统一了
代码说明
代码比较简单,MyDbContext.cs 属于一个基于EF 定义的数据访问层,QueryService.cs 是业务包装,里边有暴露common 能力到jint 中以及一个简单的调用js plugin 的处理,属于简单演示,modules/loginplugin/userlogin.js 是简单插件代码,
- MyDbContext.c
sqlite dbcontext
using Microsoft.EntityFrameworkCore;
namespace JintApp;
public class MyDbContext: DbContext
{
public DbSet<User> Users => Set<User>();
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
}
public class User
{
public int Id { get; set; }
public string Name { get; set; } = "";
public override string ToString()
{
return $"Name is: {Name}, Id is:{Id}";
}
}
- QueryService.cs
using System.Diagnostics.CodeAnalysis;
using Jint;
using Jint.Native;
using Jint.Runtime.Modules;
namespace JintApp;
[RequiresUnreferencedCode("Calls Jint.Engine.SetValue<T>(String, T)")]
public class QueryService
{
private readonly MyDbContext _dbContext;
private readonly Engine _engine;
// 此处通过ioc 注入依赖
public QueryService(MyDbContext myDbContext, Engine engine)
{
_dbContext = myDbContext;
_engine = engine;
InitEngineQueryMethod();
}
private void InitEngineQueryMethod()
{
// 暴露一些常用方法,比如console 日志的
_engine.SetValue("console", new
{
log = (Action<object>)Console.WriteLine,
error = (Action<object>)(Console.Error.WriteLine),
});
// 演示暴露platform 核心能力服务,funcs 是一些公共方法函数,
var platform = new
{
funcs = new
{
queryDb = (Func<string, string>)((name) =>
{
var users = _dbContext.Users.Where(u => u.Name == name).Select(u => u.Name + u.Id);
string userinfos = string.Join(", ", users);
return userinfos;
}),
init = (Func<string?, string>)((name) =>
{
Console.WriteLine("jint init");
return "ok";
}),
add = (Func<double, double, double>)((a, b) => a + b)
}
};
// common es 6 模块暴露
_engine.Modules.Add("@scope/platform-common", builder => { builder.ExportObject("platform", platform); });
}
public void ExecuteQuery(string userName)
{
try
{
// 调度插件,当然此处基于了文件路径模式,也可以基于text code 模式
var ns = _engine.Modules.Import("./loginplugin/userlogin.js").Get("queryUser").AsObject();
var fn = ns.Get("qv2Async").AsFunctionInstance();
var result = fn.Call(userName).UnwrapIfPromise();
Console.WriteLine($"Query result: {result}");
}
catch (Exception ex)
{
Console.WriteLine($"Error executing query: {ex.Message}");
}
}
}
- userlogin.js
简单示意,就是一个标准的es6 模块,引用了通过native 暴露的common 方法
import {platform} from "@scope/platform-common"
export const queryUser = {
name: "dalong demo",
qv2: platform.funcs.queryDb,
add: platform.funcs.add,
init: platform.funcs.init,
qv2Async:platform.funcs.queryDb
}
- Program.cs
入口代码,记性ioc 服务的注册,以及简单业务访问
using Jint;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace JintApp;
public class Program
{
static void Main()
{
var services = new ServiceCollection();
services.AddDbContext<MyDbContext>(options =>
options.UseSqlite("Data Source=example.db"));
services.AddSingleton<Engine>(s =>
{
return new Engine(options =>
{
// 基于硬编码的路径,可以结合自己的场景修改,推荐基于代码控制
options.EnableModules("/Users/dalong/RiderProjects/serail-apps/jint-apps/modules");
});
});;
services.AddSingleton<QueryService>();
var serviceProvider = services.BuildServiceProvider();
var queryService = serviceProvider.GetRequiredService<QueryService>();
for (var i = 0; i<1; i++)
{
// 调用服务
queryService.ExecuteQuery("Alice");
}
}
}
说明
以上代码比较简单,核心是简单演示下基于js 引擎的插件处理,后续看情况完善下实现,形成一个完整的解决方案
参考资料
https://github.com/sebastienros/jint
浙公网安备 33010602011771号