Вопросы напрямую не относятся к урхошарпу, но хочу проконсультироваться у местных гуру сишарпа :)
1) Я хочу сделать приложение, которое использует в качестве скрипта исходник на сишарпе.
Иными словами есть само запускаемое приложение и набор скриптов в *.cs файлах.
Приложение берет эти файлы и налету компилирует их в dll-ку. Нужно предоставить этой dll-ке доступ к объектам самого приложения, а приложение должно уметь вызывать определенный набор функций из скрипта (короче как плагин, только который компилируется на лету из исходников). А также эту dll нужно выгружать из памяти в случае изменения скрипта, компилировать измененный скрипт и заново подключать dll'ку. Такое вообще возможно? Куда копать, чего читать.
2) Я хочу одновременно запускать несколько одинаковых экземпляров приложения и чтобы каждое приложение могло отправлять широковещательное сообщение всем другим в виде строки.
То есть один экземпляр приложение отправляет в эфир сообщение "Аларм", а все другие приложения получают эту строку и могут среагировать.
Я накопал такое https://msdn.microsoft.com/en-us/library/bb546102(v=vs.110).aspx
Это то что мне нужно? Однако там нужно создавать клиент и сервер. Но у меня все экземпляры приложения равноправны.
То есть мне в каждом экземпляре нужно создавать сервер на отправку и клиент для прослушивания широковещательных сообщений?
Или это по другому делается?
1) AppDomain позволяет загружать assembly. Выгружать можно прибив AppDomain и создав новый.
public event EventHandler<CompilerEventArgs> ErrorDataReceived; public event EventHandler<CompilerEventArgs> OutputDataReceived; public event EventHandler<CompilerEventArgs> InputDataReceived; public async Task<string> CompileScripts() { var Scripts = _codeFolder.FindScripts(); var solutionPath = _codeFolder.GetSolutionPath(); var folder = Path.Combine(solutionPath, "Core", "bin", "Release"); Directory.CreateDirectory(folder); var fileName = Path.Combine(folder, ProjectName + ".dll"); var assemblyInfoFolder = Path.Combine(solutionPath, "Core", "Properties"); Directory.CreateDirectory(assemblyInfoFolder); var assemblyInfoFile = Path.Combine(assemblyInfoFolder, "AssemblyInfo.cs"); SolutionGenerator.GenerateFileIfDoesntExist(assemblyInfoFile, new AssemblyInfo(_solutionGenerator)); var frameworkPath = RuntimeEnvironment.GetRuntimeDirectory(); var cscPath = Path.Combine(frameworkPath, "csc.exe"); var info = new ProcessStartInfo(cscPath); var references = //new string[] { "System.dll", "System.Core.dll", "System.Xml.dll", "System.Xml.Linq.dll", "Microsoft.CSharp.dll", "mscorlib.dll" }.Select(_=> // Path.Combine( // @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7", // _)).ToList(); Directory.GetFiles( @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7", "*.dll"); var urhoLib = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), @"Urho.dll"); info.Arguments = "/noconfig /unsafe+ /nowarn:1701,1702,2008 /nostdlib+ /errorreport:prompt /warn:4 /define:TRACE /errorendlocation /preferreduilang:en-US /nologo /target:library /optimize /utf8output /out:" + fileName + " /reference:\"" + urhoLib + "\" " + string.Join(" ", references.Select(_ => "/reference:\"" + _ + "\"")) + " " + string.Join(" ", Scripts.Select(_ => "\"" + _ + "\"")) + " " + assemblyInfoFile; info.WorkingDirectory = _codeFolder.ProjectFolder; info.UseShellExecute = false; info.CreateNoWindow = true; info.RedirectStandardOutput = true; info.RedirectStandardError = true; Debug.WriteLine(info.FileName + " " + info.Arguments); InputDataReceived?.Invoke(this, new CompilerEventArgs(info.FileName + " " + info.Arguments)); var p = Process.Start(info); p.BeginErrorReadLine(); p.BeginOutputReadLine(); var outputMessage = new StringBuilder(); var errorMessage = new List<string>(); p.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (e.Data != null) { ErrorDataReceived?.Invoke(this, new CompilerEventArgs(e.Data)); outputMessage.AppendLine(e.Data); } }; p.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (e.Data != null) { OutputDataReceived?.Invoke(this, new CompilerEventArgs(e.Data)); outputMessage.AppendLine(e.Data); if (e.Data.IndexOf(": error") > 0) errorMessage.Add(e.Data); } }; try { await p.WaitForExitAsync(); } catch (Exception ex) { throw new Exception("Can't compile", ex); } if (p.ExitCode != 0) { throw new CompilationExeption(outputMessage.ToString(), errorMessage); } return fileName; }
Файлы из C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7 лучше с собой таскать.
2) Если тебе нужно именно между процессами общаться то пайпы, WCF, shared memory и прочее. Можешь даже UDP пакет слать на LocalHost. Вариантов масса - всё зависит от целевых ОС и прочих особенностей.
Если тебе надо в рамках одного процесса общаться между AppDomain'ами то засовываешь в них прокси-объект унаследованный от MarshalByRefObject и дёргаешь его методы.
Я бы посоветовал тебе IronPython, имхо даже с нуля его легче применить, чем шарповским методом воротить комбайн
> Если тебе нужно именно между процессами общаться то пайпы, WCF, shared memory и прочее. Можешь даже UDP пакет слать на LocalHost. Вариантов масса - всё зависит от целевых ОС и прочих особенностей.
я сам выбрать не способен )) самое универсальное (в смысле на всех платформах будет работать) это наверное UDP слать, но открытие портов может потребовать всяких разрешений от юзера, так что его я бы не стал использовать
GLoom, ты вручную компилятор запускаешь, а есть класс CodeDomProvider для этого https://habrahabr.ru/post/110999/ :)
1vanK
Да, ты чертовски прав.
Естт еще отличная книжка "метапрограммирование на .net" (кажется так). Там рассматриваются варианты кодогенерации разные.
Кроме питона есть еще всякие Aluminium Lua и т.п. да и в самой урхе же была lua интеграция. Может ее задействовать?
ох подозреваю что велосипед какой-то пишешь :D
Межпроцессами да, пайпы. Если нужен бродкаст - может лучше написать отдельный процесс-сервак для остальных? :)
Либо может есть какой аналог ServiceBus для таких целей, но это пушкой по воробьям :)
Скриптинг на шарпе можно посмотреть на CSX (scripting api) вместо велосипедов с компиляции и аппдомейном. Напиши что ты вообще хочешь сделать? :)
> Напиши что ты вообще хочешь сделать? :)
MUD-клиент, если это это о чем-то говорит )
> Скриптинг на шарпе можно посмотреть на CSX (scripting api) вместо велосипедов с компиляции и аппдомейном.
чего это?
Чем больше копаюсь, тем меньше понимаю. Я хочу использовать отдельный домен для плагина, чтобы его можно было выгрузить. Но чтобы дернуть функцию из плагина мне нужно загрузить сборку и в главный домен и в созданный. А из главного домена выгрузить сборку нельзя. И в чём смысл?
Плагин должен загрузить общую DLL какую то с интерфейсами и т.п. А дальше через MarshalByRefObject надо инстанцировать объект так чтоб в одном домене он был настоящим а в другом через ссылку. Какой где сообразить не могу - приболел и плохо соображаю.
Ух как все запутано то...
Вот у меня есть приложение: в нем есть поле ввода и поле вывода.
И мне нужно загружать и выгружать какой-то скрипт. В скрипт я передаю то, что было введено в поле ввода. Скрипт это как-то обрабатывает в своем домене и вызывает разные функции уже в домене приложения (например вывод в поле вывода).
Как мне изплагина выполнять функции в главном домене? Я ведь не могу в плагине сделать CreateInstanceFromAndUnwrap, потому что в главном домене уже есть экземпляр.
Zamir
> https://habrahabr.ru/post/242209/
я весь день седня гуглю и уж первую ссылку в гугле я точно видел))
и она мне не помогает )
Тема в архиве.