Load native libraries from a dynamic location

Today, I had to deal with an uncommon need. In short, the idea is to download a native library (dll) into a temporary directory (not in the application folder), and use its methods. The content of the dll is known, so I want to use the DllImport attribute to easily call the methods of the dll.

The application must work on Windows 10, so I can use a function introduced in Windows 8 AddDllDirectory. This function allows to indicate the paths where the native libraries are. So, you can download the dll and use the AddDllDirectory function to add its path for dll loading.

const uint LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000;

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDefaultDllDirectories(uint DirectoryFlags);

[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int AddDllDirectory(string NewDirectory);

void Initialize()
{
    var downloadDirectory = "temp";
    DownloadDll(downloadDirectory);

    // Indicate to search libraries in
    // - application directory
    // - paths set using AddDllDirectory or SetDllDirectory
    // - %windows%\system32
    SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);

    // Add the directory of the native dll
    AddDllDirectory(downloadDirectory);

    // Use the native dll
    MyMethod();
}

[DllImport("mydll.dll")]
public static extern int MyMethod();

More information about the kernel32 methods:

Comparing files using Visual Studio Code

In the previous post, I showed you how to use Visual Studio to compare 2 files. I also use Visual Studio Code from time to time. And, as every great IDE, Visual Studio Code also have a great diff tool. As with Visual Studio, you can use it to compare 2 versions of the same file if you use a source control. But you can also compare 2 files from your file system.

Comparing files using the User Interface

  1. Open the 2 files in Visual Studio Code
  2. Right click on one file and click "Select for compare"

  1. Right click on the other file and click "Compare file file1 with file2"

You should see the result:

Comparing files using the command line

  • Using Visual Studio Code
"%ProgramFiles%\Microsoft VS Code\bin\code" --diff file1.cs file2.cs
  • Using Visual Studio Code Insiders
"%ProgramFiles%\Microsoft VS Code Insiders\bin\code-insiders" --diff file1.cs file2.cs

Test JavaScript code using Karma, Mocha, Chai and headless browsers

Web applications use more and more JavaScript. As for the back-end code, you must test it. However, testing front-end code is not as simple as testing back-end code. Indeed, you have to test it on multiple browsers (Chrome, Edge, Firefox, Safari, etc.) and their different versions. This means you need to test your code on at least 10 browsers to be sure your code will works as expected.

In this post, I'll show how to use Karma to run tests, and Mocha and Chai to write them.

Quick explaination

Karma allows to test your code on real browsers and real devices such as phones, tablets. It starts the browsers and runs the tests on them.

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases.

describe('Array', () => {
  describe('#indexOf()', () => {
    it('should return -1 when the value is not present', () => {
      assert.equal([1,2,3].indexOf(4), -1);
    });
  });
});

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

assert.equal(foo, 'bar');

To sum up, Karma runs mocha on multiple browsers. The assertions of the tests are written using chai.

Installation

Karma comes with multiple plugins. There are plugins for using test frameworks, and plugings for starting browsers. You can install Karma, the plugins, mocha and chai using npm:

npm i --save-dev karma karma-mocha karma-chai
npm i --save-dev karma-chrome-launcher karma-firefox-launcher karma-ie-launcher
npm i --save-dev mocha chai

You'll find the list of launcher on GitHub: Karma launchers

Then, create a function, a test, and the karma configuration. The structure of your application should look like:

MyProject
├── src
│   └── main.js
├── test
│   └── mainSpec.js
├── package.json
└── karma.conf.js

Here's the content of main.js:

function endsWith(str, suffix) {
	return str.indexOf(suffix, str.length - suffix.length) !== -1;
}

Here's the content of mainSpec.js:

describe('main', function () {
    describe('#endsWith()', function () {
        it('should return true when the value ends with the suffix', function () {
            assert.equal(true, endsWith("abcd", "cd"));
        });

        it('should return false when the value does not end with the suffix', function () {
            assert.equal(false, endsWith("abcd", "cde"));
        });
    });
});

Then, you must configure karma. Create a file karma.config.js with the following content:

module.exports = function (config) {
    config.set({
        frameworks: ['mocha', 'chai'],
        files: [
            'src/**/*.js',
            'test/**/*.js'
        ],
        reporters: ['progress'],
        port: 9876,  // karma web server port
        colors: true,
        logLevel: config.LOG_INFO,
        browsers: ['ChromeHeadless', 'Firefox', 'FirefoxDeveloper', 'FirefoxNightly', 'IE'],
        autoWatch: false,
        concurrency: Infinity,
        customLaunchers: {
            FirefoxHeadless: {
                base: 'Firefox',
                flags: ['-headless'],
            },
        },
    })
}

By default, the karma-firefox doesn't register the headless version of the browser, so I add it manually in the customLaunchers section.

Finally, add the test script in packages.json:

{
  "name": "my-project",
  "version": "0.0.0",
  "devDependencies": {
      // code omited for brevity
  },
  "scripts": {
    "test": "karma start --single-run --browsers ChromeHeadless,FirefoxHeadless,IE karma.conf.js"
  }
}

You can now run the tests using npm test

npm test

Conclusion

Your test environment is now set up. You can add lots of tests for your front-end code. Karma and Mocha have lots of functionalities. In this post, we just cover the surface. Be sure to read the documentation to explore the possibilities of these solutions.

Comparing files using Visual Studio

The diff tool of Visual Studio is very good to compare 2 files. You can use it to compare two versions of the same file directly in Visual Studio. But you can also use it to compare 2 files that are not in a solution.

Using the command line

  1. Open the developer command prompt from the start menu, so devenv.exe is already in the path
  2. Use the following command line:
devenv /diff file1.cs file2.cs

Using the Command Window in Visual Studio

If you have already opened Visual Studio, you can use the Command Window to diff files.

  1. Open the Command Window using the Quick Launch or using the keyboard Ctrl+W, A

  1. Using the command Tools.DiffFiles with the 2 files to compare:
Tools.DiffFiles "file1.cs"  "file2.cs"

You'll get the same result as with the command line:

MSTest v2: Testing against multiple frameworks

This post is part of the serie 'MSTest v2'. Be sure to check out the rest of the blog posts of the serie!

When you create a .NET library, you can target multiple frameworks: .NET Framework, .NET Core, Universal Windows Platform, etc., and their different versions. You can now write code that targets .NET Standard to target a maximum of platform at once. However, you should test your code runs well on all these platforms. For example, if you create a .NET Standard 2.0 library, you may want to test it on .NET Core 2.0 and .NET Framework 4.6.1. You'll find the compatibility table of .NET Standard in the documentation

Using the new csproj, you can set multiple target frameworks. The test runner will use all of them.

  1. Open the csproj of the test project.
  2. Replace TargetFramework by TargetFrameworks (plural) and set the desired frameworks separated by a semicolon. The list of frameworks is available in the documentation.

Before:

<TargetFramework>netcoreapp2.0</TargetFramework>

After:

<TargetFrameworks>net461;net47;netcoreapp2.0</TargetFrameworks>
  1. Run the tests using the command line:
dotnet test

The unit tests are run three times, once per platform. This way you are sure your code will behave the same way on all platforms.

Note: The test explorer of Visual Studio doesn't support multiple frameworks. It will only display and execute the test of one platform.