Wednesday, June 1, 2022

Running a C# WebAssembly module outside of the browser

Based on "Future Possibilities for .NET Core and WASI (WebAssembly on the Server) | OD108", published May 27, 2022 by Steve Sanderson (SteveSandersonMS on Github, @stevensanderson on Twitter).  Video at https://youtu.be/A0vz_BWxIMc.

Prerequisites

.NET Version

.NET 7 or later is required.  I used ".NET 7 Preview 4", downloaded from: https://dotnet.microsoft.com/en-us/download/dotnet/7.0.

On Windows
I did not use the Installer.  Rather, I downloaded the "Binaries" and unzipped them to a local folder.  Then I added the root of that local folder to the front of the PATH environment variable, in a command prompt.
I also used the "Developer Command Prompt for VS 2022" command prompt.

On Mac
I installed .NET 7 Preview 4 using the installer.

WASI Runtime

To run the final .wasm file, I used wasmtime which I installed from here: https://wasmtime.dev/
I also ran it under wasmer, Installed from here: https://wasmer.io/

Build and Run

From a terminal or command prompt, create a new dotnet console project and "cd" into it:
dotnet new console -o HelloWasi 
cd HelloWasi

Then run it to make sure it works:
dotnet run 

It will just say "Hello world" or something like that.   Update Program.cs to output something more interesting.  Replace Program.cs with this code:

using System.Runtime.InteropServices;

System.Console.WriteLine($"Hello world! The time is {DateTime.UtcNow.ToLongTimeString()}");
System.Console.WriteLine($"OSArchitecture: {RuntimeInformation.OSArchitecture}");
System.Console.WriteLine($"OSDescription: {RuntimeInformation.OSDescription}");
System.Console.WriteLine($"FrameworkDescription {RuntimeInformation.FrameworkDescription}");
System.Console.WriteLine($"ProcessArchitecture {RuntimeInformation.ProcessArchitecture}");
System.Console.WriteLine($"RuntimeIdentifier {RuntimeInformation.RuntimeIdentifier}");

Build and run again:
dotnet build
dotnet run 

You should see output something like this.  Note what it says for "OSArchitecture"
Hello world! The time is 1:34:03 AM
OSArchitecture: X64
OSDescription: Microsoft Windows 10.0.19044
FrameworkDescription .NET 7.0.0-preview.4.22229.4
ProcessArchitecture X64
RuntimeIdentifier win10-x64

On macOS you'd get something like this:
Hello world! The time is 2:51:07 PM
OSArchitecture: X64
OSDescription: Darwin 19.6.0 Darwin Kernel Version 19.6.0: Tue Feb 15 21:39:11 PST 2022; root:xnu-6153.141.59~1/RELEASE_X86_64
FrameworkDescription .NET 7.0.0-preview.4.22229.4
ProcessArchitecture X64
RuntimeIdentifier osx.10.15-x64

Now let's update the project to target WebAssembly instead.
Add the Wasi.Sdk package:
dotnet add package Wasi.Sdk --prerelease

Or update the .csproj file to include this:
  <ItemGroup>
    <PackageReference Include="Wasi.Sdk" Version="0.1.1" />
  </ItemGroup>

Now when you do:
dotnet build

it will create HelloWasi.wasm next to the HelloWasi..exe file: 
bin\Debug\net7.0\HelloWasi.wasm
I'll be a single 16 MB file, because it contains all of the required .NET code.

Using Wasmtime, we can run this .wasm file:
wasmtime bin\Debug\net7.0\HelloWasi.wasm

Note the "OSArchitecture" field in the output:

Hello world! The time is 01:33:31
OSArchitecture: Wasm
OSDescription: Browser
FrameworkDescription .NET 7.0.0-dev
ProcessArchitecture Wasm
RuntimeIdentifier browser-wasm

Same exact .wasm file can run on any platform that supports WASI.  I tried it under wsl2 using wasmtime.  Also works under MacOS

Also tried the wasmer runtime. 


Tuesday, June 16, 2015

How to launch an elevated prompt

Here's a trick to launch an elevated prompt or run any app as Administrator elevated even from a non-elevated command prompt.

Use 'pseudo'.   It's kinda like 'sudo'

See https://github.com/kasajian/pseudo

Friday, May 1, 2015

Alternative to mocking static methods in C#

Curious what you guys think of this as an alternative to mocking static methods in C#?
Here's a a simply way to mock static methods without a mocking framework.

