Blazor server side problem share javascript code - javascript

I'm developing my project with Blazor Server-side.
While I develop, I used javascript code to implement things that hard to implement by C#.
However, I'm facing something weird situation. (I guess it is problem for javascript)
Suppose there are 2 users(A, B). When 'A' user do some action that call javascript code, if 'B' user into same page, 'A' users action affects to 'B' user.
I implemented web page that have 3d scene with threejs. As I explained above, when User 'A' move some object with mouse event(mousemove, mousedown..), if User 'B' accesses the same page, 3d objects of B are moved to the location where User 'A' moved.
Originally, when user access to web page I developed, 3d objects's position should be 0,0,0.
My Guess
I don't use prototype or class(use variable and functions globally. I'm new to javascript.. )
Javascript runs on server-side(share resources??, If then, how can I solve it)
I'm guessing the javascript would be problem, but if you have any other opinions, would you please share?
Edited
I've solved this problem using DotNetObjectReference.Create(this);
C#
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//send created instance to javascript
var dotNetObjRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("SetObjectRef", dotNetObjRef);
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable]
public async Task enableSomething(bool bEnable)
{
var something = bEnable;
}
//== before edit
//[JSInvokable]
//public static async Task enableSomethingStatic(bool bEnable)
//{
// var something = bEnable;
//}
Javascript
var objectRef;
function SetObjectRef(ref) {
objectRef = ref;
}
//call c# function
objectRef.invokeMethodAsync("enableSomething", true);
It was problem of 'static' method as I guessed.
If you declare C# method called from javascript as 'static' and this method changes something of UI variable, this method can affect another users.
So I create instance of current page and send it javascript and when I need to call C# methods from javascript, I call methods using created instance.
Is there any problem or issue, please share it.
Sorry for my bad English.

JavaScript runs client side only. I don't see how two windows, let alone two users, would share data.
Almost for sure, the problem is that you are injecting a singleton service-- which means the server will use one instance for all users.
If so, you have two choices:
(1) add logic to your singleton service to incorporate users. (For example, a dictionary with UserID/Property name for key, and a column for Value)
(2) go to Startup.cs and change the suspect singleton service to .AddScoped(), which will create a new instance for each user.
For right now, I think the latter solution will solve your problem immediately. However, don't underestimate the value of Singletons-- they'll be very useful for other things.

Related

unity webgl and browser javascript communication

So i have this problem with communicating between browser and unity webgl,
basically what i want to do is generate objects in unity's scene with javascript code from the view the webgl is being played. In other words, view will have javascript code to create game objects after the scene loaded, not sure if this is possible yet.
i've read the unity documentation but i haven't found an example of how to implement the code shown there or if it's what i'm looking for.
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html this is what i have been reading, specially the code visibility part, but since i've never worked with frontend that much i'm a bit clueless.
What you can do is to send messages to Unity inside your Javascript code but you'll let Unity do the dirty work about instantiating objects.
This is an example that I just made:
First you create a C# script that spawns your object/prefab, like this:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MyObjectSpawner : MonoBehaviour {
public Transform Prefab;
public void Spawn(string data) {
var instance = Instantiate(Prefab);
// do what you like with your instantiated object and the data from the javascript here
}
}
Now you create an object inside the scene and attach this script to it. Keep attention about the name you give to the Game Object you just created, this will be important in the next step. For now, let's say we named it "MyGameObject".
The last step is your javascript inside the game page container. For this example, I've created a button and when it's clicked, the spawnUnityObject() method is called. Like this:
HTML:
<button type="button" onclick="spawnUnityObject()">Press me</button>
Javascript:
function spawnUnityObject() {
// game object in the scene, method name, method parameter
SendMessage('MyGameObject', 'Spawn', 'Super string');
}
The result will be: when you click the "Press me" button inside the html, the game will spawn an object and you can use the "Super string" as a data inside the Spawn() method.
I hope this helps you. Let me know if you need more details.

Calling Java function from Rhino

