Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CefSharp.Example/CefSharp.Example.netcore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
<None Remove="obj/**/*.*" />
<Compile Remove="obj/**/*.*" />
</ItemGroup>

<ItemGroup>
<Compile Remove="ModelBinding\PropertyInterceptorLogger.cs" />
</ItemGroup>

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.WindowsDesktop" />
</Project>
26 changes: 26 additions & 0 deletions CefSharp.Example/ModelBinding/PropertyInterceptorLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright © 2022 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using System;
using System.Diagnostics;
using CefSharp.ModelBinding;

namespace CefSharp.Example.ModelBinding
{
public class PropertyInterceptorLogger : IPropertyInterceptor
{
object IPropertyInterceptor.InterceptGet(Func<object> propertyGetter, string propertyName)
{
object result = propertyGetter();
Debug.WriteLine("InterceptGet " + propertyName);
return result;
}

void IPropertyInterceptor.InterceptSet(Action<object> propertySetter, object parameter, string propertName)
{
Debug.WriteLine("InterceptSet " + propertName);
propertySetter(parameter);
}
}
}
33 changes: 33 additions & 0 deletions CefSharp.Test/JavascriptBinding/JavaScriptObjectRepositoryFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

using CefSharp.Example.ModelBinding;
using CefSharp.Internals;
using System;
using System.Collections.Generic;
using Xunit;

Expand Down Expand Up @@ -46,5 +48,36 @@ public void CanRegisterJavascriptObjectBindWhenNamespaceIsNull()
Assert.True(result.Success);
Assert.Equal("ok", result.ReturnValue.ToString());
}

#if !NETCOREAPP
[Fact]
public void CanRegisterJavascriptObjectPropertyBindWhenNamespaceIsNull()
{
IJavascriptObjectRepositoryInternal javascriptObjectRepository = new JavascriptObjectRepository();
var name = nameof(NoNamespaceClass);

BindingOptions bindingOptions = new BindingOptions()
{
Binder = BindingOptions.DefaultBinder.Binder,
PropertyInterceptor = new PropertyInterceptorLogger()
};
javascriptObjectRepository.Register(name, new NoNamespaceClass(), false, bindingOptions);
Assert.True(javascriptObjectRepository.IsBound(name));

var boundObjects = javascriptObjectRepository.GetObjects(new List<string> { name });
Assert.Single(boundObjects);

object getResult, setResult = 100;
string exception;
NoNamespaceClass noNamespaceClass = new NoNamespaceClass();
bool retValue = javascriptObjectRepository.TrySetProperty(boundObjects[0].Id, "year", setResult, out exception);
Assert.True(retValue);

retValue = javascriptObjectRepository.TryGetProperty(boundObjects[0].Id, "year", out getResult, out exception);
Assert.True(retValue);
Assert.Equal(100, Convert.ToInt32(getResult));
}
#endif
}

}
7 changes: 5 additions & 2 deletions CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ public BrowserTabView()
var bindingOptions = new BindingOptions()
{
Binder = BindingOptions.DefaultBinder.Binder,
MethodInterceptor = new MethodInterceptorLogger() // intercept .net methods calls from js and log it
MethodInterceptor = new MethodInterceptorLogger(), // intercept .net methods calls from js and log it
#if !NETCOREAPP
PropertyInterceptor = new PropertyInterceptorLogger()
#endif
};

//To use the ResolveObject below and bind an object with isAsync:false we must set CefSharpSettings.WcfEnabled = true before
Expand Down Expand Up @@ -90,7 +93,7 @@ public BrowserTabView()
{
if (e.ObjectName == "bound")
{
repo.Register("bound", new BoundObject(), isAsync: false, options: BindingOptions.DefaultBinder);
repo.Register("bound", new BoundObject(), isAsync: false, options: bindingOptions);
}
else if (e.ObjectName == "boundAsync")
{
Expand Down
9 changes: 9 additions & 0 deletions CefSharp/BindingOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,14 @@ public static BindingOptions DefaultBinder
/// for logging calls (from js) to .net methods.
/// </summary>
public IMethodInterceptor MethodInterceptor { get; set; }

#if !NETCOREAPP
/// <summary>
/// Interceptor used for intercepting get/set calls to the target object property. For instance, can be used
/// for logging calls to .net property (from js)
/// </summary>
public IPropertyInterceptor PropertyInterceptor { get; set; }
#endif

}
}
1 change: 1 addition & 0 deletions CefSharp/CefSharp.netcore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<Compile Remove="CefRuntime.cs" />
<Compile Remove="DevTools\DevToolsClient.Generated.cs" />
<Compile Remove="Internals\Partial\ChromiumWebBrowser.Partial.cs" />
<Compile Remove="ModelBinding\IPropertyInterceptor.cs" />
</ItemGroup>

