November 8, 2021

PBKDF2 Tool in Blazor

I first heard about Blazor a couple of years ago, and it sounded very interesting, especially the part about running .NET via WebAssembly on the browser. Blazor seems to have matured enough now and it's officially part of ASP.NET. Recently, my team needed a tool for PBKDF2 as we integrate with Keycloak, so I tried writing it in Blazor. Here are some of my thoughts on it so far.

You can find the full source in my GitHub repo.

C#

It's actually very refreshing to use just one language – C# (probably my favorite language) – for both the frontend and the backend, in a modern SPA-like paradigm, not WebForms with full page PostBacks like the good old days...? Of course, you're still using HTML and CSS (with support for SCSS and scoped CSS) for the "view" template. You can also call JavaScript via interop, which will be inevitable if you want to use built-in browser functionality such as alert().

WebAssembly

Originally, I wanted to build it as a WebAssembly project so that I can host as a static site and all you'd need is the browser to run it, but sadly, the KeyDerivation library doesn't support WebAssembly platform, so I had to use the Blazor Server hosting model.

The server hosting model uses WebSockets, and the server-side runs the logic, so scalability would need to be considered if writing real business applications with it.

JSX..?

I suppose this is more of a Razor template feature than Blazor, but I like that it's similar to React's JSX. For example, being able to use code blocks within the template, such as using the if statement to wrap around a component. (Never liked how Angular templates handle logic, such as ngIf and ngFor directives, where they are added as element attributes.)

Unit Testing

There's no official Microsoft library for unit testing Blazor, but an open-source project called bUnit seems popular for writing unit tests for Blazor components.

Being able to test the difference between snapshots of a render seems useful, but might get too complicated if testing a large change. Component isolation and keeping them small would help.

You can write tests as a razor component, which means you can use razor syntax for the component-under-test. Visual Studio editor's auto-formatting support still needs some work though.

DisplayName Validation Message Bug?

Perhaps there's a bug when using the DisplayName attribute on the InputText component. For both ValidationSummary and ValidationMessage<T>, setting the DisplayName attribute seems to have no effect on InputText. It just displays the property name, not the DisplayName.

InputNumber works fine though, as can be seen here:

...
validationErrorMessage = string.Format(ParsingErrorMessage, DisplayName ?? FieldIdentifier.FieldName);
...

Maybe it's not supported yet?

It does work if I use the [Display] attribute on the model itself, but nowadays I feel that's not the right place, since it breaks the layer boundary. If the model is serving as a "View Model", then it'd be okay.

Finding out how the [Required] attribute's message validation works was taking longer than I'd like, so I stopped at ValidationAttributeAdapterOfTAttribute.cs. If I can get to spend more time on this and can confirm it, perhaps I'll file a bug report. By the way, did you know that the ASP.NET Core solution has 480 projects? Took a very long time to load it on VS2019...

Dotnet Watch Hot Reload

It sometimes forces a manual reload, but I like the experience. VS2022 will have this feature, and will remain in .NET 6 CLI..

Misc.

RNGCryptoServiceProvider

RNGCryptoServiceProvider is obsolete in .Net 6 Preview. Be aware that a lot of examples on the internet still use this class for generating the salt.

JavaScript PBKDF2

There's actually a JavaScript library for handling PBKDF2, so yes, I could've just done it all in CodeSandbox:

import "./styles.css";
import { pbkdf2Sync } from "pbkdf2";

export default function App() {
  let textToHash = "foobar";
  let salt = atob("b9Txti27LxJWX9BejPSaAQ==");
  let result = pbkdf2Sync(textToHash, salt, 27500, 64, "sha256").toString(
    "base64"
  );

  return <div className="App">Hash: {result}</div>;
}

No comments:

Post a Comment