Very often, API versioning is something that is being thought of only when there is a need for changing our API. However, we shouldn't wait until we need such a thing before we implement it. Rather, we should have a versioning strategy, that we will follow while building our API endpoints, right from the beginning of API development.

When we expose our API for use, it is assumed that we have clearly defined the contracts and that the consumers of our API can rely on these contracts. If we make some changes to our API contracts, these should be exposed as a new version of our API. This new version does not mean a new code base of the API. It should be the same code base that supports different versions of an API.

One code base - multiple versions

There are many approaches we can use to implement API versioning. In general, there isn't a good or a bad way when talking about API versioning. Which approach to choose depends on who is using our API, on our overall product development situation (are we starting a new project, or do we need to incorporate versioning to a mature, production API), and on how detailed we want to be with API versioning. Find an option that best suits your needs, and stick with it when building your API endpoints.

If you are familiar with basic versioning concepts, or just want to go straight to the code, I have created a simple example that covers all of the API versioning methods described in this post. This project can be downloaded/cloned from a GitHub repository.

The first step with API versioning is to install Microsoft's versioning package. From package manager console run following command:

Install-Package Microsoft.AspNetCore.Mvc.Versioning

API versioning is achieved by setting versioning configuration in the ConfigureServices method of the Startup.cs file, and by annotating controllers and actions with appropriate attributes.

To activate API versioning, simply add the line services.AddApiVersioning(); to the ConfigureServices method. With this line added, we have activated default API versioning settings, and therefore when calling our API, our clients MUST specify a version in their requests. Otherwise, our API will respond with a BadRequest and ApiVersionUnspecified error. It is a pretty strict rule to require explicit stating of an API version in every request. To make life a bit easier for the users of our API, we need to set a default API version to be used when it is not explicitly stated in the request.

options.DefaultApiVersion = new ApiVersion(1, 0); - This setting is not mandatory, because by default it is assumed that the initial version is set to 1.0. But, it is a good practice to state it explicitly. With DefaultApiVersion being set, all controllers that do not have an API version attribute ([ApiVersion("1.0")]) applied on them, will implicitly bound to this default API version. However, for easier understanding, it is recommended to explicitly apply API version attributes on our controllers.

options.AssumeDefaultVersionWhenUnspecified = true; - DefaultApiVersion just tells us the number of default API version, but we still need to set AssumeDefaultVersionWhenUnspecified to true for our default API version to be activated. Without this setting, any clients that do not specify an API version in their requests would get a BadRequest response with an ApiVersionUnspecified error stating that An API version is required, but was not specified.

Types of API versioning

There are four out-of-the-box supported approaches for versioning a service:

by query string parameter

by HTTP header

by URL path segment

by media type parameter

The default method is to use a query string parameter named 'api-version'. We can also combine API versioning methods or define our custom method of API versioning.

API Version Reader

API Version Reader defines how an API version is read from the HTTP request. If not explicitly configured, the default setting is that our API version will be a query string parameter named 'api-version' (example: ../users?api-version=2.0 ). Another, probably more popular option is to store the API version in the HTTP header. We have also the possibility of having an API version both in a query string as well as in an HTTP header.

The next common versioning method is via the URL path. Version information will be one segment in the URL path of the endpoint. This means that our customers are always explicitly asking for a certain version (by going to that specific URL). In many cases, this is not appropriate, because it is not possible to have a default API version for a URL path segment, and there is no way to configure implicit matching to a certain version.

We can change the parameter name that represents the version (like in the query string method above, where we have used the letter 'v' instead of default 'api-version').

Microsoft's versioning library also supports some other (custom) versioning methods like versioning with Accept Header, versioning with Content-Type Header, versioning with Custom Media Types, versioning by namespaces, versioning by writing our own controller/action resolver. For versioning by Media Type, you can take a look at an example described on Microsoft's official wiki page for this type of versioning. A nice example of more specific versioning, using the Accept Header, can be found on this blog post. These versioning strategies are more specific to implement, and their implementation differs from API to API. Anyway, the most common API versioning methods are with HTTP Header and/or with a query-string parameter, as well as versioning by URL path segment.

Adding versioning informations to controllers and methods

Let us decorate our controllers

After choosing a versioning strategy, and configuring it in the ConfigureServices method, we can start versioning our API endpoints. Microsoft's versioning package provides several attributes that we can apply to our controllers and methods.

When configuring versioning on controllers and methods, these are the rules to follow:

The initial version of a controller may not have any API version attribution and will implicitly become the configured default API version. The default configuration uses the value 1.0.

To differentiate between multiple versions supported by our controller, we annotate controller methods with [MapToApiVersion(...)] attribute. This approach is useful for small version differences (example: [MapToApiVersion("1.0")]).

If we are versioning our API with URL path segment, beside [ApiVersion(...)] attributes we also need to set the URL segment of the route where the API version will be read from:

[Route("api/v{version:apiVersion}/[controller]")]

To deprecate some version in our API controller, we need to set Deprecated flag to true: [ApiVersion("1.0", Deprecated = true)].

It is a good practice to explicitly version all our services. However, if we have a service that is version-neutral, we will mark that controller with [ApiVersionNeutral] attribute.

All of the service API version informations are accessible via extension methods. Beginning in the ASP.NET Core 3.0 version, Model Binding is also supported. So, in our controller methods, we can get the requested API version by calling:

var apiVersion = HttpContext.GetRequestedApiVersion();

And, for getting an API version with model binder, our method would look like:

API Version Conventions

Attributes vs Conventions

Besides attributing our controllers and methods, another way to configure service versioning is with API versioning conventions. There are several reasons why would we use API versioning conventions instead of attributes:

It is possible to use both API version conventions together with versioning attributes at the same time.

There is also an option to define custom conventions. Beginning in .NET Core 3.0, there is a IControllerConvention interface for this purpose. Custom conventions are added to the convention builder through the API versioning options:

options.Conventions.Add(new MyCustomConvention());

Lastly, we can version our API's by namespace convention they reside in:

options.Conventions.Add(new VersionByNamespaceConvention());

The defined namespace name must conform to the API version format so that it can be parsed.

For example, namespacing our controllers like on the following folder structure:

api/v1/UsersController

api/v2/UsersController

api/v2_1/UsersController

would map to the following URL paths:

api/1.0/users

api/2.0/users

api/2.1/users

This was a brief overview of the API versioning in the ASP.NET Core 3.0+. Well configured API versioning can be really useful, both for the users and API developers, and there shouldn't be a reason why not to version every API. If you have read this far, I hope you are more confident about choosing an appropriate way to go with versioning your API.

What is your opinion on this matter?

Have you used API Versioning in your ASP.NET Core projects? Was it useful, and did it save you from problems you might've seen otherwise? Let me know, and share it in the comments!

The Final DrawingEditor Modifications

Our save function will need to exist on the Razor Page code-behind file. Because of this, we require a way for our main DrawingEditor class to use that function as a callback. We also need to be able to create the JSON for the current drawing, and lucky for us, FabricJS provides a way to do exactly that:

Note the saveDrawing() function; this is not implemented quite yet. The next thing we need is to make the page handler that will "process" the POSTed drawing JSON. Since we're not actually doing anything with the JSON, the code is very short:

In a production system, we'd need to persist the drawing JSON to a datastore or database.

In normal circumstances, we'd almost certainly want the OnPostSave() method to return something, be it IActionResult, JsonResult, or just a string.

The Final Script

Now we need to return to the Razor Page and implement the saveDrawing() function to call the new OnPostSave() method. We also need to show and hide the "saving" status message on the status bar immediately below the canvas.

One additional thing Chris decided to do was put some extra code in to prevent "double-click" saving, so our save method can only be called one second after it was last called. You can see all of this code below:

The Last Hotkey

There's one last little thing we should do: since we already have hotkeys for cut, copy, paste, etc. we should implement the hotkey for save (Ctrl+S) as well. Here's the modifications we need to make to DrawingEditor to realize this:

GIF Time!

Let's see how this works in a GIF:

Pay special attention to the lower-right side of the GIF, where the "Saving" message will appear very briefly.

Conclusion

That's it! With this last feature, we have made our drawing canvas match the goal photo from the beginning of the series! Thank you, dear readers, for reading these posts about creating a drawing canvas with FabricJS and TypeScript! Chris and I are pretty proud of this sample, and we hope it helps you all in your projects.

For the final time, don't forget to check out the sample project for this series over on GitHub. It contains the final, working code for this series. Don't be afraid to make pull requests if you see a way we can improve!

We're nearing the end of our Drawing with FabricJS and TypeScript series. In this part, let's add one last set of improvements by implementing cut, copy, and paste functionality as well as hotkey shortcuts for those, plus undo and redo.

We need to fill in each of the methods (other than the constructor, which for this class doesn't have an implementation; it just gets an instance of DrawingEditor).

Let's start with copy(). When we copy an object, we place a copy of it in memory so that it can be pasted later. In this particular case, we need to get the active object on the FabricJS canvas, clone it, and then set it to the memorizedObject property of Copier. Plus, we have an optional callback method that needs to be executed, if it is not undefined. Here's how that looks:

The callback method becomes immediately useful, because we now need to implement the cut() method. Cut is really just copy and then delete, so our cut() method will pass a function that deletes the selected object after it is cut. Here's the implementation:

cut() {
this.copy(() => this.editor.deleteSelected());
}

The last part of this is the paste() method. In this method, we clone the memorized object, add it to the canvas, and re-render the canvas. Here's the code:

But wait! There's currently no way the user can actually use this functionality! For cut/copy/paste, we aren't going to add display components to the toolbar. Instead, we're going to enable hotkeys (e.g. Ctrl+X, Ctrl+C, Ctrl+V).

Hotkeys

Not only will we enable hotkeys for cut, copy, and paste, we'll also enable them for undo (Ctrl+Z) and redo (Ctrl+Y). To start, we need our DrawingEditor class to be aware of the key codes for each of the letters. One of the ways we can do this is by using a very neat site called keycode.info. Here's the keycodes for X, C, V, Z, and Y:

TypeScript defines for us a KeyboardEvent class which represents an event where the user pressed a key on the keyboard. That event also tells us if the Ctrl key was pressed during the event. We can use this class to initialize our key code events:

That's all we need to do for hotkeys! Now the user can cut, copy, paste, undo, and redo using the keyboard shortcuts for those events! This is difficult to put into a GIF (because you wouldn't be able to see what keyboard shortcut I was using), so there won't be one for this part of the series.

