Встроенные ресурсы
Использование встроенных ресурсов
Что это такое и зачем это нужно
Embedded Resources — это механизм в скриптах, который позволяет «нести с собой» любые файлы прямо рядом со скриптом: изображения, видео, ML-модели, исполняемые файлы и даже DLL.
Изображения можно использовать в вашем кастомном UI, видео — для обучающих материалов, а DLL — для дополнительного кода, который по каким-то причинам неудобно поставлять как пакет NuGet.
NuGet
Обратите внимание: если библиотека уже есть на NuGet, гораздо надежнее подключать её через #r "nuget:" и ссылаться на пакет, а не на «сырую» DLL.
Как добавить
Щелкните правой кнопкой мыши по дереву файлов скрипта (его показывает кнопка Show Files) → Add Existing File...

Либо воспользуйтесь кнопкой New.
После добавления файл появится в списке, и его можно будет выбрать.

Как удалить
Чтобы удалить ресурс, просто удалите файл из списка.
Как использовать
Когда скрипт запускается, выбранные вами файлы загружаются автоматически, и скрипт может их использовать.
Через IScriptFileProvider
Этот способ позволяет прочитать содержимое файла как текст или как массив байтов. Что делать с этими байтами дальше — решаете вы.
var fontData = GetService<IScriptFileProvider>().ReadAllBytes("Roboto-Regular.ttf");
Через Blazor
Если вы строите UI через Blazor, файлы можно использовать напрямую. Например, если вы добавили в скрипт Image 12.jpg, то для отображения достаточно написать:
<img src="Image 12.jpg" />
Точно так же можно показывать видео, загружать текст, стили и всё остальное.
Как подключаемую DLL
По аналогии с пакетами NuGet, вы можете положить нужную DLL прямо в скрипт и при этом сохранить автодополнение, определение типов и прочие удобства.
Для этого нужно:
- добавить в скрипт нужную .NET-сборку, например
MyDll.dll - в
Script.csxнаписать
#r "assemblyPath: MyDll.dll"
Готово. При компиляции скрипта EyeAuras найдет подходящую DLL среди ресурсов проекта и использует её. А при запуске скрипта загрузит её из ресурсов. Никаких отдельных файлов рядом держать не нужно.
Экспорт/импорт C# Solution
EyeAuras умеет экспортировать скрипт как полноценный C# .sln, который потом можно открыть в JetBrains Rider или Visual Studio.
Embedded resources (файлы) тоже экспортируются и помечаются как Embedded Resource.
Например, для Image 12.jpg произойдет следующее: во-первых, сам файл будет экспортирован в целевую папку, а во-вторых, в экспортированном файле проекта появится:
<ItemGroup>
<EmbeddedResource Include="Image 12.jpg" />
<None Remove="Image 12.jpg" />
</ItemGroup>
Это говорит C#-компилятору включить Image 12.jpg как embedded resource внутрь итоговой DLL.
При обратном импорте .sln в EyeAuras читаются элементы Embedded Resource, и вы увидите их как файлы в списке.
В Visual Studio/Rider это соответствует Build Action = EmbeddedResource. Если вы открыли экспортированный проект, можно:
- добавлять и удалять файлы прямо в папке проекта
- в
.csprojуказывать<EmbeddedResource Include="..."/>для каждого ресурса - при необходимости добавлять
<None Remove="..."/>, чтобы файл не копировался в выходную папку как обычный контент
При импорте обратно EyeAuras просканирует .csproj, найдет все EmbeddedResource-элементы и покажет их в списке файлов скрипта. Имена и относительные пути сохраняются — это важно для корректного доступа из кода и Blazor.

