Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request - Dynamic method & property support for script object registered from .Net #4658

Open
WeeMud opened this issue Dec 18, 2023 · 4 comments

Comments

@WeeMud
Copy link

WeeMud commented Dec 18, 2023

I have a third party lib, contains hundreds of class, each class concain 10 ~ 100+ method & property.
I try to use this in CefSharp browser, but it is unwise to create .Net wrapper for every class.
The best way is create a simple wrapper class, contain base class info,
in script, just simply use ob.methodA(); ob.propertyA = 'a';
in wrapper .Net class , just catch the access event, then find and run or show error like "method/propert not found".

Then i try extend class from System.Dynamic, but it does not support.

// CefSharp/Internals/JavascriptObjectRepository.cs , line 240
// method Register
var type = value.GetType();
if (type.IsPrimitive || type.BaseType.Namespace.StartsWith("System."))
{
throw new ArgumentException("Registering of .Net framework built in types is not supported, " +
"create your own Object and proxy the calls if you need to access a Window/Form/Control.", "value");
}

i don't known why, mayby security issue?

i read source code to find a way to use dynamic method or property
finally, i think there is no way to do this.

// CefSharp/Internals/JavascriptObjectRepository.cs
// method AnalyseObjectForBinding
// line 670 - 699
// it cache the method to List

// CefSharp/Internals/JavascriptObjectRepository.cs
// method TryCallMethod
// line 301 - 305
// simply check List, if not found, throw error

also there can be an ugly way to use , wrapper class create proxy method
and use in script like ob.proxyCall('methodA', []); ob.proxyGet('propertyA')
it's too silly.

build custom cefsharp is hard and heavy to me, so i create this issue
suggest some way to support Dynamic method & property for script object registered from .Net
here is my solution:

[1] create interface to declear .Net class need Dynamic method & property support

// CefSharp/IDynamicMethod.cs
interface IDynamicMethod {
MethodInfo resolveDynamicMethod(string name);
};

// CefSharp/IDynamicProperty.cs
interface IDynamicProperty{
PropertyInfo resolveDynamicProperty(string name);
};

[2] modify CefSharp/Internals/JavascriptObjectRepository.cs

// method TryCallMethod & TryCallMethodAsync
// if method not found
// if obj implement IDynamicMethod , try get method from obj.resolveDynamicMethod
// do some validation & check (such as security issue) then wrap .Net MethodInfo to JavascriptMethod

// method TryGetProperty & TrySetProperty
// if property not found
// if obj implement IDynamicProperty, try get property from obj.resolveDynamicProperty
// do some validation & check (such as security issue) then wrap .Net PropertyInfo to JavascriptProperty

then we done, it's simply change few lines.
may be can cache dynamic wrappered JavascriptMethod or JavascriptProperty
but the better way is let user decide and write extra code to cache MethodInfo and PropertyInfo.

now if user require Dynamic Method or Property
just implment IDynamicMethod or IDynamicProperty,it‘s simple , elegent and comfortable.

@amaitland
Copy link
Member

Someone from the community would need to take ownership for this.

@WeeMud Are you planning on submitting a PR?

@WeeMud
Copy link
Author

WeeMud commented Dec 23, 2023

@amaitland

my local dev env can not support me to complie & verify this whole project.
so i can't submit PR with verified code.

so if someone need to take ownership for this issue, it's OK.

@mitchcapper
Copy link
Contributor

@WeeMud if you can code just not compile I can test for you. A simpler option however is to use an invisible proxy. Use a native javascript proxy and you can access things as properties and functions to your hearts content, then have the native js proxy call a CS proxied helper like you gave before: external.getProp("propName") external.callFunc("funcName") on the C# side its easy to turn those back into dynamic calls.

Here is JS to do the proxying change the console.log per above. It nicely figures out prop/method call:

let handler = {
  get: (target, name) => {

    let isProp = true;
    Promise.resolve().then(	() => console.log(`called ${name} as ${(isProp ? "Prop" : "Func")}`) );
    return new Proxy(()=>{}, {
      get: handler.get,
      apply: () => {
        isProp = false;
        return new Proxy(()=>{}, handler);
      }
    });
  }
};

let test = new Proxy({}, handler);
test.best;
test.rest();
test.best.lest.fest.rest.nest();

@amaitland
Copy link
Member

Writing your own JS proxy is certainly an option, there's a proof of concept I wrote for MAUI at https://github.com/Eilon/MauiHybridWebView/pull/3/files that should provide some inspiration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants