프로그래밍/c#

JavaScript 에서 C# 클래스 호출하는 방법

소행성왕자 2021. 11. 26. 14:17
JavaScript 에서 C# 클래스 호출하는 방법

 

JavaScript 바인딩(JSB)을 사용하면 JavaScript및 .Net. 현재 사용할 수 있는 두 가지 고유한 구현, 즉 Async버전과 이전 Sync버전이 있습니다.

 

Async개체 바인딩 JavaScript

 

CefSharp.BindObjectAsync의 방법은 호출되는 Javascript객체를 결합 할 수 있습니다.

 

CefSharp.BindObjectAsync 는 바인딩된 개체를 사용할 수 있을 때 해결 되는 Promise 반환 합니다.

 

객체는 전역 컨텍스트(window객체의 속성)에서 생성됩니다.

 

CefSharp.BindObjectAsync매개변수 없이 호출하면 등록된 모든 객체가 바인딩됩니다.

 

간단한 워크플로는 다음과 같습니다.

 

1. 자바스크립트에 노출하려는 클래스를 생성합니다
 
2. 클래스의 인스턴스를 JavaScriptObjectRepository
 
3. 등록하려는 개체의 이름으로 CefSharp.BindObjectAsync 를 호출 합니다 CefSharp.BindObjectAsync("boundAsync");

 

1단계 .Net 클래스 생성

 

public class BoundObject
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

 

2단계 클래스의 인스턴스를 JavaScriptObjectRepository

 

프로세스의 두 번째 부분은 객체를 등록하는 것입니다

 

JavascriptObjectRepository(browser.JavascriptObjectRepository 속성을 통해 액세스 가능)

 

객체를 등록하기 위한 두 가지 옵션이 있습니다

 

첫 번째 옵션 사전에 등록되며 일반적으로 ChromiumWebBrowser 인스턴스 를 생성한 직후에 수행됩니다.

 

두 번째 옵션 더 유연하며 Resolved 필요할 때 개체를 허용 합니다.

 

첫번째 옵션
//For async object registration (equivalent to the old RegisterAsyncJsObject)
browser.JavascriptObjectRepository.Register("boundAsync", new BoundObject(), true, BindingOptions.DefaultBinder);



두번째 옵션(선호)

 

JavaScript async 함수에서

 

browser.JavascriptObjectRepository.ResolveObject += (sender, e) =>
{
    var repo = e.ObjectRepository;

    if (e.ObjectName == "boundAsync")
    {
        repo.NameConverter = null;
        repo.NameConverter = new CamelCaseJavascriptNameConverter();
        repo.Register("boundAsync", new BoundObject(), isAsync: true);
    }

};
.Net개체가 바인딩되었을 때 알림을 JavaScript 받으려면

 

ObjectBoundInJavascript 이벤트 또는 ObjectsBoundInJavascript 이벤트를 구독할 수 있습니다.

 

(두 이벤트는 매우 유사합니다)

 

browser.JavascriptObjectRepository.ObjectBoundInJavascript += (sender, e) =>
{
	var name = e.ObjectName;
	Debug.WriteLine($"Object {e.ObjectName} was bound successfully.");
};



3단계 Call CefSharp.BindObjectAsync

 

웹페이지 문서에 Javascript 추가

 

<script type="text/javascript">
(async function()
{
	await CefSharp.BindObjectAsync("boundAsync");
	
	//The default is to camel case method names (the first letter of the method name is changed to lowercase)
	boundAsync.add(16, 2).then(function (actualResult)
	{
		const expectedResult = 18;
		assert.equal(expectedResult, actualResult, "Add 16 + 2 resulted in " + expectedResult);
	});
})();

 

