What is preventing my JavaScript arrays from being successfully converted to the correct data types?

I have encountered difficulties passing JavaScript arrays and dictionary-like objects to methods in my managed code through the HTMLBridge. Despite searching for information on this topic in a Microsoft article and various other sources, I have not found a solution.

Referring to the information provided in the linked article:

.NET Framework properties or input parameters that are typed as object undergo certain conversions when marshaled by value to a target .NET Framework property or input parameter:

JavaScript arrays are converted to object[].

JavaScript dictionaries are converted to Dictionary<string,object>.

... I have made several attempts to pass arrays and dictionary-like objects to my managed code without success:

Javascript:

var array = [{key: 1}, {key: 2}, {key: 3}];
silverlight_domElement.content.testObject.testMethod(array);

C# (attempt #1):

[ScriptableMember]

//Throws conversion exception here
public void testMethod(Dictionary<string,object>[] arrayParam) 
{
    //...
}

C# (attempt #2):

[ScriptableMember]
public void testMethod(object arrayParam) 
{
    //Throws conversion exception here
    Dictionary<string, object>[] arr = (Dictionary<string, object>[])arrayParam; 
}

C# (attempt #3):

[ScriptableMember]
public void testMethod(ScriptObject arrayParam)
{
    //Throws conversion exception here
    Dictionary<string, object>[] arr = 
      arrayParam.ConvertTo<Dictionary<string, object>[]>();

}

The exceptions appear in the following form (where "TARGET TYPE" is the expected type of the object resulting from an explicit or implicit cast, including Object[]):

SCRIPT16389: System.ArgumentException: This object cannot be converted to the specified type TARGET TYPE. Parameter name: targetType

at System.Windows.Browser.ScriptObject.ConvertTo(Type targetType, Boolean allowSerialization)

at System.Windows.Hosting.ScriptingInterface.GetScriptParamValueForType(ScriptParam scriptParam, Type desiredType)

at System.Windows.Hosting.ScriptingInterface.ConvertFromScriptParams(ParameterInfo[] parameters, ScriptParam[] args)

at System.Windows.Browser.ManagedObjectInfo.ScriptMethod.Invoke(ManagedObject obj, InvokeType invokeType, ScriptParam[] args)

at System.Windows.Browser.ManagedObjectInfo.Invoke(ManagedObject obj, InvokeType invokeType, String memberName, ScriptParam[] args)

at System.Windows.Hosting.ManagedHost.InvokeScriptableMember(IntPtr pHandle, Int32 nMemberID, Int32 nInvokeType, Int32 nArgCount, ScriptParam[] pArgs, ScriptParam& pResult, ExceptionInfo& pExcepInfo)

(Similar attempts were made to pass dictionary-like objects to C# as Dictionary<string, object>).

Are these unsuccessful attempts due to misinterpretation of the information in the referenced article and beyond? Or is there a flaw in my implementation?

Addendum:

I am aware of using ScriptObject.getProperty() to achieve what I need, but I prefer working with concrete, specific types if possible. Moreover, it returns either a native type, String, or ScriptObject if the keyed value cannot be unboxed as either of the former two. I would rather not resort to repeatedly calling it on deeply nested objects until reaching a native type.

Answer №1

It appears that

[{key: 1}, {key: 2}, {key: 3}]

is categorized as

an object []

rather than a dictionary type.

Your code is attempting to convert an array into a dictionary, which is not possible.

To clarify, because the top level object is an Array and therefore an object [], the JSON parser cannot determine the individual types of each element in the array.

You will need to convert it to

object[]

and then handle it like this:

Dictionary<string,object> cur;
foreach(object o in objArray)
{
   cur = (Dictionary<string,object>) o;

}

Answer №2

Upon further examination of the linked article, it appears that the excerpt in question pertains to marshalling operations on a managed object after its creation via the createObject or createManagedObject methods.

Consider a class structure like this:

[ScriptableType]
public class TestClass
{
    public object arrayObj;
    public object dicObj;
    public TestClass sibling;

    public TestClass(){}
    public void testMethod(TestClass testClassObj)
    {
                               //Assuming argument came from Javascript
                               //& arrayObj and dicObj were assigned an 
                               //Array and dictionary-obj respectively

         testClassObj.arrayObj; //Formal type: Object. Actual type: object[]
         testClassObj.dicObj;   //Formal type: Object. Actual type: 
                                //                     Dictionary<string, object>
    }
}

Implemented in the Silverlight application as follows:

private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = new MainPage();
    HtmlPage.RegisterCreatableType("TestClass", typeof(TestClass));
    HtmlPage.RegisterScriptableObject("scripTestClassObj", new TestClass());
}

This can be utilized on the client-side like so:

var testClassObj = silverlight_domElement.content
                    .services.CreateObject("TestClass");
testClassObj.arrayObj = [1,2,3];  
testClassObj.dicObj = {key: 1};  

silverlight_domElement.content.scripTestClassObj.testMethod(testClassObj);

//"sibling"'s arrayObj and dicObj types will have actual types
//of object[] and Dictionary<string, object> respectively
silverlight_domElement.content.scripTestClassObj.sibling = testClassObj;

To clarify, these details do not affect the current discussion on functionality.

In the context of my query, it indicates that passing non-primitive Javascript values to managed code necessitates adherence to specific guidelines:

  1. The target property or method parameter must be of type ScriptObject (or Object, given its inheritance).
  2. Either explicitly or implicitly registering the target type with HtmlPage.RegisterCreatableType, requiring the passed value to derive from a createObject or createManagedObject invocation using the registered alias (createObject) or type (createManagedObject).