In this part, we're going to further improve our drawing canvas by adding an undo/redo functionality. To accomplish this, we have to implement a state manager system which keeps track of the various states of the canvas and the objects on it. It's not as bad as it sounds, I promise. Let's go!

The State Manager

In order to accomplish this undo/redo functionality, we need a class that will keep track of the various states of the drawing canvas. Said class will need to keep a representation of the canvas in JSON, so that said representation can be easily restored.

Lucky for us, FabricJS already provides a way to get the JSON for the canvas: the method toDatalessJSON(). By using this method, we can get the complete state of the canvas at any given time.

The state manager itself will need to keep a stack of states, so that we can pop off the top state to undo. It will also need to keep a separate stack of popped states, so that we can redo.

The method saveState() is used as a shortcut method to allow other methods to a) save the current state and b) render all objects on the canvas again. saveState() needs to be used in quite a few places, most notably whenever a canvas object is modified, created, or deleted.

class DrawingEditor {
//...Properties and constructor
private initializeCanvasEvents() {
//...Other events
this.canvas.on('mouse:up', (o) => {
this.isDown = false;
switch (this.cursorMode) {
//If the cursor mode is currently Draw when a mouseup
//event occurs, we have just finished dragging to
//create that object. Hence, we need to add the new
//state of the canvas to the state manager.
case CursorMode.Draw:
this.isObjectSelected = false;
this.saveState();
}
});
//If an object has been modified at all, save the new state
this.canvas.on("object:modified", (e) => {
this.saveState();
});
}
//This method is called by the DeleteComponent from Part 5.
deleteSelected(): void {
this.canvas.remove(this.canvas.getActiveObject());
this.canvas.renderAll();
this.saveState();
}
//...Other methods
}

Our DrawingEditor will now save the state of the canvas whenever objects are changed, created, or deleted. But we still need toolbar items for undo/redo. Guess what that means? We need some new display components!

Creating the Custom Image Dropdown

Drawing is an inherently visual endeavor, and due to this Chris felt that we needed an appropriately visual selector for the colors, line styles, and fills. Hence he created something he termed an Image Dropdown, a class which shows you little images instead of text for each selectable object, and can be used for multiple types of selections.

But before we can use it, we have to make it. And we need some basic stuff to start. Basic stuff like a class to represent each option in the Image Dropdown...

class ImageOption {
display: string;
value: any;
text: string;
}

...a class to represent the options we need to select to render the image dropdown itself...

But now we come to the most difficult portion of this implementation: the attachEvents() method.

attachEvents() Method

Whenever an element in the Image Dropdown is clicked, we need to ensure that the next objects which will be drawn in the canvas are drawn with the selected line color, fill color, or style. Plus, the item that has been selected must appear in the "viewable" portion of the display, just like in a standard drop down.

With that in mind, let's see the annotated code for the attachEvents() method.

Most of this code probably doesn't make much sense yet, but I promise it will.

We have now fully written our reusable ImageDropdown class! Time to implement a few instances of it.

Line Color and Fill Color

We can demonstrate how to use our new ImageDropdown class by implementing a way for the user to select the line color and fill color for the lines, shapes, and text they want to draw.

We're making a couple assumptions about this element:

There will only be a certain number of colors available. The user won't pick from a color wheel (though this would be an excellent improvement if you, dear reader, want to make a pull request for it) AND

The same set of colors will be available for lines and fill color.

Let's build a reusable display component that will make use of ImageDropdown and let the users choose colors! Here's the code for our component.

NOTE: In the above code and in many other places throughout this series, you may see constructors that have readonly parameters. In TypeScript, this is the same as instantiating a property for the class that contains that constructor, and so we don't need to define a property. I did not know this before starting this series, and I can see how it's a useful feature to have. See the docs for more info.

Just like our earlier display components, we need to modify the base DrawingEditor class and the Razor Page markup and script to wire up the new ColorChooserComponent. But this time, there's some extra changes that also need to be made.

In DrawingEditor, because it is that class which is aware of the brush currently being used to draw objects, we need to modify that brush whenever a new fill color or line color is selected. This is in addition to adding the new line/fill components to the addComponents() method, like we did for the other ones. Here's the changes to DrawingEditor for both of these:

GIF Time 1!

Now we can finally run the app, and use our new line color and fill color pickers! Here's a GIF that shows these features in action:

But wait, we're not done yet! Now let's see how to change the line styles and width.

Line Styles

Our requirements for this project specified that we needed a way to change the line "style" of the shapes. That is, we needed to allow the user to draw dotted, dashed, or solid lines. So, let's build a component to do this!