<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
Expand Down
2 changes: 2 additions & 0 deletions CefSharp/Internals/IJavascriptObjectRepositoryInternal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ public interface IJavascriptObjectRepositoryInternal : IJavascriptObjectReposito
{
TryCallMethodResult TryCallMethod(long objectId, string name, object[] parameters);
Task<TryCallMethodResult> TryCallMethodAsync(long objectId, string name, object[] parameters);
#if !NETCOREAPP
bool TryGetProperty(long objectId, string name, out object result, out string exception);
bool TrySetProperty(long objectId, string name, object value, out string exception);
#endif
bool IsBrowserInitialized { get; set; }
List<JavascriptObject> GetObjects(List<string> names = null);
List<JavascriptObject> GetLegacyBoundObjects();
Expand Down
4 changes: 4 additions & 0 deletions CefSharp/Internals/JavascriptObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ public class JavascriptObject //: DynamicObject maybe later

public IMethodInterceptor MethodInterceptor { get; set; }

#if !NETCOREAPP
public IPropertyInterceptor PropertyInterceptor { get; set; }
#endif

public JavascriptObject()
{
Methods = new List<JavascriptMethod>();
Expand Down
28 changes: 24 additions & 4 deletions CefSharp/Internals/JavascriptObjectRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ public void Register(string name, object value, bool isAsync, BindingOptions opt
jsObject.IsAsync = isAsync;
jsObject.Binder = options?.Binder;
jsObject.MethodInterceptor = options?.MethodInterceptor;
#if !NETCOREAPP
jsObject.PropertyInterceptor = options?.PropertyInterceptor;
#endif

AnalyseObjectForBinding(jsObject, analyseMethods: true, analyseProperties: !isAsync, readPropertyValue: false);
}
Expand Down Expand Up @@ -562,6 +565,7 @@ protected virtual async Task<TryCallMethodResult> TryCallMethodAsync(long object
return new TryCallMethodResult(false, result, exception);
}

#if !NETCOREAPP
bool IJavascriptObjectRepositoryInternal.TryGetProperty(long objectId, string name, out object result, out string exception)
{
return TryGetProperty(objectId, name, out result, out exception);
Expand All @@ -585,8 +589,14 @@ protected virtual bool TryGetProperty(long objectId, string name, out object res

try
{
result = property.GetValue(obj.Value);

if (obj.PropertyInterceptor == null)
{
result = property.GetValue(obj.Value);
}
else
{
result = obj.PropertyInterceptor.InterceptGet(() => property.GetValue(obj.Value), property.ManagedName);
}
return true;
}
catch (Exception ex)
Expand All @@ -596,7 +606,9 @@ protected virtual bool TryGetProperty(long objectId, string name, out object res

return false;
}
#endif

#if !NETCOREAPP
bool IJavascriptObjectRepositoryInternal.TrySetProperty(long objectId, string name, object value, out string exception)
{
return TrySetProperty(objectId, name, value, out exception);
Expand All @@ -618,8 +630,14 @@ protected virtual bool TrySetProperty(long objectId, string name, object value,
}
try
{
property.SetValue(obj.Value, value);

if (obj.PropertyInterceptor == null)
{
property.SetValue(obj.Value, value);
}
else
{
obj.PropertyInterceptor.InterceptSet((p) => property.SetValue(obj.Value, p), value, property.ManagedName);
}
return true;
}
catch (Exception ex)
Expand All @@ -629,6 +647,8 @@ protected virtual bool TrySetProperty(long objectId, string name, object value,

return false;
}
#endif


/// <summary>
/// Analyse the object and generate metadata which will
Expand Down
56 changes: 56 additions & 0 deletions CefSharp/ModelBinding/IPropertyInterceptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CefSharp.ModelBinding
{
/// <summary>
/// Provides the capability intercepting get/set property calls made from javascript as part of the
/// JavascriptBinding (JSB) implementation.
/// </summary>
public interface IPropertyInterceptor
{
/// <summary>
/// Called before the get property is invokved. You are now responsible for evaluating
/// the property and returning the result.
/// </summary>
/// <param name="propertyGetter">A Func that represents the property to be called</param>
/// <param name="propertName">Name of the property to be called</param>
/// <returns>The property result</returns>
/// <example>
/// <code>
/// <![CDATA[
/// public object IPropertyInterceptor.InterceptGet(Func<object> propertyGetter, string propertyName)
/// {
/// object result = propertyGetter();
/// Debug.WriteLine("InterceptGet " + propertyName);
/// return result;
/// }
/// ]]>
/// </code>
/// </example>
object InterceptGet(Func<object> propertyGetter, string propertName);

/// <summary>
/// Called before the set property is invokved. You are now responsible for evaluating
/// the property.
/// </summary>
/// <param name="propertySetter">A Func that represents the property to be called</param>
/// <param name="parameter">paramater to be set to property</param>
/// <param name="propertName">Name of the property to be called</param>
/// <example>
/// <code>
/// <![CDATA[
/// public object IPropertyInterceptor.InterceptSet(Action<object> propertySetter, object parameter, string propertName)
/// {
/// Debug.WriteLine("InterceptSet " + propertName);
/// propertySetter(parameter);
/// }
/// ]]>
/// </code>
/// </example>
void InterceptSet(Action<Object> propertySetter, object parameter, string propertName);
}
}