0

I started with a working app with static exported C# methods like

[SupportedOSPlatform("browser")] // suppress CA1416 "only supported on: 'browser'"
public static partial class Code
{
    [JSExport]
    public static string NameOf([JSMarshalAs<JSType.Any>] object entity)
        => ((IHasName)entity).Name;
}

Then I created a marshaling system for using C# conveniently in JS so you could write, for example,

import { DictionaryOfInt32_String } from 'csharp'; // generated TypeScript

let dict = DictionaryOfInt32_String.new(7); // .NET dictionary, capacity 7
dict.set(7, "se7en");                       // dict[7] = "se7en";
console.log(dict.get(7));

But now I'm trying to separate my app's code from that of the marshaling system, so I created an extra JSMarshalerWasm library:

<!-- My app's .csproj for WebAssembly -->
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <Nullable>enable</Nullable>

    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
    <CompilerGeneratedFilesOutputPath>obj/generated</CompilerGeneratedFilesOutputPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
    ...
    <ProjectReference Include="..\JSMarshalCore\JSMarshalCore.csproj" />
    <ProjectReference Include="..\JSMarshalerWasm\JSMarshalerWasm.csproj" />
    <ProjectReference Include="..\JSMarshalerGenerator\JSMarshalerGenerator.csproj" 
                      ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
  </ItemGroup>  
</Project>

<!-- JSMarshalerWasm library (meant to be compiled to WebAssembly) -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
    <ProjectReference Include="..\JSMarshalCore\JSMarshalCore.csproj" />
  </ItemGroup>  
</Project>

The Marshaler project does not use Microsoft.NET.Sdk.WebAssembly because every WebAssembly project demands a Main() method to prevent this error:

Program does not contain a static 'Main' method suitable for an entry point

(I not only don't call Main(), but couldn't even figure out how to call it.) But if I add a Main() method to both projects, the following error occurs:

C:\Program Files\dotnet\sdk\9.0.305\Sdks\Microsoft.NET.Sdk.StaticWebAssets\targets\Microsoft.NET.Sdk.StaticWebAssets.targets(616,5): error : Conflicting assets with the same target path '_framework/blazor.boot.json'. For assets 'Identity: C:\Dev\MyApp\Server\MyAppWasm\bin\Debug\net8.0\wwwroot_framework\blazor.boot.json, SourceType: Computed, SourceId: MyAppWasm, ContentRoot: C:\Dev\MyApp\Server\MyAppWasm\bin\Debug\net8.0\wwwroot, BasePath: /, RelativePath: _framework/blazor.boot.json, AssetKind: Build, AssetMode: All, AssetRole: Primary, AssetRole: , AssetRole: , RelatedAsset: , AssetTraitName: WasmResource, AssetTraitValue: manifest, Fingerprint: fmiu3i5gfl, Integrity: OYuLu5ui6DeTmqCHsz8viTMsr9s2gps4W8mqrbYrE4w=, FileLength: 22689, LastWriteTime: 11/5/2025 4:27:23 AM +00:00, CopyToOutputDirectory: PreserveNewest, CopyToPublishDirectory: Never, OriginalItemSpec: obj\Debug\net8.0\blazor.boot.json' and 'Identity: C:\Dev\MyApp\Server\JSMarshalerWasm\bin\Debug\net8.0\wwwroot_framework\blazor.boot.json, SourceType: Project, SourceId: JSMarshalerWasm, ContentRoot: C:\Dev\MyApp\Server\JSMarshalerWasm\bin\Debug\net8.0\wwwroot, BasePath: /, RelativePath: _framework/blazor.boot.json, AssetKind: Build, AssetMode: All, AssetRole: Primary, AssetRole: , AssetRole: , RelatedAsset: , AssetTraitName: WasmResource, AssetTraitValue: manifest, Fingerprint: qpeekuqssc, Integrity: /q1cS1sIQjh1Us8LmqZQEEOpnikjG+LDv6FJZIMtp+U=, FileLength: 17475, LastWriteTime: 11/5/2025 4:26:53 AM +00:00, CopyToOutputDirectory: PreserveNewest, CopyToPublishDirectory: Never, OriginalItemSpec: obj\Debug\net8.0\blazor.boot.json' from different projects.

So I used Microsoft.NET.Sdk instead, but then the JSExport attributes in the Marshaler don't work:

    import { dotnet } from '_framework/dotnet.js';
    ...
    ...
    const { setModuleImports, getAssemblyExports, getConfig, runMain } = await dotnet
        .withApplicationArguments('start')
        .create();

    const config = getConfig();

    DotNetExports = await getAssemblyExports(config.mainAssemblyName);
    
    // RUNTIME ERROR:
    // TypeError: can't access property "Marshaler", DotNetExports.JSMarshaling is undefined
    Marshaler = DotNetExports.JSMarshaling.Marshaler;

Note: this is not a Blazor app, but AFAICT Microsoft didn't give a name to its .NET-in-WebAssembly system. If you're reading this Microsoft, please give your system a name so that people can discuss it properly. I see "blazor" in the error message above, but Blazor is a UI-in-C# system and I'm not doing any UI work in C#.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.