전체소스

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.JavascriptBinding;
using CefSharp.WinForms;
using Newtonsoft.Json.Linq;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
 
        public ChromiumWebBrowser browser;
        private BindingOptions options;
 
        public object EvaluateJavaScriptResult { get; private set; }
 
        public Form1()
        {
            InitializeComponent();
            InitBrowser();
        }
 
       
 
        private void InitBrowser()
        {
 
            var settings = new CefSettings();
            settings.Locale = "ko";
            settings.CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache");
 
            Debug.WriteLine(settings.CachePath);
            settings.RemoteDebuggingPort = 8087;
            Cef.Initialize(settings);
 
            browser = new ChromiumWebBrowser("https://yeskey.coforward.com/cef.html");
            
            JsHandler jh = new JsHandler();
            browser.JsDialogHandler = jh;
 
            this.panel1.Size = new Size(600, 400);
            this.panel1.Controls.Add(browser);
            browser.Dock = DockStyle.Fill;
 
            //frame_load_finish();
 
            //frame_load_finish();
 
            //callback_frame_load_finish();
 
 
 
            browser.JavascriptObjectRepository.ResolveObject += (sender, e) =>
            {
                var repo = e.ObjectRepository;
                
                
 
                if (e.ObjectName == "boundAsync")
                {
 
                    MessageBox.Show("123");
 
                    //BindingOptions bindingOptions = null; //Binding options is an optional param, defaults to null
                    //bindingOptions = BindingOptions.DefaultBinder; //Use the default binder to serialize values into complex objects
 
                    //bindingOptions = new BindingOptions { Binder = new MyCustomBinder() }); //Specify a custom binder
                    repo.NameConverter = null; //No CamelCase of Javascript Names
                                               //For backwards compatability reasons the default NameConverter doesn't change the case of the objects returned from methods calls.
                                               //https://github.com/cefsharp/CefSharp/issues/2442
                                               //Use the new name converter to bound object method names and property names of returned objects converted to camelCase
                    repo.NameConverter = new CamelCaseJavascriptNameConverter();
                    //repo.Register("boundAsync", new BoundObject(), isAsync: true, options: bindingOptions);
                    repo.Register("boundAsync", new BoundObject(), isAsync: true);
                }
            };
 
            browser.JavascriptObjectRepository.ObjectBoundInJavascript += (sender, e) =>
            {
                var name = e.ObjectName;
 
                Debug.WriteLine($"Object {e.ObjectName} was bound successfully.");
            };
 
 
        }
 
 
 
 
 
        
 
 
        /**
         *  페이지로드가 완료될때까지 기다립니다.
         */
 
        private void webpage_load_finish()
        {
            browser.LoadingStateChanged += (sender, args) => 
            {
                if(args.IsLoading == false)
                {
                    //browser.ExecuteScriptAsync("alert('c# 에서 로딩 완료된후 alert 실행');");
                    //browser.ExecuteScriptAsync("document.body.style.background = 'red'");
                    browser.ExecuteScriptAsync("aa()");
                }
            };
        }
 
 
        private void frame_load_finish()
        {
            // MainFrame이로드를 완료 할 때까지 기다립니다.
            browser.FrameLoadEnd += (sender, args) =>
            {
                //Wait for the MainFrame to finish loading
                if (args.Frame.IsMain)
                {
                    
                    args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
                    browser.ExecuteScriptAsync("document.body.style.background = 'blue';");
                    browser.ExecuteScriptAsync("aa();");
                    
                    Task task = new Task(() => {
                        //object js = EvaluateScript(browser, "document.getElementsByTagName('html')[0].innerHTML;");
                        object js = EvaluateScript(browser, "bb();");
                        MessageBox.Show(js.ToString());
                    });
                    
                    task.Start();
                    
                }
            };
        }
 
 
        private void callback_frame_load_finish()
        {
            // MainFrame이로드를 완료 할 때까지 기다립니다.
            browser.FrameLoadEnd += (sender, args) =>
            {
                //Wait for the MainFrame to finish loading
                if (args.Frame.IsMain)
                {
 
                    args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
                    browser.ExecuteScriptAsync("document.body.style.background = 'blue';");
                    browser.ExecuteScriptAsync("");
 
                    Task task = new Task(() => {
                        //object js = EvaluateScript(browser, "document.getElementsByTagName('html')[0].innerHTML;");
                        object js = EvaluateScript(browser, "cc();");
                        MessageBox.Show(js.ToString());
                    });
 
                    task.Start();
 
                }
            };
        }
 
        /**
         * MainFrame 로드를 완료 할 때까지 기다립니다. 
         */
        /*
        private void frame_load_finish_ori()
        {
            browser.FrameLoadEnd += (sender, args) =>
            {
                //Wait for the MainFrame to finish loading
                if (args.Frame.IsMain)
                {
                    args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
                    browser.ExecuteScriptAsync("document.body.style.background = 'blue';");
                    browser.ExecuteScriptAsync("");
 
                    Task task = new Task(() => {
 
                        //object js = EvaluateScript(browser, "document.getElementsByTagName('html')[0].innerHTML;");
                        
                        object js = EvaluateScript(browser, "bb();");
                        
                        Debug.WriteLine(js.ToString());
                        
                        string json = js.ToString().Trim();
                        
                        Debug.WriteLine(json);
                        
                        JObject applyJObj = JObject.Parse(json.Trim());
                        
                        string nick = applyJObj["field1"].ToString();
                        
                        string id = applyJObj["field2"].ToString();
                        
                        Debug.WriteLine($"nick -> {nick}");
                        
                        Debug.WriteLine("$"id -> {id}");
                    
                        });
 
                    task.Start();
                }
            };
        }
        */
 
 
        static object EvaluateScript(ChromiumWebBrowser b, string script)
        {
            var task = b.EvaluateScriptAsync(script);
            task.Wait();
            JavascriptResponse response = task.Result;
            return response.Success ? (response.Result ?? "") : response.Message;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
 
 
            /*
            var script = @"
            document.getElementById('Sign').click();
            ";
            browser.ExecuteScriptAsync("script");
            */
 
            browser.ExecuteScriptAsync("document.body.style.background = 'red';");
            Task task = new Task(() => {
                object js = EvaluateScript(browser, "cc();");
                string json = js.ToString().Trim();
 
                Debug.WriteLine(json);
                JObject applyJObj = JObject.Parse(json.Trim());
                string nick = applyJObj["nick"].ToString();
                string id = applyJObj["name"].ToString();
 
                MessageBox.Show(nick);
 
            });
 
            task.Start();
 
        }
 
    }
 
 
    public class JsHandler : IJsDialogHandler
    {
        public bool OnBeforeUnloadDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, string messageText, bool isReload, IJsDialogCallback callback)
        {
            //throw new NotImplementedException();
            return true;
        }
 
        public void OnDialogClosed(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {
        //throw new NotImplementedException();
 
        }
 
        public bool OnJSDialog(IWebBrowser browserControl, IBrowser browser, string originUrl, CefJsDialogType dialogType, string messageText, string defaultPromptText, IJsDialogCallback callback, ref bool suppressMessage)
        {
            String type = dialogType.ToString().ToLower();
            if (type == "confirm")
            {
                DialogResult result = MessageBox.Show(messageText, "트레이딩 커뮤니티", MessageBoxButtons.OKCancel);
                switch (result)
                {
                    case DialogResult.OK: { callback.Continue(true); break; }
                    case DialogResult.Cancel: { callback.Continue(false); break; }
                }
            }
            else
            {
                DialogResult result = MessageBox.Show(messageText, "트레이딩 커뮤니티");
                callback.Continue(true);
            }
 
            return true;
        }
        public void OnResetDialogState(IWebBrowser chromiumWebBrowser, IBrowser browser)
        {
            //throw new NotImplementedException();
        }
    }
 
    public class BoundObject
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
 
 
 
}