In FabricJS, there is a class called BaseBrush, which represents the brush being used at any given time to draw objects. BaseBrush contains two properties we will need to use: strokeLineCap and strokeDashArray.

strokeLineCap sets the line ending of the line being drawn; in our case, we only use the value "round".

strokeDashArray sets the properties of the dashes being drawn as part of a line. This allows us to set the size of the dashes. Our requirements specify that we need both dotted and dashed lines, so we will use strokeDashArray to create each of these.

GIF Time 2!

Guess what? It's GIF time again! Let's see how the new LineTypeComponent looks:

Woohoo! Almost there! There's only one thing left we need to do, and that's to create a component which allows the user to choose the thickness of the line being drawn.

Line Thickness

Given that you, dear reader, have probably seen this pattern many times by this point, I'm going to give you the short version of implementing this component. First, we need the new component class, LineThicknessComponent:

Implementing the DeleteComponent

We're going to implement this delete functionality a bit backwards from the way we've implement other functionality: we're going to write the component first, then integrate it with the drawing editor.

Our component will exist in the toolbar, but needs to only be active when an object is selected; otherwise it should be disabled. Further, this isn't going to be the only component that changes the canvas: later in this series we're going to implement undo/redo functionality. So, we need a "base" class for all components that will do non-drawing functionality.

Chris termed these components ControlComponents, and implemented the following abstract class:

Modifying the Markup and Script

There's something little bit strange about FabricJS's Canvas object: it doesn't provide events for keydown or keypress, so we have to wire those events up against the page, and then call the appropriate methods in the DrawingEditor class.

Here's the markup changes and script changes we need to make in our Razor Page. Note that the delete button will sit by itself on the leftmost side of the toolbar:

With all of these changes in place, we can now write text onto our canvas, as shown in this GIF:

Note that our implementation did not require us to change things like the text font, size, style, or color, and so I leave those kinds of improvements up to you, my dear readers.

Let's also take a few minutes to implement another useful FabricJS feature: polylines.

Freeform Lines (AKA Polylines)

"Freeform" lines are lines which are drawn freely onto the canvas: think using the pencil tool in Paint. FabricJS terms these "polylines" because in reality a "freeform" line consists of many tiny straight lines that combine to form what looks like curves. These straight lines are created by storing a list of ordinal points, between which lines are connected (essentially like playing a giant version of connect-the-dots).

As with Text, we need two parts: a drawer and a display component. Here's the drawer class:

GIF Time!

All of this together allows us to draw freeform lines, as shown in the below GIF:

Ta-da! Now we have some very useful tools added to our FabricJS canvas toolbox!

Summary

Just like with the basic shapes, for both Text and Polylines we needed to implement a drawer and a display component. Those classes then needed to be wired up to the main DrawingEditor class, and into the Razor Page markup and script.

Initializing the Display Components

Before we can build more shape drawers, we first need a way to display the existing drawers in a "toolbar" so the user can select which one they want. We need a lot of pieces to make this work, so let's get started building them.

The first thing we need is a class that represents each displayed option. We are calling these classes "display components" and we need a base one from which all specific components can inherit. This class will need some properties that allow us to set up things like the CSS classes and icon displayed, as well as set the Drawing Mode.

Here's the annotated code for this base class, called DisplayComponent:

This class implements an SVG definition for the component's icon, and saves the alt text, before using super() to call the parent class DisplayComponent's constructor.

Showing the Display Components

We're halfway to being able to, ahem, display the display components. Now we need to make some changes to the main DrawingEditor class.

We want our DrawingEditor (which, as a reminder, represents the drawing area as a whole, including our display components) to be able to initialize components at creation time. To do this, we're going to create two methods:

The method componentSelected() needs to be implemented on DrawingEditor. We do that like this:

class DrawingEditor {
//...Properties and Methods
componentSelected(componentName: string) {
//Deselect any objects on the canvas that are selected
this.canvas.discardActiveObject();
//FOREACH component in the drawing editor...
for (var key in this.components) {
// IF this component has a property with the passed-in name
// THEN do nothing
if (!this.components.hasOwnProperty(key)) continue;
//OTHERWISE...
const obj = this.components[key];
//IF the component with the passed-in name
//IS the component we expect
if (obj[0].target === componentName) {
//SET the drawing mode to the drawing mode
//needed by the component
this.drawingMode = obj[0].drawingMode;
}
//IF the method selectedChanged is defined on the component,
//THEN call that method
if (obj[0].selectedChanged !== undefined) {
obj[0].selectedChanged(componentName);
}
}
}
}

HTML and Script

We have one last piece we need to do to set up our first display component: we need to insert some HTML and some JavaScript on our Razor Page where we want to make a drawing.

Next up in this series, we'll make a new component that will allow us to delete objects from the canvas, and implement hotkey functionality for the same. Check out Part 3 of Drawing with FabricJS and TypeScript!

Our drawing canvas is now created, but it doesn't do anything yet. In this part of our series on creating a drawing canvas with FabricJS and TypeScript, we're going to refactor our drawing editor to draw what might be the simplest kind of shape: a straight line. Unfortunately, doing such a thing is not as easy as it sounds.