Как это устроено внутри
При сборке скриптов EyeAuras старается максимально следовать логике официального компилятора: добавленные вами файлы включаются в итоговую DLL как Embedded Resources и доступны через Assembly.GetManifestResourceNames и Assembly.GetManifestResourceStream.
Кратко о .NET-методах:
Assembly.GetManifestResourceNames()— возвращает полный список имен ресурсов, например"DefaultNamespace.folder.file.ext"Assembly.GetManifestResourceStream(fullName)— открывает поток для чтения ресурса по его ПОЛНОМУ имени
Пример «в лоб» (обычно это не нужно — удобнее использовать IScriptFileProvider):
var asm = typeof(Script).Assembly; // your script’s assembly
foreach (var name in asm.GetManifestResourceNames())
{
Log.Info($"Resource: {name}");
}
using var stream = asm.GetManifestResourceStream("MyScript.Images.logo.png");
using var ms = new MemoryStream();
stream.CopyTo(ms);
var bytes = ms.ToArray();
В EyeAuras удобнее использовать IScriptFileProvider, потому что он сам сопоставляет пути и находит нужный ресурс.
Именование
У C# Embedded Resources есть одна особенность: когда ресурсы попадают в DLL, их относительный путь «сворачивается» и превращается в namespace.folder.filename.
Как формируется полное имя ресурса во время сборки:
- берется
DefaultNamespaceпроекта (если он не задан — имя проекта) - слеши в относительном пути файла заменяются на точки
- результат:
FullName = DefaultNamespace + "." + relative/path/with/dots
Пример: проект с namespaceMyScriptи файлImages/logo.png→ ресурс:MyScript.Images.logo.png
Как искать ресурс в EyeAuras:
- можно указать короткий путь:
"logo.png"— провайдер заменит слеши на точки и будет искать по суффиксу без учета регистра - можно указать подпапку:
"Images/logo.png"или"Images.logo.png"— это надежнее - можно указать ПОЛНОЕ имя:
"MyScript.Images.logo.png"— точное совпадение с учетом регистра - разделители
'/','\\'и'.'в запросе взаимозаменяемы
Важно про совпадения и регистр:
- полное имя сравнивается строго и с учетом регистра
- короткие и частичные пути ищутся через
EndsWith, без учета регистра - если в проекте есть два файла с одинаковым окончанием пути (например,
a/logo.pngиb/logo.png), короткий запрос"logo.png"вернет первое совпадение. Чтобы избежать путаницы, указывайте подпапку или полное имя.
Примеры запросов, которые сработают для Images/logo.png:
"logo.png""Images/logo.png""Images.logo.png""MyScript.Images.logo.png"
EyeAuras старается упростить жизнь пользователю и поддерживает как полные имена (с точками), так и относительные (без namespace). Можно также использовать привычные пути вроде folder/Image 12.jpg вместо folder.Image 12.jpg.
Практические примеры (ELI5)
- Прочитать JSON-конфиг как текст:
var files = GetService<IScriptFileProvider>();
var json = files.ReadAllText("config.json");
var cfg = JsonConvert.DeserializeObject<MyConfig>(json);
- Загрузить ONNX/ML-модель как байты:
var files = GetService<IScriptFileProvider>();
var model = files.ReadAllBytes("models/my_model.onnx");
// pass the bytes into your ML library
- Открыть поток (для больших файлов):
var files = GetService<IScriptFileProvider>();
var file = files.GetFileInfo("video/tutorial.mp4");
using var stream = file.CreateReadStream();
// read in chunks without holding everything in memory
- Показать изображение в Blazor:
<img src="Images/logo.png" />
Загрузка DLL из ресурсов — как это работает
-
На этапе компиляции
- В
Script.csxдобавьте директиву:#r "assemblyPath: MyLib.dll" - EyeAuras найдет файл
MyLib.dllв ресурсах и добавит его как ссылку. Это даст автодополнение, определение типов и успешную компиляцию.
- В
-
Во время выполнения
- EyeAuras подписывается на
AssemblyLoadContext.Resolvingи пытается загрузить сборку из embedded resources.
- EyeAuras подписывается на
Полезный пример:
#r "assemblyPath: Newtonsoft.Json.dll"
using Newtonsoft.Json;
Log.Info(JsonConvert.SerializeObject(new { Hello = "World" }));
Как вывести список всех доступных имен
- Через .NET API (полные имена):
var asm = typeof(Script).Assembly;
foreach (var name in asm.GetManifestResourceNames())
{
Log.Info($"Resource: {name}");
}
- Через file provider (
IFileProvider):
var files = GetService<IScriptFileProvider>();
foreach (var fi in files.GetDirectoryContents("/"))
{
Log.Info($"Found: {fi.Name} ({fi.Length} b)");
}
- Если вам нужен именно список manifest names, а сервисом является
ScriptEmbeddedResourceFileProvider:
var files = GetService<IScriptFileProvider>() as ScriptEmbeddedResourceFileProvider;
var names = files?.GetManifestNames() ?? Array.Empty<string>();
Log.Info(string.Join("\n", names));
FAQ и нюансы
-
Файл не находится
- Убедитесь, что он добавлен в список файлов скрипта
- Попробуйте указать подпапку: вместо
"logo.png"→"Images/logo.png" - Проверьте регистр, если используете полное имя
-
Дубликаты имен
- Если есть два файла с одинаковым окончанием пути (
a/logo.pngиb/logo.png), короткий запрос"logo.png"может указать не на тот файл. Уточняйте путь через подпапку.
- Если есть два файла с одинаковым окончанием пути (
-
Большие файлы
- Читайте их как поток через
CreateReadStream()— не держите всё целиком в памяти
- Читайте их как поток через
-
Я изменил файл, но не вижу обновлений
- Embedded resources вшиваются в DLL. Перезапустите или пересоберите скрипт, чтобы новые байты попали в сборку.
-
DLL не загружается
- Проверьте, что
#r "assemblyPath: ..."указывает на правильный файл.
- Проверьте, что
-
Точки или слеши в путях?
- Работают оба варианта:
"Images/logo.png","Images.logo.png"— провайдер нормализует путь в точки и ищет по суффиксу.
- Работают оба варианта: