Generating Webassembly from pure C# class - javascript

I'm making my backend on C# and frontend on JS.
I want to reuse some alghoritms written in C# in browser JavaScript.
Simplified example:
class Fibonacci {
int Fib(int x) {
if (x == 0) return 0;
int prev = 0;
int next = 1;
for (int i = 1; i < x; i++)
{
int sum = prev + next;
prev = next;
next = sum;
}
return next;
}
Is it possible to compile one library-independent class to WebAssembly and use it from browser? How?

Yes, with NativeAOT-LLVM (https://github.com/dotnet/runtimelab/tree/feature/NativeAOT-LLVM). There's a similar question with a full answer at Compiling C# project to WebAssembly

From what I understand, C# needs some middleware / framework to convert it to wasm. If your use case does not warrant Blazor, you might try the UNO platform: https://github.com/unoplatform/Uno.Wasm.Bootstrap

You can call .NET methods form JavaScript functions like this
Here is the razor html
#inject IJSRuntime JS
<button #onclick=#CallToJS >Call JS function</button>
Here is the code behind
#code {
/// <summary>
/// This method calls javascript function with .net object reference parameter
/// </summary>
/// <returns>Awaitable task</returns>
private async Task CallToJS() => await JS.InvokeVoidAsync("sayHi", DotNetObjectReference.Create(this));
/// <summary>
/// This method is called from javascript
/// </summary>
/// <param name="name">some string parameter coming from javascript</param>
/// <returns>Returns string</returns>
[JSInvokable]
public async Task<string> CalledFromJS(string name)
{
// Here you can call your class library
return $"Hi {name}";
}
}
And this is the JavaScript code calling .NET method
function sayHi(dotNetHelper) {
var promise = dotNetHelper.invokeMethodAsync('CalledFromJS', "Surinder");
promise.then(function (result) {
console.log(result);
});
}

Related

Why I can't execute Java method in JavaScript code?

Please have a look at the JavaScript code below.
const locations = /*[[${locations}]]*/ null;
locations.forEach(location => {
location.description = 44;
location.lnglat = 127;
location.fun(); // error
});
description and lnglat are variables from Java list of objects of class 'Location'; fun is a function from this class.
There is no problem assigning values to variables, but I can't call the function fun. Unfortunately, I don't know what the reason is and how can I fix it.
In Java, I use Spring Boot and method addAttribute:
#GetMapping("/")
public String homePage(Model model) {
model.addAttribute("locations", locations());
return "home";
}

Blazor, how to constantly get currentWindow width?

I want to do something like this in a razor page:
#if (currentwidth<x)
{
le code
}
else
{
le other code
}
I have added javascript file and connected it to a utility service which works when I get the static width (which I tested).
js:
export function getCurrentWidth() {
return window.addEventListener("resize", () => {
window.innerWidth;
});
}
UtilityService method:
public async Task<double> GetCurrentWidth()
{
var m = await GetModule();
var result = await m.InvokeAsync<double>("getCurrentWidth");
return result;
}
Razor file:
double width;
protected async override Task OnInitializedAsync()
{
width = await utilityService.GetCurrentWidth();
}
Thus the problem is I can't call it from OnInitailzedAsync since this function only fired once, so I need a function that constantly checks the GetCurrentWIdth() method to check for resize.
Is there another way of doing this in blazor or what method could I use/ Thank you in advance.
First of all I'd like to point out that you may not have to solve your problem with javascript/C# code. If it's something in the html that you want to manipulate, you may just be better of using css. But I'll leave that up to you.
If however you truly need the window width like you mentioned above, then I would recommend registering a listener to the window (as you've already done) and have that listener call a dotnet function. Doing this with static methods is quite easy, but for instance component this can be a bit trickier as you have to pass an object reference of the current object.
The [JsInvokable] indicates that this method can be called from javascript, which allows communication from the javascript event listener to dotnet.
CSharpFromJs.razor.cs
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Threading.Tasks;
public partial class CSharpFromJS
{
private DotNetObjectReference<CSharpFromJS> _objectReference;
public int WindowWidth { get; set; }
[Inject]
public IJSRuntime JSRuntime { get; set; }
protected override void OnInitialized()
{
_objectReference = DotNetObjectReference.Create(this);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await InitWindowWidthListener();
}
}
[JSInvokable]
public void UpdateWindowWidth(int windowWidth)
{
WindowWidth = windowWidth;
StateHasChanged();
}
private async Task InitWindowWidthListener()
{
await JSRuntime.InvokeVoidAsync("AddWindowWidthListener", _objectReference);
}
public async ValueTask DisposeAsync()
{
await JSRuntime.InvokeVoidAsync("RemoveWindowWidthListener", _objectReference);
_objectReference?.Dispose();
}
}
CSharpFromJs.razor
#implements IAsyncDisposable
<h1>Window width: #WindowWidth</h1>
Javascript
// Manages the registered event listeners so they can be disposed later
let windowEventListeners = {};
function AddWindowWidthListener(objReference) {
let eventListener = () => UpdateWindowWidth(objReference);
window.addEventListener("resize", eventListener);
windowEventListeners[objReference] = eventListener;
}
function RemoveWindowWidthListener(objReference) {
window.removeEventListener("resize", windowEventListeners[objReference]);
}
function UpdateWindowWidth(objReference) {
objReference.invokeMethodAsync("UpdateWindowWidth", window.innerWidth);
}
The only thing you should be careful with is when a component is disposd. You should remove the registered handlers in the DisposeAsync function to ensure that they're not still registered to prevent memory leaks.
This link might provide some better instructions on how to use this, but they don't explain the part about disposing handlers.
Note: This only works in .net5 and later, as IAsyncDisposable was not yet implemented for component before that. If for some reason you're working with an earlier version, you could call it using IDisposable. But this could potentially cause deadlocks, so I would not recommend it.
For me works the NuGet package BlazorPro.BlazorSize
Implement the method:
async void WindowResized(object _, BrowserWindowSize window){}
and all necessary Dependencies (see description).

Calling Javascript functions from C# Unit Tests

I am working on a small project that will primarily be a C# library. I also want to create a JavaScript counterpart that is functionally equivalent. I would like to be able to test both from the same unit tests.
To be clear I am NOT going to be using this in a production environment where C# calls JS, or vice versa. I only want to blend C# and JavaScript in the context of the unit tests so I can verify and maintain cross-platform compatibility. Most examples I find show that this is possible within Blazor using JSRuntime, but I don't want to do this within a web application.
Below is an example of what I am trying to accomplish.
C# Method:
public class CsharpLibrary
{
public static bool CheckLength(string str) {
if (str.Length > 10)
return false;
return true;
}
}
JavaScript Function:
function CheckLength(str) {
if (str.length > 10)
return false;
return true;
}
Unit Test
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CsharpJavascriptUnitTesting
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void CheckLength_TooLong()
{
var str = "1234567890123456789";
var isValid = CsharpLibrary.CheckLength(str);
Assert.IsFalse(isValid);
// TODO: is it possible to load the local Javascript file?
// TODO: call JavaScript CheckLength(str);
// TODO: assert that the value returned is also false
}
}
}
Thanks to the recommendation in the comment above from Collen I was able to accomplish this with the Jurassic library.
[TestMethod]
public void CheckLength_TooLong()
{
var str = "1234567890123456789";
var isValid = CsharpLibrary.CheckLength(str);
Assert.IsFalse(isValid);
var engine = new Jurassic.ScriptEngine();
engine.ExecuteFile(#"..\..\JsLibrary.js");
isValid = engine.CallGlobalFunction<bool>("CheckLength", str);
Assert.IsFalse(isValid);
}

How to return value from JS function to Java instantly without JS Interface?

I have a webview. I want to call JS function from Java and assign return value to a variable.
This line from java calls getUserDetails() function of JavaScript.
webview.loadUrl("javascript:window.getUserDetails()");
This is the getUserDetails function in javascript which returns a string
window.getUserDetails = function(){
return "username";
}
I want to achieve something like this.
String user = webview.loadUrl("javascript:window.getUserDetails()");
How can I able to achieve this?
You have to change the way you are calling that method.
webview.loadUrl("javascript:alert(window.getUserDetails())");
and while handling the alert your returned value will be there.
For more info please follow this link
As per the comment you can do this in following way.
String mUserName;
String getUserName(){
runOnUiThread(new Runnable() {
#Override
public void run() {
webView.loadUrl("javascript:android.onData(window.getUserDetails())");
}
});
return mUserName;
}
#JavascriptInterface
public void onData(String value) {
mUserName = value;
}
WebView#evaluateJavascript is the recommended way to do this asynchronously. If you want something which feels synchronous, you can try using Futures to wait for the callback:
final SettableFuture<String> jsFuture = SettableFuture<>.create();
webView.evaluateJavaScript("window.getUserDetails()", new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
jsFuture.set(value);
}
});
String value = jsFuture.get();

Is it possible to pass a function with SignalR?

I imagine it would look like the following.
Server(C#):
public class MyHub : Hub {
...
public int DoSomething(Func<int> fn) {
var res = fn();
return res;
}
...
}
Client(TS/JS):
myHub.invoke('DoSomething', () => 2 + 2).then(res => console.log(res));
However, with this code fn is null on the server.
Seems this is impossible as your parameters should be serializable. So all you can - serialize parameters in known structure and generate invocation function based on deserialization result.
You could write the function in c# and pass it back to the server as a string, then compile and run it - this might help with compiling:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime

Categories

Resources