Fabric Objects, Drawers, and DrawingMode

FabricJS has a concept of "objects" or two-dimensional things that have been placed onto the drawing canvas. In FabricJS, ALL 2D objects inherit from a base "Object" class. Objects can then implement certain events.

In this tutorial, we have a concept of "drawers" or classes that create objects. For each kind of object that can be drawn onto the canvas, we will have a "drawer" class which is responsible for creating the object, which in turn inherits from Fabric.Object. Each of these drawers should therefore implement an interface, one which allows them to "draw" the object they represent.

Note that this interface expects the classes that implement its methods to return a Promise<fabric.Object> for both the make() and resize() methods.

Also note the drawingMode property. This is an enum which tells the drawing canvas which mode we are currently in (alternatively, which shape will be drawn on the next mouse event); this allows the user to draw a single shape or line multiple times without needing to set the drawer again. The values are as follows:

Note that we are using the Fabric.Line class, which is FabricJS's implementation of a straight line. Wherever possible, we will use the FabricJS definitions for our classes.

We now have a class that will draw straight lines for us! Now what we need to do is create events that our canvas can listen to, which will allow the user to actually draw the lines.

Canvas Properties

At this point in the tutorial, we need to make some changes to the root DrawingEditor object we created in Part 1.

The first thing we need to do is allow the drawing editor to keep track of which drawer class is currently being used, as well as all the possible drawer classes that can be selected. For this, we need to modify the DrawingEditor class like so:

These changes will allow us to modify which drawer is currently selected based on some kind of user input. You'll see specific demos of this in later parts of the series.

Let's now discuss exactly how we want the user to interface with the canvas in order to draw a line.

User Interactions and Events

For this tutorial series, we're going to specify that a user draws an object by clicking down the mouse button, dragging the cursor to a new location, and then releasing the button. In this way, our drawing canvas will behave like many other drawing applications, using a "click-drag-release" pattern.

That means we must define "events" for each part of this sequence: mouse down (click), mouse over while holding button (drag), mouse up (release). We also need to specify what happens if the user is clicking-and-dragging the mouse over an-already created object, where the already-created object should not be modified in any way.

The problem is the "dragging". We need a way to tell the canvas that the user is currently holding down the mouse button, and therefore certain interactions should be modified. We do this by adding a new property to the DrawingEditor class:

When the user clicks the mouse within the canvas, the drawer should begin to draw an object starting from the point where the mouse was clicked. Fabric provides us with the MouseEvent class to represent mouse events, as well as a canvas.getPointer() method we can use to get the current position of the mouse pointer at the time of the event. By getting the MouseEvent and the pointer location, we can initialize an event and call our mouseDown() method like so:

MouseUp Event (Release)

Example Lines

With all of the events in place, we can now draw straight lines! Here's a GIF of this code in action:

Bug: Drawing Lines when Moving Objects

We've done quite a lot so far! However, there's a problem with our current implementation: while trying to drag an already-created object (a function which Fabric supports natively) we will accidentally draw another line! It looks like this:

We need to do some additional work to ensure this situation doesn't happen.

First, we need to keep track of what "mode" the cursor is in at any given time. This means we need to know if it is currently drawing or selecting an object. Hence, we need a new enumeration:

const enum CursorMode {
Draw,
Select
}

We also need our DrawingEditor object to keep track of the current CursorMode:

Finally, we need two new events: one in which when an object is selected the cursor mode is changed to Select; and one in which when the selected object is "cleared" (i.e. no longer selected) the cursor mode is reset to the default Draw.

GIF Time!

With all of this in place, we no longer draw lines when moving already created objects, as shown by this GIF:

Summary

In the second part of our Drawing with FabricJS and TypeScript series, we used our previously-created DrawingEditor object repesenting a canvas and refactored it to code up the ability to draw straight lines. In the process, we learned about "drawer" classes and mouse events, and which ones we needed to implement. We also encountered and fixed a bug that happened when dragging already-created lines.

In the next part of the series, we'll start working on drawers for basic shapes, including ovals and rectangles, as well as for text. We'll also need to work out a way for the user to select which drawer they want to use. For all of that, check out Part 3 of Drawing with FabricJS and TypeScript!

Given how often I've mentioned it recently, my dear readers, you are probably aware that my team and I have been working on a new project. Said project's primary goal was to replace an application that has been in use for many years at our company, in which users could create "drawings" of basic shapes, lines, text, and colors to map out where certain things should be placed at their facilities (think along the lines of an emergency-exit map).

In the process of developing this application, my team and I settled on using a JavaScript library called FabricJS to implement the drawing portion. FabricJS is a library which enables, according to their own site, an "interactive object model on top of canvas element" and, more importantly for us, the ability to save drawings in the JSON format. It was a no-brainer.

It also occurred to us that there weren't any good, long-form tutorials about how to use FabricJS, so that's what I'm writing here. For this post and the next eight, we're going to see how to develop a drawing application using FabricJS and TypeScript.

Credit and Caveat