Say you have code like this:
        class Math
        {
            public static int Add(int x, int y)
            {
                return x + y;
            }

You want to "mock" the Add method, but you can't. Change the above code to this:

        class Math
        {
            public static Func Add = (x, y) =>
            {
                return x + y;
            };

Existing client code doesn't have to change (maybe recompile), but source stays the same.

Now, from the unit-test, to change the behavior of the method, just reassign an in-line function to it:
    [TestMethod]
    public static void MyTest()
    {
        Math.Add = (x, y) =>
        {
            return 11;
        };dada

Put whatever logic you want in the method, or just return some hard-coded value, depending on what you're trying to do.

This may not necessarily be something you can do each time, but in practice, I found this technique works just fine.

Another thing to keep in mind.   When you set the static variable like that, you should undo it when the test is complete.   One way to do that is to re-run the class's static initializer. 

 Example:
    typeof(SomeClassName).TypeInitializer.Invoke(null, null);

Wednesday, March 18, 2015

Favorite Day-of-Week calculation

/* 0 = Sunday, 1 <= m <= 12, y > 1752 or so */
int dayofweek(int y, int m, int d)
{
    static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    y -= m < 3;
    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}

Wednesday, January 28, 2015

A slight-of hand with .NET Lazy

The following is an example of a better way to read a value from a C# dictionary.

In C#/.NET, you will get an exception if you specify an non-existent key when attempting to read a value from a Dictionary.   The workaround is to call the TryGetValue method, which is awkward because of the out parameter, and the requirement of the additional variable declaration (< C#6).

Sometimes the behavior that you want is to get a null or 0 value when using an invalid key.   Other times you want to simply test the returned value to see if actually has a value, similar to Option/Maybe idiom in other languages.

Because of the extensible nature of C#, you can kinda have your cake an eat it to.   There's multiple ways to solve this problem, and some cool functional libraries have this built in (such as https://github.com/louthy/language-ext ), but with some slight-of hand, you can actually re-purpose the .NET built-in Lazy class to do this for you.

A Lazy object is an object that holds another object (or value), but it may be empty.  The reason it exists is for "memoization", in that, the Lazy object starts out empty, and then later, it may be filled with a value.

But no is stopping you from using Lazy as a way to indicate an optional value.   The following is an extension to IDictionary called GetValue.  When called with an existing key, it returns a Lazy object containing the value.   If the key does not exist, it returns an empty Lazy object.   You just have to call IsValueCreated on the Lazy object to determine if the value exists.   Alternatively, you can just use the .Value property and use the type's default value, such as 0 or null, when the key doesn't exist.  Depending on what you're doing, that may be what you want.

Either way, you don't have to use TryGetValue

References:

http://programmers.stackexchange.com/questions/159096/return-magic-value-throw-exception-or-return-false-on-failure/264516#264516

http://www.extensionmethod.net/csharp/idictionary/idictionary-getvalue

Wednesday, January 21, 2015

C# Dictionary to XML

Do you have a string dictionary in .NET code (C#) that want to write out to disk in nicely formatted XML?

A single line of text will do this:

new XElement("root", d.Select(
    kv => new XElement(kv.Key, kv.Value)))
        .Save(filename, SaveOptions.OmitDuplicateNam
espaces);


To read the XML file back later into a dictionary, is another single line:

var d = XElement.Parse(File.ReadAllText(filename))
    .Elements()
    .ToDictionary(k =>
        k.Name.ToString(),
        v => v.Value.ToString
());

That's it!

Monday, January 19, 2015

Easily Zip just the source of a Visual Studio project

When playing around, creating new Visual Studio projects such as a weekend project, you want an easy way to zip up my source and not worry about .pdb, obj/bin files, etc. files.
The .gitignore file is created when you create a Visual Studio project with the "Create new Git repository" selected.
You don't need to use pkzip because Git has the archiving feature built-in.  Just type:
git archive -o all.zip HEAD
and it will create all.zip of the latest source, without any of the stuff you don’t want in the .zip file like bin, obj, exes, nuget assemblies, etc.

Sunday, January 18, 2015

Double click file to run a PowerShell script

Typically, you cannot double click on a PowerShell script (.ps1 file) and have it automatically run, like you could with a batch file (.bat or .cmd). This is a good thing because someone may accidentally run something that was not meant to be run.

But what if you need to have someone run a PowerShell script and you just want them to double click a shortcut of some sort to make it happen.

The trick is to create a batch file that invokes the PowerShell. If you give the batch file and PowerShell script the same base name, then the batch file content doesn't have to change:


@echo off
pushd "%~d0"
pushd "%~dp0"
powershell.exe -sta -c "& {.\%~n0.ps1 %*}"
popd
popd

So, for instance, if you wish to run a PowerShell script called xyz.ps1, just create xyz.bat with the above content.

That's it!


By the way, the two pushd/popds are necessary in case the user's CDs is on a different drive. Without the outer set, the CD on the drive with the script will get lost.


Friday, November 21, 2014

How do I specify Git Commit id (hash) when launching a build with TFSBuild.exe?

TFSBuild.exe is the method by which you launch TFS build from the command line. TFSBuild.exe doesn't indicate how to specify a Git commit Id (the hash of the commit).
TFSBuild.exe discusses the /getOption:Custom option which, when used, lets use specify the change-set or label to base the build on, by specifying the change-set or label identifier with the /customGetVersion option. For a label, you start with an "L". For a change-set, you start with a "C".
You specify the git commit-id using the "Label" syntax, but add a "G:ref:" before the commit ID. As in: /customGetVersion:LG:ref:
Full syntax:
TFSBuild start teamProjectCollectionUrl teamProject definitionName /queue /getOption:Custom /customGetVersion:LG:ref:
Example usage:
TFSBuild start http://gitsourceserver:8080/tfs/MyCompany MyTeamProject MyBuildDefinition /queue /getOption:Custom /customGetVersion:LG:ref:0c9cc3ce

Saturday, November 15, 2014

Closures in C#, just like in JavaScript

How would I rewrite this JavaScript routine in C# using closure?

function makeConverter(toUnit, factor, offset) {
    offset = offset || 0;

    var converter = function (input) {
        return ((offset + input) * factor).toFixed(2) + " " + toUnit;
    };

    return converter;
}

var milesToKm = makeConverter('km', 1.60936);
var poundsToKg = makeConverter('kg', 0.45460);
var farenheitToCelsius = makeConverter('degrees C', 0.5556, -32);

log(milesToKm(10));
log(poundsToKg(2.5));
log(farenheitToCelsius(98));

You can do the same thing in C#:
public static Func<double, string> makeConverter(string toUnit, double factor, double offset = 0.0)
{
    return (input) => string.Format("{0:0.##} {1}", (offset + input) * factor, toUnit);
}

public static void Main()
{
    var milesToKm = makeConverter("km", 1.60936);
    var poundsToKg = makeConverter("kg", 0.45460);
    var farenheitToCelsius = makeConverter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm(10));
    Console.WriteLine("{0}", poundsToKg(2.5));
    Console.WriteLine("{0}", farenheitToCelsius(98));
}
You can further reduce it down to a single method:
public static void Main()
{
    Func<string, double, double, Func<double, string>> makeConverter =
        (toUnit, factor, offset) => (input) => string.Format("{0:0.##} {1}", (offset + input) * factor, toUnit);

    var milesToKm = makeConverter("km", 1.60936, 0.0);
    var poundsToKg = makeConverter("kg", 0.45460, 0.0);
    var farenheitToCelsius = makeConverter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm(10));
    Console.WriteLine("{0}", poundsToKg(2.5));
    Console.WriteLine("{0}", farenheitToCelsius(98));
}
You can even use old-style can use C# 2 syntax (yes, C# has had closure since 2005)
public delegate string del_t(double input);

public static del_t makeConverter(string toUnit, double factor, double offset = 0.0)
{
    return delegate(double input) 
    {
        return string.Format("{0:0.##} {1}", (offset + input) * factor, toUnit );
    };
}

public static void Main()
{
    var milesToKm = makeConverter("km", 1.60936);
    var poundsToKg = makeConverter("kg", 0.45460);
    var farenheitToCelsius = makeConverter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm(10) );
    Console.WriteLine("{0}", poundsToKg(2.5) );
    Console.WriteLine("{0}", farenheitToCelsius(98));
}
For comparison, if you didn't use closure, the traditional class-based way of solving this problem in C# would be:
public static void Main()
{
    var milesToKm = new Converter("km", 1.60936);
    var poundsToKg = new Converter("kg", 0.45460);
    var farenheitToCelsius = new Converter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm.Convert(10) );
    Console.WriteLine("{0}", poundsToKg.Convert(2.5) );
    Console.WriteLine("{0}", farenheitToCelsius.Convert(98) );
}

class Converter
{
    string m_toUnit;
    double m_factor;
    double m_offset;

    public Converter(string toUnit, double factor, double offset = 0)
    {
        m_toUnit = toUnit;
        m_factor = factor;
        m_offset = offset;
    }

    public string Convert(double input)
    {
        return string.Format("{0:0.##} {1}", (m_offset + input) * m_factor, m_toUnit );
    }
}