{"id":31978695,"url":"https://github.com/yoshiki-okawa/blazorjsproxy","last_synced_at":"2025-10-14T22:25:46.427Z","repository":{"id":305833617,"uuid":"398708349","full_name":"yoshiki-okawa/BlazorJSProxy","owner":"yoshiki-okawa","description":"Dynamic proxy of Microsoft.JSInterop.IJSRuntime which makes defining and invoking JS object much easier","archived":false,"fork":false,"pushed_at":"2022-07-11T10:34:51.000Z","size":247,"stargazers_count":2,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-14T22:25:33.432Z","etag":null,"topics":["blazor","blazor-wasm","blazor-webassembly","dispatchproxy","jsinterop","jsruntime","net50","proxy"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yoshiki-okawa.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-08-22T03:51:15.000Z","updated_at":"2022-02-20T21:27:22.000Z","dependencies_parsed_at":"2025-07-22T09:08:47.317Z","dependency_job_id":null,"html_url":"https://github.com/yoshiki-okawa/BlazorJSProxy","commit_stats":null,"previous_names":["yoshiki-okawa/blazorjsproxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yoshiki-okawa/BlazorJSProxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshiki-okawa%2FBlazorJSProxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshiki-okawa%2FBlazorJSProxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshiki-okawa%2FBlazorJSProxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshiki-okawa%2FBlazorJSProxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yoshiki-okawa","download_url":"https://codeload.github.com/yoshiki-okawa/BlazorJSProxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yoshiki-okawa%2FBlazorJSProxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279021780,"owners_count":26087055,"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","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["blazor","blazor-wasm","blazor-webassembly","dispatchproxy","jsinterop","jsruntime","net50","proxy"],"created_at":"2025-10-14T22:25:29.371Z","updated_at":"2025-10-14T22:25:46.415Z","avatar_url":"https://github.com/yoshiki-okawa.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BlazorJSProxy\nDynamic proxy of Microsoft.JSInterop.IJSRuntime which makes defining and invoking JS object much easier.\\\nAll you need is to define interface for JavaScript class with matching properties and methods.\\\n[![NuGet](https://img.shields.io/nuget/v/BlazorJSProxy.svg)](https://www.nuget.org/packages/BlazorJSProxy/)\\\n\\\nSee the actual working examples in Class1.cs in ClassLibrary1 project.\\\n**Example 1 - Existing window variable**\n```c#\n\t[JSTarget(ConstructorFunction = \"MouseEvent\")]\n\tpublic interface IMouseEvent : IAsyncDisposable\n\t{\n\t\tValueTask\u003cint\u003e OffsetX { get; set; }\n\t\tValueTask\u003cint\u003e OffsetY { get; set; }\n\t}\n\n\t[JSTarget(GlobalVariable = \"window.location\")]\n\tpublic interface ILocation : IAsyncDisposable\n\t{\n\t\tValueTask\u003cstring\u003e Href { get; set; }\n\t}\n\n\t// Use JSTarget with GlobalVariable as window is a global variable in JS.\n\t[JSTarget(GlobalVariable = \"window\")]\n\tpublic interface IWindow : IAsyncDisposable\n\t{\n\t\tValueTask\u003cILocation\u003e Location { get; set; }\n\t\t// Use JSName to use custom propery name instead.\n\t\t[JSName(\"onclick\")]\n\t\tFunc\u003cIMouseEvent, Task\u003e OnClick { get; set; }\n\t\t// Use JSName to use custom propery name instead.\n\t\t[JSName(\"ondblclick\")]\n\t\tAction\u003cIMouseEvent\u003e OnDoubleClick { set; }\n\t}\n\n\tprivate async Task TestWindow()\n\t{\n\t\t// Create a JS proxy of window.\n\t\tawait using var window = await BlazorJSProxy\u003cIWindow\u003e.CreateAsync(jsRuntime, null);\n\t\t// Get current URL.\n\t\tvar location = await window.Location;\n\t\tConsole.WriteLine(await location.Href); // https://localhost:5001/counter\n\t\t// Register a callback function to onclick with Func\u003cIMouseEvent, Task\u003e.\n\t\twindow.OnClick = async evt =\u003e\n\t\t{\n\t\t\tConsole.WriteLine(\"Clicked:\" + await evt.OffsetX + \",\" + await evt.OffsetY); //Clicked:99,18\n\t\t\tawait Task.CompletedTask;\n\t\t};\n\t\t// Register a callback function to ondblclick with Action\u003cIMouseEvent\u003e.\n\t\twindow.OnDoubleClick = async evt =\u003e\n\t\t{\n\t\t\tConsole.WriteLine(\"Double clicked:\" + await evt.OffsetX + \",\" + await evt.OffsetY); //Double clicked:99,18\n\t\t};\n\t\t// window object is disposed automatically with await using from both .NET and JS.\n\t}\n```\n\n**Example 2 - Custom classes**\n```c#\n\t// Use JSTarget with ConstructorFunction as Parent is a custom class defined.\n\t[JSTarget(ConstructorFunction = \"Parent\")]\n\tpublic interface IParent : IAsyncDisposable\n\t{\n\t\tValueTask\u003cstring\u003e Name { get; set; }\n\t\tValueTask\u003cIChild\u003e GetChild();\n\t\t// IArray is a simple Array JS proxy so that no parsing from JS and .NET vice versa are required until absolutely needed.\n\t\tValueTask\u003cIArray\u003cIChild\u003e\u003e GetChildren();\n\t\tValueTask\u003cIChild\u003e Child { get; set; }\n\t\t// IArray is a simple Array JS proxy so that no parsing from JS and .NET vice versa are required until absolutely needed.\n\t\tValueTask\u003cIArray\u003cIChild\u003e\u003e Children { get; set; }\n\t}\n\t[JSTarget(ConstructorFunction = \"Child\")]\n\tpublic interface IChild : IAsyncDisposable\n\t{\n\t\tValueTask\u003cstring\u003e Name { get; set; }\n\t}\n\n\tprivate async Task TestCustomParentChildClasses()\n\t{\n\t\tawait DefineCustomParentChildClasses();\n\t\tawait TestProxyReturnType(x =\u003e x.GetChild(), x =\u003e x.GetChildren());\n\t\tawait TestProxyReturnType(x =\u003e x.Child, x =\u003e x.Children);\n\t}\n\n\tprivate async Task DefineCustomParentChildClasses()\n\t{\n\t\tawait jsRuntime.InvokeVoidAsync(\"eval\", @\"\nwindow.Parent = class Parent {\n\tname = 'Parent';\n\tchild = this.getChild();\n\tchildren = this.getChildren();\n\n\tgetChild() {\n\t\treturn new Child('Child1');\n\t}\n\n\tgetChildren() {\n\t\treturn [new Child('Child1'), new Child('Child2')];\n\t}\n};\nwindow.Child = class Child {\n\tconstructor(name)\n\t{\n\t\tthis.name = name;\n\t}\n};\");\n\t}\n\n\tprivate async Task TestProxyReturnType(Func\u003cIParent, ValueTask\u003cIChild\u003e\u003e getChild, Func\u003cIParent, ValueTask\u003cIArray\u003cIChild\u003e\u003e\u003e getChildren)\n\t{\n\t\t// Create a JS proxy of Parent. Every time this is called, new instance of Parent is created in JS.\n\t\tawait using var parent = await BlazorJSProxy\u003cIParent\u003e.CreateAsync(jsRuntime, null);\n\t\t// Get the parent name.\n\t\tConsole.WriteLine(await parent.Name); // Parent\n\t\t// Get a child.\n\t\tawait using var child1 = await getChild(parent);\n\t\t// Get the child name.\n\t\tConsole.WriteLine(await child1.Name); // Child1\n\t\t// Set the child name to Child3\n\t\tchild1.Name = new ValueTask\u003cstring\u003e(\"Child3\");\n\t\t// Get the child's Name again.\n\t\tConsole.WriteLine(await child1.Name); // Child3\n\t\t// Get children.\n\t\tawait using var children = await getChildren(parent);\n\t\t// Get a number of children.\n\t\tConsole.WriteLine(await children.Length); // 2\n\t\t// Get the first child name.\n\t\tConsole.WriteLine(await (await children[0]).Name); // Child1\n\t\t// Get the second child name.\n\t\tConsole.WriteLine(await (await children[1]).Name); // Child2\n\t\t// Set the first child name to Child4\n\t\t(await children[0]).Name = new ValueTask\u003cstring\u003e(\"Child4\");\n\t\t// Get the first child name again.\n\t\tConsole.WriteLine(await (await children[0]).Name); // Child4\n\t\t// Set the first child = the second child.\n\t\tchildren[0] = new ValueTask\u003cIChild\u003e(await children[1]);\n\t\t// Get the first child name again.\n\t\tConsole.WriteLine(await (await children[0]).Name); // Child2\n\t\t// Get the second child name again.\n\t\tConsole.WriteLine(await (await children[1]).Name); // Child2\n\t}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoshiki-okawa%2Fblazorjsproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyoshiki-okawa%2Fblazorjsproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyoshiki-okawa%2Fblazorjsproxy/lists"}