Before we get started, I need to give credit where credit is due: the code used in these samples was originally developed by my teammate (and fellow long-haired dude) Christopher Jestice. He gave permission for me to use this code and credit him. Refinements to his original code base (as well as certain changes made just for this series) are by me, so we consider these examples a truly joint effort.

Further, Chris and I want you dear readers to know the following: neither of us are intimately familiar with the workings of TypeScript. We chose it because of its similarity to our most-familiar language C#. If anyone out there has suggestions on how to improve the code we use in these posts, please feel free to let us know in the comments.

Goals

The main goal of this blog series is to create a drawing canvas, using FabricJS and TypeScript, which can do the following things:

Draw straight lines

Draw basic shapes (ovals, rectangles, triangles) and text

Draw freeform lines

Use colors for lines and fill

Use a few line styles (e.g. dotted, solid, dashed)

Display status messages

Implement cut/copy/paste with hotkeys

Have an undo/redo feature with hotkeys

Have a "save to server" feature with hotkey

More specifically, we want our final canvas to look like this:

By the end of this nine-part series, our canvas will fully implement all of the above features.

The Sample Project

As with all my code-based posts, this series has a sample project hosted on GitHub. Check it out!

Without any further ado, let's get started building our drawing canvas with FabricJS and TypeScript!

Setting Up TypeScript

Before we can create the TypeScript classes to represent our drawing, we need a tsconfig.json file to give the TypeScript compiler a group of settings. Here's a shortened version of the one this sample project uses:

The two important properties to notice are the "lib" property and the "outFile" property. The "lib" property sets a list of TypeScript library files that need to be included in the compilation; because this project will use some pretty recent features, our list includes "es2015" for ECMAScript 2015 and "dom.iterable" for iteration properties.

Setting Up Libraries

There is some additional setup we need to do: we need to include the libraries for FabricJS, jQuery, Bootstrap, and a few typings for TypeScript. How you choose to include these libraries is up to you; Chris and I both use Visual Studio, and as such we chose to use the unimaginatively-named Library Manager (LibMan) extension. Here's the libman.json file we used:

Note the "destination" settings for the jQuery and FabricJS typings: they are included in the DrawingEditor directory, which is where we will place our TypeScript classes.

The Starting Markup

We can now start building the markup and script for our drawing canvas.

