{"id":18009842,"url":"https://github.com/kekyo/marionetta","last_synced_at":"2025-08-17T16:31:36.517Z","repository":{"id":50306880,"uuid":"516577190","full_name":"kekyo/Marionetta","owner":"kekyo","description":"Outprocess sandboxed controller.","archived":false,"fork":false,"pushed_at":"2022-08-04T05:10:48.000Z","size":185,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-02T13:48:27.157Z","etag":null,"topics":["component","dotnet","ipc","isolation","outprocess","sandbox","split"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kekyo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-22T01:58:33.000Z","updated_at":"2024-09-15T08:17:16.000Z","dependencies_parsed_at":"2022-08-23T03:01:01.981Z","dependency_job_id":null,"html_url":"https://github.com/kekyo/Marionetta","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FMarionetta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FMarionetta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FMarionetta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FMarionetta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kekyo","download_url":"https://codeload.github.com/kekyo/Marionetta/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230143636,"owners_count":18180024,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component","dotnet","ipc","isolation","outprocess","sandbox","split"],"created_at":"2024-10-30T02:11:14.618Z","updated_at":"2024-12-17T16:11:47.179Z","avatar_url":"https://github.com/kekyo.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Marionetta\n\n![Marionetta](Images/Marionetta.100.png)\n\nMarionetta - Split dirty older architecthre based component depending with sandboxed outprocess and made manipulation easy.\n\n[![Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostatus.org/#wip)\n\n## NuGet\n\n| Package  | NuGet                                                                                                                |\n|:---------|:---------------------------------------------------------------------------------------------------------------------|\n| Marionetta | [![NuGet Marionetta](https://img.shields.io/nuget/v/Marionetta.svg?style=flat)](https://www.nuget.org/packages/Marionetta) |\n\n## CI\n\n| main                                                                                                                                                                 | develop                                                                                                                                                                       |\n|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| [![Marionetta CI build (main)](https://github.com/kekyo/Marionetta/workflows/.NET/badge.svg?branch=main)](https://github.com/kekyo/Marionetta/actions?query=branch%3Amain) | [![Marionetta CI build (develop)](https://github.com/kekyo/Marionetta/workflows/.NET/badge.svg?branch=develop)](https://github.com/kekyo/Marionetta/actions?query=branch%3Adevelop) |\n\n----\n\n[![Japanese language](Images/Japanese.256.png)](https://github.com/kekyo/Marionetta/blob/main/README_ja.md)\n\n## What is this?\n\nMarionetta is a solution that allows a very exclusive (and possibly proprietary software) .NET library\nto run in isolation on a sandbox with process isolation.\n\nFor example, a library that is fixed to `x86` instead of `Any CPU` and limited to\nthe `net35` operating environment can be loaded and called remotely under process isolation.\nConceptually, it is similar to .NET Remoting, but as you know,\nit is obsolete in .NET 6/5 and .NET Core.\n\nOf course, it can also be used when the target is not a legacy library,\nbut simply wants to run in a sandbox environment.\n\nMarionetta does not yet support transparent proxies,\nbut allows running on .NET Core runtimes and remote method invocation\nwith an API that is easy enough to understand.\n\nMarionetta uses [DupeNukem](https://github.com/kekyo/DupeNukem) as the basis for the back-end RPC transfer.\n\n### Operating Environment\n\nThe following platforms are supported by the package.\nA separate assembly is provided for each version.\nThis is in consideration of legacy libraries that are sensitive to the operating environment.\n\n* NET 6, 5\n* NET Core 3.1, 3.0, 2.2 to 2.0\n* NET Standard 2.1, 2.0, 1.6 to 1.3\n* NET Framework 4.8 to 4.0, 3.5\n\n----\n\n## How to use\n\nMarionetta installs and uses [NuGet package Marionetta](https://www.nuget.org/packages/Marionetta) in both of the following projects:\n\n|Role|Class|Overview|\n|:----|:----|:----|\n|Master|`Marionettist`|The application side of the control.|\n|Slave|`Puppet`|The side being controlled, i.e. the side containing legacy libraries. It is an independent program and starts as a child process.|\n\nYou can intentionally use Marionetta in the same process.\nIn that case, use `MasterPuppet` and `SlavePuppet` classes in pairs.\n\n### How to configure slaves\n\nThere are many possible operating conditions for legacy libraries.\nFor example, instead of `AnyCPU`, which is most common in .NET,\nor the platform specification such as `x86` or `x64` is required,\nor the configuration of the slave library is not `STAThread`\nand `Slave` as expected in WPF or Windows Forms.\n\nWindow message pumping by `STAThread` and `Application` classes is\nrequired to drive the main thread, etc.\n\nTherefore, it is necessary to write custom execution code\n(although the amount of code is small).\n\nThe following is an example of how to configure a slave\nto host a legacy library that uses WPF:\n\n```csharp\nusing Marionetta;\nusing DupeNukem;\n\n[STAThread]  // (1)\npublic static void Main(string[] args)\n{\n    // Initialize the Application class\n    var app = new Application();\n\n    // (2) Explicitly assign a SynchContext to enforce STAThread\n    // (Captured during Puppet creation)\n    var sc = new DispatcherSynchronizationContext();\n    SetSynchronizationContext(sc); SynchronizationContext;\n\n    // Generate Puppet from factory\n    var arguments = DriverFactory.ParsePuppetArguments(args);\n    using var puppet = DriverFactory.CreatePuppet(arguments);\n\n    // Register a remote callable instance\n    // (similar to DupeNukem usage)\n    var legacy = new LegacyController();\n    puppet.RegisterObject(\"legacy\", legacy);\n\n    // Shutdown notification is triggered by the master\n    puppet.ShutdownRequested += (s, e) =\u003e\n        // Shutdown the WPF application\n        app.Shutdown();\n\n    // Run Puppet (in background)\n    puppet.Start();\n \n    // (3) Run the message pump\n    app.Run();\n}\n```\n\nWhen working with legacy libraries,\nit is necessary to reproduce the situation implicitly assumed by WPF. In other words:\n\n1. The thread is basically under `STAThread`.\n2. WPF's `SynchronizationContext` is allocated.\n3. Use the `Application` class to make the message pump work.\n\nIn particular, for 2, it is recommended to pre-configure as above,\nsince it will be automatically invoked on the UI thread\nwhen a remote invocation from the master occurs.\n\nThe class `LegacyController` that manipulates the legacy library\nmust be able to reference methods from the master.\nThis is done by simply applying the `CallableTarget` attribute:\n\n```csharp\npublic sealed class LegacyController\n{\n    // Hold legacy library classes\n    private readonly LegacyDirtyClass legacyDirtyClass = new();\n\n    // Make it available for reference from the master side\n    [CallableTarget]\n    public Task\u003cstring\u003e GetValueAsync(int parameter)\n    {\n        // Use legacy library class\n        var result = this.legacyDirtyClass.GetValue(parameter);\n\n        // Return the result directly\n        return Task.FromResult(result);\n    }\n}\n```\n\nThe return value of the method must always be `Task` or `Task\u003cT\u003e`.\nThis means that you can implement asynchronous methods in a straightforward manner,\nor you can implement them synchronously as described above.\n\nThis constraint is because DupeNukem requires it,\n[and may be able to return a direct value in the future.](https://github.com/kekyo/DupeNukem/issues/4)\n\n### How to configure the master\n\nTODO:\n\n----\n\n## Background\n\nOne of the major motivations is the problem that the ASP.NET infrastructure is too large.\nASP.NET as an endpoint for RPC calls (the associated ASP.NET WebAPI),\nwould result in a huge number of libraries to depend on and require an up-to-date environment to\ncoexistence with legacy libraries can become impossible.\n\nThere are several other libraries that can be used to implement sandboxing, and\nMarionetta uses a technology commonly referred to as \"IPC\" or \"RPC\".\nMarionetta is an extension of \"IPC\" and \"RPC\" as well,\nbut by designing it with as few dependencies on other libraries as possible,\nwe have tried to eliminate the prerequisites, constraints, and background knowledge.\n\nDupeNukem uses JSON for its serializer (the familiar [NewtonSoft.Json](https://www.newtonsoft.com/json)),\nbut NewtonSoft.Json is also well thought out as a library, independent and supports a wide range of platforms.\n\n----\n\n## License\n\nApache-v2.\n\n----\n\n## History\n\nTODO:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekyo%2Fmarionetta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkekyo%2Fmarionetta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekyo%2Fmarionetta/lists"}