Calling Javascript functions running inside Rhino from Java is easy enough - that after all is why Rhino was created. The thing I am having trouble establishing is this:
Context: I have a Phonegap CLI (v 6.3.3) Android project (API 19+) where I do a great deal of processing via loadable JavaScript running inside rhino
A Phonegap plugin - which I am creating at the same time as the actual Phonegap app - contains class called Storage which provides public, static, methods such as readFromFile(String fileName), writeToFile(String fileName,String data) etc.
What I want to be able to do is to call Storage.readFromFile etc from my loaded JavaScript code in Rhino.
Just how this should be done is not too clear to me. From the searches I have done thus far it involves using ScriptableObject.putProperty to pass the Java class in question, Storage in my case to JavaScript. However, how this should be done and then how it should be used at the JS end leaves me rather confused.
I would be most grateful to anyone here who might be able to point me in the right direction
Given that Rhino has less than 100 followers here it should perhaps come as little surprise that this question was not answered. In the mean time I have managed to find the solution myself and it turns out to be very simple. I share it below for the benefit of anyone else running into this thread.
My Storage class is very simple. It goes something like this
public class Storage
{
public static boolean haveFile(){}
public static boolean readFromFile(String fname){}
...
}
When I call Javascript from Java via Rhino I simply pass a new instance of the Storage class as the last of my function parameters
Context rhino = Context.enter();
Object[] functionParams = new Object[] {"Other parameters",new Storage()};
rhino.setOptimizationLevel(-1);
try
{
Scriptable scope = rhino.initStandardObjects();
String rhinoLog = "var log = Packages.io.vec.ScriptAPI.log;";
String code = /*Javascript code here* as shown separately below/;
rhino.evaluateString(scope, rhinoLog + code, "ScriptAPI", 1, null);
Function function = (Function) scope.get("jsFunction", scope);
Object jsResult = function.call(rhino,scope,scope,functionParams);
}
where the Javascript code is
function jsFunction(a,s)
{
//a - or a,b,c etc - here will be the "other" parameters
//s - will be the instance of the Java side Storage class passed above
//now you can do things like
s.writeToFile('fileName','fileData');
var fd = s.readFromFile('fileName');
s.dropFile('fileName');
...
}

OnContextCreated() in Cef not being called

I have a similar problem to the person in this post; I'm trying to extend the cefsimple.exe app included with the chromium embedded framework binaries to include a V8 handler. I implemented the OnContextCreated() method and made sure to extend RenderProcessHandler in the SimpleHandler class. I'm trying to implement a simple window bound variable called test_string; here's what my code looks like;
void SimpleHandler::OnContextCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CefRefPtr<CefV8Value> object = context->GetGlobal();
object->SetValue("test_string", CefV8Value::CreateString("this is a test"), V8_PROPERTY_ATTRIBUTE_NONE);
}
But the program never arrives at any breakpoints I add within the method, and the variable is undefined on any webpages I load within the app. I saw that one of the solutions in the other thread is to enable the settings.single_process flag, which i've done, but my code still doesn't reach the breakpoint.
To be clear, I'm accessing the variable on pages with window.test_string.
Make sure that you are sending that CefApp to CefExecuteProcess.
CefRefPtr<SimpleApp> app(new SimpleApp);
// CEF applications have multiple sub-processes (render, plugin, GPU, etc)
// that share the same executable. This function checks the command-line and,
// if this is a sub-process, executes the appropriate logic.
int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
Found this solution here
Have you read through the General Usage guide? Some key points below
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-cefapp
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-processes
The single_process mode is not supported so I've never used it. In general I'd avoid it. The multi process architecture means you need to attach the debugger to the process. The Chromium guide is relevant to CEF in this instance.
https://www.chromium.org/developers/how-tos/debugging-on-windows#TOC-Attaching-to-the-renderer
you need to ensure your App is derived from CefRenderProcessHandler
not SimpleHandler!!!
class SimpleApp : public CefApp
, public CefRenderProcessHandler
{
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
valdemar-rudolfovich says you need to pass instance of SimpleApp in
CefExecuteProcess

Using PHP/JS to perform actions

to help teach myself PHP I've tasked myself with updating old mysql_* code with PDO.
This has been going great, and as I've been learning I've been able to greatly reduce the amount of code. However my research has ran into a brick wall in a particular area.
Currently, we have it so projects are recorded in a list view, with a set of 'actions/options' for each project. Each of these actions links to a PHP file which runs a small amount of code then sends you back to the list view.
Here is an example:
function projectComplete(id) {
location.href = "complete.php?id=" + id;
}
<button type="button" class="projectComplete" onclick="projectComplete('<?= htmlentities($row['projectid']); ?>')"></button>
The complete.php file simply contains an SQL update query that sets a column in the record a completed state of '1'.
I originally wanted to ask the question 'what is the best practice for handling this type of interaction' however that may attract opinion based answers which I read is not allowed here.
Instead I will phrase it like this: Is there a way of having all of these 'actions' run in the same page? (ideally able to use buttons rather than forms, due to difficulty in layout styling of forms)
I know that if it used forms, I could simply name each form's submit button differently then run an if statement (the only issue would be passing the id, but I'm sure I could figure that out e.g.
if (isset($_POST['exampleAction'])) { Run the code.. }
Any links to guides/tutorials/similar questions etc would be very much appreciated. As previously stated, I'm self-learning PHP - I know very few 'best practices' and would like to learn more.
One thing you could consider is an MVC pattern, where a page call will run some function based on some parameters. A full-blown MVC framework is probably more than you need for this project, but mimicking the controller dispatching is certainly doable. Something to this effect could work (code untested):
if (isset($_GET['action'])) {
new Actions()->dispatch('action_'.$_GET['action']);
}
class Actions {
public function dispatch($action) {
if (method_exists($this, $action)) {
$this->$action($_GET);
} else {
http_response_code(400);
exit(1);
}
}
// The following functions are examples only!
public function action_Create($parameters) {
// Create database record
}
public function action_Read($parameters) {
// Read database record
}
public function action_Update($parameters) {
// Update database record
}
public function action_Delete($parameters) {
// Delete database record
}
}
Then you'd call (for example) action.php?action=Read&name=foo&author=bar

How to discover and load js files at runtime?

I'm writing a node.js based server that manages a range of devices. The node.js based server tells connected clients about its abilities. The abilities are defined by separate js files that define objects that are using inheritance via util.inherits().
The problem I have is that right now, I have to define a new js for a new ability and then update the main js program to require the new js, change the code to publish that the ability is available, and then utilise the new ability if requested to by the client.
I would like to make the main code more generic whereby it can
detect the new abilities,
automatically include them,
notify the clients, and
utilise the code.
The detection I can do via the various npm modules out there that support tree browsing, I can just nominate a subdirectory for all capabilities and discover what files are there. I presume that I can use require for step 2 (though not 100% certain), however I don't know how to do step 3 and 4 or use the results from step 2 with step 3 and 4.
I would value any feedback on how to solve this problem.
To clarify my problem. Right now my logic is as per the following:
var logicA = requires('./capabilities/a.js');
var logicB = requires('./capabilities/b.js');
var logicC = requires('./capabilities/c.js');
var Comms.CAPABILITY_A = 'a';
var Comms.CAPABILITY_B = 'b';
var Comms.CAPABILITY_C = 'c';
var Comms.MSG_CAPABILITY = 0;
var Comms.MSG_DO_LOGIC = 1;
function onMessageReceived(comms, msgId, body) {
switch (msgId) {
case(MSG_DO_LOGIC):
doLogic(body);
break;
...
}
}
function doLogic(flag) {
switch(flag) {
case(Comms.CAPABILITY_A):
logicA.doLogic();
break;
case(Comms.CAPABILITY_B):
logicB.doLogic();
break;
case(Comms.CAPABILITY_C):
logicC.doLogic();
break;
}
}
At the client side I have hard coded logic that presumes what is available. I can remove this by having the server send an array of the capabilities to the client, and then the client can choose one of the elements of the array and pass it back as the request to execute the logic. This is not my problem.
My problem is understanding how to cause the host program load all the logic dynamically and then evaluate which logic to execute on the dynamically loaded logic.
I should state that when I say dynamic, I mean that the code available is determined at runtime. However the evaluation is only ever performed when the server is first started.
I solved the problem by creating a register.js where all the protocols are kept. Each time I create a new protocol, I add it to the register.
Via the register I can get an array of all registered protocols. I can pass them back to the client, the client can choose a protocol and I can request an instance of the protocol via the register class.
While there is some hardcoding, it's restricted to the register class which is in the same directory as the protocols.
So in the register I have the following functions:
getList()
getText()
validateProtocolId()
getProtocol()
I use getList() to return an array of the protocol id's that are registered. I use getText() to provide a human readable list of supported protocols. I use validateProtocolId() to validate an id returned from the client to confirm that the id represents a registered protocol and then I use getProtocol() to generate an instance of the registered protocol.
In essence the getProtocol() just does a require('./<protocol file>.js') as appropriate.
It's not as elegant as auto discovery, but it allows tighter controls on what is registered without forcing custom file, etc.

Categories