(NOTE: For this series, we are using ASP.NET Core Razor Pages. If you are unfamiliar with this tech stack, check some of my other posts about it. The markup won't be terribly different in other stacks, I believe.)

FabricJS uses a Canvas element to represent the drawing area. In our case, we want our canvas to use up as much of the visible area of the page as possible, so we are going to create the canvas in a sort-of roundabout way.

Notice: there's no Canvas element! That's because we're going to replace that innermost div with the Canvas when we create our drawing class in TypeScript. In other words, the innermost div is just a placeholder.

We now need a TypeScript class to represent the drawing area itself. This class needs to be able to replace the inner div with the markup for a FabricJS canvas, as well as create that canvas to a specified size. Here's the typescript for that class:

The Example Page

With all our pieces in place, we can now run the project. The drawing page gives us the following screenshot:

It's not quite what we saw in the goal photo earlier in the post, but it's a start. The real test is to check the markup.

See the markup in the red box? It shows that a new div, one with class "canvas-container" was inserted where our innermost div was previously, and within the new div are two canvas objects. This is a function of how FabricJS behaves.

We did it! We created a brand new FabricJS canvas onto our Razor Pages app! But it doesn't actually do anything yet, and in the next part of this series, we'll add some very basic line-drawing functionality to our new canvas.

This time, we wanted a way to build a cascading drop down list using Razor Pages and jQuery, and after a little bit of trial and error settled on this method of doing so. Come along with me as we see how to wire up a jQuery AJAX request in ASP.NET Core Razor Pages using a new feature, termed Named Handler Methods. Let's go!

The Sample Project

As always with my code-focused posts, there is a sample project for this post over on GitHub. Check it out!

Implementation details are over on GitHub. Be warned: they are not very fancy.

So we already have the ability to get a list of countries for a specific continent. What we are going to do now is use Razor Pages, and specifically the Named Handler Methods feature, to wire up an AJAX request to get the countries for a specified continent.

Named Handler Methods

We already know from previous posts about ASP.NET Core Razor Pages that each page supports two methods by default: OnGet() and OnPost(). These methods are often the "normal" way of allowing a page to GET and POST data to and from the server.

In fact, Razor Pages supports other method formats as well. For example, this would be a supported method name:

public IActionResult OnGetListContinents() { }

The key part is the OnGet prefix; this tells ASP.NET Core that this method is expected to respond to a GET request. Please note that any parameters to these methods do not distinguish them as far as ASP.NET Core is concerned, so having the methods OnGetListCountries() and OnGetListCountries(string continent) on the same page will cause an InvalidOperationException to be thrown when the methods are invoked.

This syntax is called Named Handler Methods, and you can read more about their implementation on the official docs site.

Creating an AJAX Request with Named Handler Methods

Now for the real meat of this post: given that we can use Named Handler Methods in Razor Pages and that we have a data access layer, how can we create an AJAX request to get the countries for a given continent?

First, we need to create the named handler method itself. It looks like this:

Note the call to @Url.Page(). This code is using the IUrlHelper interface to generate the URL to the /Index page, the page we are running this script on. We could also not use that call at all, in which case the invocation would be this:

However my "official" solution includes the call to IUrlHelper because such a call is going to work on many different pages, not just the ones that map to the default URL of "~/".

The last thing to do is to fill out the success() function. We need to remove all existing items in the Countries select list and repalce them with the values retrieved during the AJAX call. We can do that like this:

We're done! Now we have a cascading drop down list for continents and countries, all using Named Handler Methods and jQuery Ajax.

Summary

In ASP.NET Core Razor Pages, we can wire up jQuery AJAX calls with server-side Named Handler Methods to provide a way to query for data without needing to POST the entire form or page. In this way, we can build nice cascading drop down lists, and other user-friendly controls.

My team is continuing to work on another large project, and this time we're using ASP.NET Core with Dapper as our main data-access tool. It's no secret that I'm a fan of Dapper, and once again something we ended up implementing in our projects might be useful to you, my dear readers.

In this post, I'm going to show how we implemented a "base" Dapper repository class with common functionality in our ASP.NET Core project, in the hopes that someone out there (which will most likely be future me) can make use of it.

Let's get started!

Background

We noticed, as we have continued building this new, large ASP.NET Core system, that many of our repository classes needed similar or even identical functionality. Most of said repos had methods such as GetByID(), and many shared other common methods like GetForUser() or Search(). Problem was, these classes got very large, because of all the boilerplate code necessary to get Dapper running and to log exceptions within each method.

My team and I decided that we needed a way to try and "shrink" these classes, with the goal of improving their readability, and being object-oriented programmers, agreed that a "base" class would be the best way to share functionality.

It occurred to my team and I that the actual functionality all of these repository classes shared was querying the database, and that if we could reduce that down to a set of defined methods we could implement them in the base class and share them to all repositories. We also wanted logging at that level, since it was possible that queries could be generated that, for example, should have gotten exactly one item from the database but actually got zero.

A "Regular" Repo

Here's an example of a C# repository class that does not include a base Dapper repo.

All by itself, this isn't very complicated or difficult to read. Refactoring this to use a "base" Dapper repository would be a waste of time if this repository was the only such data access class in our system.

But imagine that you have, as we do, a great many of these repositories. Large systems that I've worked on have had twenty, thirty, or even more of these. All of them have at least a GetByID() method or similar functionality, and many of them have other methods in common as well. Further, in a "normal" app each of them have to log something every time querying the database goes wrong.

So how can we combine the common functionality (e.g. logging) in a way that allows us to clean up our code? By implementing a "base" Dapper repository class.

The Base Dapper Repository Class

To achieve our goals, we wrote the following "base" Dapper repository class in C#:

This class allows us to call the methods Query<T>(), QuerySingle<T>(), and QueryFirst<T>() to get information out of our database. You can add more methods to it: for example, you might want asynchronous calls, or to include the QueryFirstOrDefault<T>() and QuerySingleOrDefault<T>() methods.

Whatever methods you end up using, the point is that all the other repositories, once they inherit from this "base" one, get considerably cleaner and easier to read. Here's that SampleRepository C# class from earlier, refactored to use the new "base" Dapper repo.

Again, this isn't terribly different from the first, non-refactored repository. If this were a new project that I was assigned to, and I encountered this repo inheriting from a base class, I'd happily refactor that base class out. But when you have twenty, thirty, or more repositories, each calling the same database and needing similar methods, the amount of code you save and the clarity of the code you write both improve dramatically.

Drawbacks

There are a couple of minor drawbacks to this architecture.

First, you are introducing dependencies. Each class which inherits from the base Dapper repo must pass the injected values (In our case, ILogger and IDbConnection) to the base repo's constructor. If the base repo's constructor ever changes, you are going to need to refactor all the child repos as well.

Second, at the moment there is no way to say what child repository submitted the query that caused a logged exception. You can solve this many ways (we ended up merely passing the name of the child class into the base class constructor).

All that said, though, this architecture has proven rather resilient and useful for me and my team. I hope it will for yours, as well.

Summary

By implementing a "base" Dapper repository class in our ASP.NET Core projects, we allow many data-access classes to use a common set of functionality, and we can log issues when they arise. With minor improvements, this architecture can become the backbone of your ASP.NET Core app's data access strategy!

If you are a C# developer, chances are you have heard about this new .NET Core thing and the new version of the ASP.NET framework. You can continue to work with ASP.NET Web API or any other framework from the old ASP.NET you've known for years. But, ASP.NET Core is here to stay.

In case you missed it, "ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-based, Internet-connected applications". "ASP.NET Core is a redesign of ASP.NET 4.x, with architectural changes that result in a leaner, more modular framework".

Don't worry if you haven't started to work with ASP.NET Core yet. This is a new framework with lots of new features, but it has brought many other features from the previous version. So, you will feel like home.

ASP.NET Core has been created with other operating systems and IDEs in mind. Now you can create a project, compile it, and run the tests from the command line. For example, to create a new empty Web project, you can use $ dotnet new web

Where is the packages.config file?

If you installed a NuGet package into your brand new ASP.NET Core project, one thing you could notice is the missing packages.config file. If you remember, it is an xml file that holds the packages installed. But, where in the world are those packages referenced now? In the csproj file of your project.

Nuget packages are referenced under ItemGroup in a PackageReference node. There you are Newtonsoft.Json! Goodbye, packages.config!

Wait! What happened to the csproj file?

Csproj files have been simplified. Before, a csproj file listed every single file in the project. All your files with .cs extension were in it. Now, every .cs file within the folder structure of the project is part of it.

Before, things started to get complicated as time went by and the number of files increased. Sometimes, merge conflicts were a nightmare. There were files under version control not included in the csproj file. Were they meant to be excluded because they didn't apply anymore? Or somebody tried to solve a merge conflict and forgot to include them? This problem is no more!

Where is the Web.config file?

Another missing file is the Web.config file. Instead you have a Json file: the appsettings.json file. You can use strings, integers and booleans in your config file. There is even support for sections and subsections. Before, if you wanted to achieve that, you had to come up with a naming convention for your keys. For example, prepending the section and subsection name in every key name.

Probably, you have used ConfigurationManager all over the place in your code to read configuration values. Now, you can have a class with properties mapped to a section or subsection of your config file. And you can inject it into your services.

You still need to register that configuration into the dependency container! More on that later.

Additionally, you can override keys per environment. You can use the name of your environment in the file name. For example, appsettings.Development.json or appsettings.QA.json. You can specify the current environment with an environment variable or in the launchSettings.json file.

There's even support for sensitive settings that you don't want to version control: secrets.json file. You can manage this file from the command line too.

Where is the Global.asax?

Yet another missing file: Global.asax. You used it to perform actions on application or session events. For example, when application started or ended. It was the place to do one-time setups, register filters or define routes.

But now we use the Startup.cs file instead. It contains the initialization and all the settings needed to run the application. A Startup.cs file looks like this:

It has two methods: ConfigureServices and Configure. The Configure method replaces the Global.asax file. It creates the app's request processing pipeline. This is the place to register a filter or a default route for your controllers. And the ConfigureServices is to configure the services to be injected into the dependency container...Wait, what?

A brand new dependency container

Prior to ASP.NET Core, if you wanted to apply dependency injection, you had to bring a container and roll the discovery of services for your controllers. For example, you had an xml file to map your interfaces to your classes or did some assembly scanning to do it automatically.

Now, a brand new dependency container is included out-of-the-box. You can inject dependencies into your services, filters, middlewares and controllers. It lacks some of the features from your favorite dependency container, but it is meant to suit "90% of the scenarios".

If you are familiar with the vocabulary from another containers, AddTransient, AddScoped and AddSingleton ring a bell. These are the lifetimes of the injected services, ranging from the shortest to the largest.

More specifically, a transient service is created every time a new instance is requested. An scoped service is created once per request. Plus, a singleton service is created only once per the application lifetime.

To register your services, you have to do it inside of the ConfigureServices method of the Startup class. Also, you bind your classes to a section or subsection of the config file here.

Conclusion

You have only scratched the surface of ASP.Net Core. You have learned about some of the changes AspNet Core has brought. But, if you haven't started with ASP.NET Core, go and try it. You may be surprisedby how things are done now.

I've written before about implementing a pattern known as POST-REDIRECT-GET in my ASP.NET MVC apps, and since my team and I are working on a new ASP.NET Core Razor Pages project I thought it might be useful to see if such a pattern can be implemented there.

If the user performs a valid search, they get results, just like we would expect:

However, when they try to refresh the page, they get this:

This is not a great user experience. For one, it "breaks" the back button; once a search is performed if the user presses the back button that popup will appear. For another thing, you cannot send a URL of search results to someone else; anyone who wants to do the same search you did will have to come to this page and manually perform that search.

We can improve this by implementing the POST-REDIRECT-GET pattern, slightly modified for ASP.NET Core Razor Pages.

The POST-REDIRECT-GET Pattern

In order to implement PRG in our Razor Pages app, we make the search parameters inputs to our OnGet() method, and only do a redirect in OnPost(). The final code looks something like this:

But now, clicking the back button actually takes us back to the page before we did the search. Further, the URL for this results screen now includes a query string, which may look like this

/?country=UnitedStates

This means that we can now send this search to other people as a URL, and when they click it, the search will be performed again with no input from them. Overall, the PRG pattern results in an improved experience for our users.

The key part of the PRG pattern is that the inputs to the search need to be parameters to theOnGet() function, and the OnPost() function must redirect back to the same page using RedirectToPage().

Summary

We can remove the annoying "Confirm Form Resubmission" popups and make our user experience just that much better by using the POST-REDIRECT-GET (PRG) pattern in ASP.NET Core and Razor Pages. Remember the following in order to implement PRG:

Make the parameters to the search inputs to the OnGet() function.

Ensure the OnPost() function redirects back to the search page using RedirectToPage().