If any statements provided are inaccurate, please feel free to provide corrections.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Changing the prefix for a guild can be done without needing a complete restart, while adding a new guild to my database inexplicably requires one

I have set up a code that adds guilds to the database with default settings when they join. If the guild decides to change the prefix, it updates successfully and they can immediately start using it. However, there is an issue where I have to restart the b ...

The Null object within localStorage is identified as a String data type

As someone transitioning from Java development to Javascript, I am seeking clarification on a particular issue. In my project, I am utilizing localStorage to keep track of the user's token in the browser. localStorage.token = 'xxx' When a ...

Unable to execute the 'getElementsByTagName' function as null value is passed as the parameter

I'm encountering a problem with my first AJAX attempt and my first time using a .php file. I'm working through an exercise in the text, but things aren't going as expected. To troubleshoot, I've been using the alert function extensively ...

How can I update the color of a list item when it is clicked within a foreach loop using knockout js?

Currently, I am encountering an issue with changing the color when a user clicks on a list item using the latest version of knockout js. My goal is to change the color of a list item when it is clicked and maintain that color until another item is clicked, ...

The error message regarding pdf.worker.min is stating that the use of 'import' and 'export' is limited to within module code and cannot be used outside of it

Upon attempting to deploy a build to Vercel, I encountered the following error message: Failed to compile. static/media/pdf.worker.min.50acc843.mjs from Terser x 'import', and 'export' cannot be used outside of module code ,-[18:1 ...

Utilizing several carets in a single or multiple text areas and input boxes

Just a quick question... Can a textbox have two carets simultaneously, or can we have two separate textboxes both focused at the same time? I am aware of simulating this using keydown listeners but I'm specifically looking for visible carets in both ...

How to Retrieve CheckBox Values from a SQL Database in ASP.Net?

I have a scenario where I am working with CheckBoxes that are stored in a SQL database as '1' and '0'. However, when trying to retrieve these values on a load event, I am facing difficulties. Below is the code snippet: private void ...

Transforming Uint8Array into BigInt using Javascript

I've come across 3 different ways to convert a Uint8Array to BigInt, but each method seems to produce varying results. Can someone clarify which approach is correct and recommended? Utilizing the bigint-conversion library. The function bigintConversi ...

Error message: The Javascript Electron app is unable to find the node-fetch module when

Below is the code snippet from my gate.html file: <html> <head> <meta http-equiv='Content-Security-Policy' content='default-src 'self'; https://example.com.tr/validkeys.txt'> <meta http-equiv=&ap ...

Troubleshooting: The issue of receiving a 403 error when trying to access

I'm currently using Codeigniter 3 and have encountered an issue with a script. When the code is in my HTML file, everything works perfectly fine. However, if I move the code to an external file, I receive a 403 error. The location of my JavaScript fi ...

What is the alternative name for DOM elements in TypeScript?

When working with a HTMLImageElement, I can simply reference it like this: let image: HTMLImageElement; ... In Dart, importing the dom is possible using: import 'dart:html' as dom; Using 'dom' as an alias for the "dart:html" package. ...

The Twilio JWT authentication token has expired

I'm currently utilizing Twilio voice call functionality and everything is working smoothly. However, the Twilio JWT token expires every hour, forcing users to refresh the page periodically. I'm seeking advice on how to extend the token validity p ...

How can you create a unique record by appending a number in Javascript?

Currently, when a file already exists, I add a timestamp prefix to the filename to ensure it is unique. However, instead of using timestamps, I would like to use an ordinal suffix or simply append a number to the filename. I am considering adding an incr ...

My goal is to generate a collection of nested objects by iterating through an array and storing the results as input

I need help converting the elements in this array into a JSON object format. Here is the list of items in the array: Input var input = [ { bio: "Test", id: 2, image: "http://localhost:8000/media/default.jpg", user: 2 ...

How to override an event in JavaScript when a specific value is entered

I am looking to implement a system with complex conditions. The goal is to have an alert appear when a value is inputted and the button is clicked. First, a confirmation message Have you input ? should be displayed, followed by clicked with input. If no va ...

Exposing a factory JS variable globally within an AngularJS environment

I am trying to access a variable created within a factory in another function in my AngularJS controllers. How can I achieve this and make the new calculated value available? The variable I want to use is result.data.bkor_payamount = result.data.bkor_paya ...

Using the ASP.NET parameter or variable in both the application settings and application build events

Is it possible to retrieve an Application Setting from the Pre Build Event in ASP.NET? Can the value of a Setting be injected from the Pre Build Event? Here is the full context: In my project, I have an Angular app integrated within an ASP.NET 4 Web API ...

How to extract a JavaScript object from an array using a specific field

When dealing with an array of objects, my goal is to choose the object that has the highest value in one of its fields. I understand how to select the value itself: Math.max.apply(Math, list.map(function (o) { return o.DisplayAQI; })) ... but I am unsur ...

Unexpected behavior in Next.js when using Auth0: pageProps are empty when wrapped with withPageAuthRequired HOC

Explaining the Issue The problem arises when using withPageAuthRequired with getServerSideProps, as the pageProps object is empty. Despite following common practices, the pageProps parameter remains undefined. Expected Outcome Upon calling getServerSideP ...

Eliminate any unnecessary tags located before the text

I am facing a challenge with the following code snippet. The Variable contains a string that includes HTML tags such as <img>, <a>, or <br>. My goal is to eliminate the <img> tag, <a> tag, or <br> tag if they appear befo ...