core icon indicating copy to clipboard operation
core copied to clipboard

WS9 Using `ImportAttribute` on a `public static` method in a C# thrown an exception `invalid address import`

Open MangelMaxime opened this issue 2 months ago • 2 comments

Hello,

In our project, we have a C# project with some API available in JavaScript

public class Delta
{
    public static readonly ushort NHASH = 16;

        [Require(typeof(JS.FossilDelta)), Inline("fossilDelta.create($origin,$target)")]
        public static byte[] Create(byte[] origin, byte[] target) {
            // ...
        }
}

because we are upgrading to WS9 we want to use ESM instead of having a global fossilDelta register on globalThis.

However trying to use ImportAttribute lead to an exception from WS:

public class Delta
{
    public static readonly ushort NHASH = 16;

        [Import("create", "./js/fossilDelta.js")]
        public static byte[] Create(byte[] origin, byte[] target) {
            // ...
        }
}
WebSharper error : Global error : System.Exception: invalid address import   at WebSharper.Compiler.JavaScriptPackager.bodyTransformer@548-1.TransformGlobalAccessSet(Address a, Expression v)   at WebSharper.Core.AST.Transformer.TransformExprStatement(Expression a)   at WebSharper.Core.AST.Transformer.TransformClassStatic(Statement a)   at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 x) in D:\a\_work\1\s\src\FSharp.Core\local.fs:line 247   at Microsoft.FSharp.Collections.ListModule.Map[T,TResult](FSharpFunc`2 mapping, FSharpList`1 list) in D:\a\_work\1\s\src\FSharp.Core\list.fs:line 98   at WebSharper.Core.AST.Transformer.TransformClass(Id a, FSharpOption`1 b, FSharpList`1 c, FSharpList`1 d, FSharpList`1 e, FSharpList`1 f)   at WebSharper.Core.AST.Transformer.TransformStatement(Statement x)   at WebSharper.Compiler.JavaScriptPackager.packageClass@1309-14(Output output, PackageContent content, Dictionary`2 imports, HashSet`1 jsUsed, Dictionary`2 addresses, List`1 statements, HashSet`1 currentScope, Boolean isSingleType, Dictionary`2 bundleExports, FSharpFunc`2 getOrImportAddress, TypeTranslator typeTranslator, FSharpFunc`2 resModule, Hashed`1 typ, Id outerClassId, Address currentClassAddr, Id classId, GenericParam[] gsArr, Statement classDecl)   at WebSharper.Compiler.JavaScriptPackager.packageType(Output output, Info refMeta, Info current, String asmName, Boolean flattened, PackageContent content)   at WebSharper.Compiler.JavaScriptPackager.pkgTyp@1589(Output output, Info refMeta, Info current, String asmName, Boolean flattened, List`1 pkgs, Hashed`1 typ)   at WebSharper.Compiler.JavaScriptPackager.packageAssembly(Output output, Info refMeta, Info current, String asmName, Boolean flattened, FSharpOption`1 entryPoint, EntryPointStyle entryPointStyle)   at WebSharper.Compiler.FrontEnd.CreateResources(LoggerBase logger, FSharpOption`1 comp, Info refMeta, Info current, Boolean sourceMap, Boolean dts, Boolean ts, Boolean dce, FSharpOption`1 closures, FSharpOption`1 runtimeMeta, AssemblyDefinition a, FSharpList`1 refAssemblies, Boolean isLibrary, Boolean prebundle, Boolean isSitelet)   at WebSharper.Compiler.FrontEnd.ModifyCecilAssembly(LoggerBase logger, FSharpOption`1 comp, Info refMeta, Info current, Boolean sourceMap, Boolean dts, Boolean ts, Boolean dce, FSharpOption`1 closures, FSharpOption`1 runtimeMeta, AssemblyDefinition a, FSharpList`1 refAssemblies, Boolean isLibrary, Boolean prebundle, Boolean isSitelet)   at WebSharper.Compiler.FrontEnd.ModifyAssembly(LoggerBase logger, FSharpOption`1 comp, Info refMeta, Info current, Boolean sourceMap, Boolean dts, Boolean ts, Boolean dce, FSharpOption`1 closures, FSharpOption`1 runtimeMeta, Assembly assembly, FSharpList`1 refAssemblies, Boolean isLibrary, Boolean prebundle, Boolean isSitelet)   at WebSharper.Compiler.CSharp.Compile.Compile$cont@109-1(WsConfig config, LoggerBase logger, String thisName, Boolean isBundleOnly, AssemblyResolver aR, Loader loader, FSharpList`1 refs, FSharpList`1 wsRefs, FSharpList`1 metas, Info refMeta, FSharpOption`1 assem, Compilation comp, Unit unitVar)   at WebSharper.Compiler.CSharp.Compile.Compile$cont@48(WsConfig config, LoggerBase logger, FSharpFunc`2 tryGetMetadata, String thisName, Boolean isBundleOnly, Unit unitVar)   at WebSharper.Compiler.CSharp.Compile.compileMain$cont@270(String[] argv, FSharpFunc`2 tryGetMetadata, LoggerBase logger, Unit unitVar)   at WebSharper.Compiler.CSharp.Compile.compileMain(String[] argv, FSharpFunc`2 tryGetMetadata, LoggerBase logger)   at WebSharper.CSharp.Program.main(String[] argv) [/home/mmangel/Workspaces/Github/Experiad/Motivity/websharper-9/src/Scatter.Fossil/Scatter.Fossil.csproj]

The error is from:

https://github.com/dotnet-websharper/core/blob/c08607accedc47832691113afded30eaf4bb8569/src/compiler/WebSharper.Compiler/JavaScriptPackager.fs#L547-L580

Is it possible to use Import on a C# method?

MangelMaxime avatar Oct 14 '25 16:10 MangelMaxime

It seems like the following works:

[Import("create", "./js/fossilDelta.js")]
[Inline("$import($origin, $target)")]
public static byte[] Create(byte[] origin, byte[] target) { }

MangelMaxime avatar Oct 14 '25 16:10 MangelMaxime

Yes, the Import won't assume the JS inline by itself. However, adding Stub will, but take note that it also keeps exact casing, so you need to name your .NET method create for [Import("create", "./js/fossilDelta.js"), Stub] to work.

Jand42 avatar Oct 20 '25 12:10 Jand42