Stavo solo cercando di fare la stessa cosa, tranne che volevo memorizzare i miei script come risorse incorporate. Sto creando una libreria che è una miscela di C# e IronPython e volevo distribuirla come una singola DLL. Ho scritto un PlatformAdaptationLayer che funziona, prima controlla le risorse per lo script che viene caricato, ma poi ricade sull'implementazione di base che appare nel filesystem. Tre parti di questo:
Parte 1, La PlatformAdaptationLayer personalizzato
namespace ZenCoding.Hosting
{
internal class ResourceAwarePlatformAdaptationLayer : PlatformAdaptationLayer
{
private readonly Dictionary<string, string> _resourceFiles = new Dictionary<string, string>();
private static readonly char Seperator = Path.DirectorySeparatorChar;
private const string ResourceScriptsPrefix = "ZenCoding.python.";
public ResourceAwarePlatformAdaptationLayer()
{
CreateResourceFileSystemEntries();
}
#region Private methods
private void CreateResourceFileSystemEntries()
{
foreach (string name in Assembly.GetExecutingAssembly().GetManifestResourceNames())
{
if (!name.EndsWith(".py"))
{
continue;
}
string filename = name.Substring(ResourceScriptsPrefix.Length);
filename = filename.Substring(0, filename.Length - 3); //Remove .py
filename = filename.Replace('.', Seperator);
_resourceFiles.Add(filename + ".py", name);
}
}
private Stream OpenResourceInputStream(string path)
{
string resourceName;
if (_resourceFiles.TryGetValue(RemoveCurrentDir(path), out resourceName))
{
return Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
}
return null;
}
private bool ResourceDirectoryExists(string path)
{
return _resourceFiles.Keys.Any(f => f.StartsWith(RemoveCurrentDir(path) + Seperator));
}
private bool ResourceFileExists(string path)
{
return _resourceFiles.ContainsKey(RemoveCurrentDir(path));
}
private static string RemoveCurrentDir(string path)
{
return path.Replace(Directory.GetCurrentDirectory() + Seperator, "").Replace("." + Seperator, "");
}
#endregion
#region Overrides from PlatformAdaptationLayer
public override bool FileExists(string path)
{
return ResourceFileExists(path) || base.FileExists(path);
}
public override string[] GetFileSystemEntries(string path, string searchPattern, bool includeFiles, bool includeDirectories)
{
string fullPath = Path.Combine(path, searchPattern);
if (ResourceFileExists(fullPath) || ResourceDirectoryExists(fullPath))
{
return new[] { fullPath };
}
if (!ResourceDirectoryExists(path))
{
return base.GetFileSystemEntries(path, searchPattern, includeFiles, includeDirectories);
}
return new string[0];
}
public override bool DirectoryExists(string path)
{
return ResourceDirectoryExists(path) || base.DirectoryExists(path);
}
public override Stream OpenInputFileStream(string path)
{
return OpenResourceInputStream(path) ?? base.OpenInputFileStream(path);
}
public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share)
{
return OpenResourceInputStream(path) ?? base.OpenInputFileStream(path, mode, access, share);
}
public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
{
return OpenResourceInputStream(path) ?? base.OpenInputFileStream(path, mode, access, share, bufferSize);
}
#endregion
}
}
Lei avrebbe bisogno di cambiare il ResourceScriptsPrefix costante qualunque sia il vostro spazio dei nomi di base è dove è stato memorizzato gli script Python.
parte 2, l'abitudine ScriptHost
namespace ZenCoding.Hosting
{
internal class ResourceAwareScriptHost : ScriptHost
{
private readonly PlatformAdaptationLayer _layer = new ResourceAwarePlatformAdaptationLayer();
public override PlatformAdaptationLayer PlatformAdaptationLayer
{
get { return _layer; }
}
}
}
Parte 3, infine, come ottenere un motore di Python utilizzando la tua roba personalizzato:
namespace ZenCoding.Hosting
{
internal static class ResourceAwareScriptEngineSetup
{
public static ScriptEngine CreateResourceAwareEngine()
{
var setup = Python.CreateRuntimeSetup(null);
setup.HostType = typeof(ResourceAwareScriptHost);
var runtime = new ScriptRuntime(setup);
return runtime.GetEngineByTypeName(typeof(PythonContext).AssemblyQualifiedName);
}
}
}
Sarebbe facile cambiare questo per caricare gli script da qualche altra posizione, come un database. Basta cambiare i metodi OpenResourceStream, ResourceFileExists e ResourceDirectoryExists.
Spero che questo aiuti.
Grazie! Ho esattamente lo stesso caso d'uso come il tuo –