这是本文档旧的修订版!
08 自定义端点与插件扩展
为什么要扩展 Compute
默认 Compute 暴露了大量 RhinoCommon 相关端点,也支持 Grasshopper 求解。但有些业务更适合自定义端点:
- 需要把多个 RhinoCommon 调用封装成一个稳定业务 API。
- 需要隐藏复杂参数,给客户端提供简单接口。
- 需要复用公司内部 Rhino 插件算法。
- 需要减少客户端和服务端之间的大量往返。
- 需要把几何运算和业务约束放在服务端统一维护。
扩展方式
官方方式是在 Rhino 插件中注册 Compute 端点:
- 在插件项目中定义静态类。
- 在静态类中定义 public static 方法。
- 在插件
OnLoad中调用Rhino.Runtime.HostUtils.RegisterComputeEndPoint。 - 在本地 Rhino 和 Compute 服务器上安装该插件。
- 打开
/sdk检查新端点是否出现。
简化示例
using Rhino; using Rhino.Geometry; using Rhino.PlugIns; static class MyCustomComputeFunctions { public static double Add(double x, double y, double z) { return x + y + z; } public static double AdjustedArea(Curve curve, double factor) { var amp = AreaMassProperties.Compute(curve); return amp.Area * factor; } } public class MyPlugin : PlugIn { protected override LoadReturnCode OnLoad(ref string errorMessage) { Rhino.Runtime.HostUtils.RegisterComputeEndPoint( "Rhino.CustomEndPoint", typeof(MyCustomComputeFunctions) ); return base.OnLoad(ref errorMessage); } }
注册后,访问:
http://localhost:6500/sdk
如果插件加载成功,应能在 SDK 页面看到自定义函数。
方法设计原则
- 方法应是
public static,输入输出类型应能被 Compute 序列化。 - 不要依赖当前 Rhino 窗口、视口、鼠标选择、命令行交互。
- 不要在方法内部保存跨请求的可变全局状态。
- 输入参数要小而明确,复杂请求使用专门 DTO。
- 输出结果要可预测,错误要抛出清晰异常或返回结构化错误。
- 对大几何、大文件、外部 URL 要做大小和来源校验。
插件部署注意事项
服务器上的 Compute 子进程是无界面 Rhino 环境。插件能在普通 Rhino 中运行,不代表一定能在 Compute 中稳定运行。
需要检查:
- 插件是否安装到服务器 Rhino 可发现的位置。
- 插件是否支持当前 Rhino 版本。
- 插件是否依赖 UI、弹窗、命令行输入或用户选择。
- 插件是否有单独授权机制,服务器上是否已授权。
- 插件依赖的 DLL、配置文件、模板、数据文件是否存在。
- 插件首次加载是否需要人工确认。
调试流程
- 在普通 Rhino 中安装插件并确认可加载。
- 在普通 Rhino 中手动运行插件核心命令或测试方法。
- 启动本地 Compute。
- 访问
/sdk,确认自定义端点出现。 - 用最小请求调用端点。
- 再接入业务客户端或 Hops。
- 最后部署到 IIS 生产环境。
与 Grasshopper 的取舍
| 方案 | 优点 | 风险 |
|---|---|---|
| Grasshopper/Hops | 设计人员容易维护;可视化;快速迭代。 | 复杂定义可维护性下降;插件依赖多;序列化开销大。 |
| 自定义 Compute 端点 | API 稳定;性能可控;易测试;适合工程化。 | 需要 C# 插件开发能力;部署和版本管理更严格。 |
实践建议:
- 早期方案验证可以用 Hops。
- 稳定、高频、性能敏感的核心算法逐步下沉为自定义端点。
- 保留 Hops 给设计师迭代,把生产业务 API 交给自定义端点或外层服务。
测试建议
- 为插件核心算法写普通 .NET 单元测试。
- 为 Compute 端点写集成测试,真实启动 Compute 调用 HTTP。
- 测试空输入、非法几何、巨大几何、单位差异、异常路径。
- 每次 Rhino 或插件升级后,重新跑一遍端点集成测试。
本章检查点
- 自定义函数是否为可序列化的静态方法?
- 插件是否能在无界面 Compute 环境中加载?
/sdk是否能看到自定义端点?- 是否为端点准备了最小 HTTP 集成测试?