bradygaster.com

Brady Gaster is a Christian dad who lives near Seattle, Washington. At work, he and his amazing colleagues work together to make it fun for .NET developers to party in the cloud. At home, he tinkers with MIDI hardware and makes loud music amidst a hurricane of wires.

Since downr is built using Blazor WebAssembly, I'll be loading components into areas of the page. Given I wanted to continue to use Google Analytics to track each page (and component) load, simply slapping the Google Analytics tracking JavaScript code on my index.html page isn't sufficient. I'll need to track traffic on a component-by-component basis. This post walks through the usage of the Google Analytics feature in downr, and describes how I built it.

How to enable Google Analytics in downr

Enabling GA support is as simple as changing one setting in appsettings.json. Here's my file before I added GA support:

{
  "downr": {
    "title": "bradygaster.com",
    "rootUrl": "https://bradygaster.com",
    "pageSize": 4,
    "author": "brady gaster",
    "indexPageText": "Hi! I'm a christian dad who lives near Seattle, works at Microsoft with the talented folks on the .NET team, tinkers with MIDI hardware, and makes loud music with computers.",
    "imagePathFormat": "https://bradygasterdotcom.azureedge.net/posts/{0}/media/"
  }
}

Here's the appsettings.json file with support added:

{
  "downr": {
    "title": "bradygaster.com",
    "rootUrl": "https://bradygaster.com",
    "pageSize": 4,
    "author": "brady gaster",
    "indexPageText": "Hi! I'm a christian dad who lives near Seattle, works at Microsoft with the talented folks on the .NET team, tinkers with MIDI hardware, and makes loud music with computers.",
    "imagePathFormat": "https://bradygasterdotcom.azureedge.net/posts/{0}/media/",
    "googleTrackingCode" : "UA-133394-2"
  }
}

Once downr users add a value for the googleTrackingCode, Google Analytics lights up. It's that simple.

Tracking code in components? No.

The first thing I thought was, let's put the tracking code into each component. This was far too easy a solution to really work. What if I build in more features over time, resulting in nested components? I don't want to repeat the same JavaScript code at various points throughout the site - that'd get bloated quickly.

Not to mention the fact that the Razor compiler knows this isn't a good idea and lets me know pretty clearly why.

Tracking script error in a .razor file

Thanks, team, for saving me from doing something not-quite-right here!

How tracking was implemented

The implementation wasn't too complex. Before I wrote the code to support it, I established a few assumptions & goals:

  1. I'm going to want to add support for Azure Application Insights, so whatever I do, I need it to not "tie" me to Google Analytics as my only means of tracking.
  2. downr users will want to easily configure their own GA code.
  3. The tracker should be reusable in other components.

The first step was to add the configuration property to the DownrOptions class, which provides IOption<T>-style configuration throughout the downr's components, services, and controllers.

/// <summary>
/// This value is optional. If it is provided in your configuration, the Google tracking
/// JavaScript code will be injected into your pages.
/// </summary>
/// <value></value>
public string GoogleTrackingCode { get; set; }

The index.html page needs to be outfitted with the remote script enabling Google Analytics tracking to occur. This is okay for index.html - I'm not actually executing the tracking behavior, just including the script as a dependency.

<script async src='https://www.google-analytics.com/analytics.js'></script>

I'll also add a small JavaScript function to site.js. This code executes the GA tracking functionality. By wrapping the tracking code in this manner, the Blazor components can use the IJSRuntime service to call the tracking script when they load.

window.trackWithGoogle = (ua) => {
    window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
    ga('create', ua, 'auto');
    ga('send', 'pageview');
};

The Tracker.razor component code is obviously very minimal - it serves the purpose of executing the tracking code if I've enlisted in it via configuring my site for it. Tracker's implementation leaves room for me to dial in another tracker when I'm ready.

@inherits ComponentBase
@using downr
@inject DownrOptions options
@inject IJSRuntime JSRuntime

@code {
    protected override async Task OnInitializedAsync()
    {
        if(!string.IsNullOrEmpty(options.GoogleTrackingCode))
        {
            await JSRuntime.InvokeVoidAsync("trackWithGoogle", options.GoogleTrackingCode);
        }
    }
}

By configuring my site with the googleTrackingCode property, I enlist in GA tracking, and the trackWithGoogle script is called each time any component including the Tracker component renders.

Tracking per-component

Now, I can include Tracker in my other components. The list isn't long - downr only has two (currently) main pages:

  • Index.razor, which renders the list of posts
  • Posts.razor, which is what you see when you click to read a post

Tracker is included both at the bottom of Index.razor to track when the home page is loaded:

    <button id="loadMorePostsButton" class="btn btn-secondary btn-center" @onclick="OnLoadMoreButtonClicked">more</button>
  </div>
</div>

<Tracker/>

And at the bottom of Posts.razor, so each click-through to an article can be tracked.

@page "/posts/{slug}"
@using downr.Models
@inject HttpClient Http
@inject Microsoft.Extensions.Options.IOptions<downr.DownrOptions> downrOptions

<div class="text">
    <h1 class="display-4">@Post.Title</h1>
    <div id="post">
        @((MarkupString)Post.Content)
    </div>
</div>

<Tracker/>

Summary

When you have needs for tracking scripts within a Blazor app, there are definitely some things you'll need to consider, but there are also some great customization opportunities for how you track behavior and traffic in your site. This post examines how I accomplished tracking with downr. Soon I'll add support for Azure Application Insights (or I'll accept a pull request if you'd like to implement it), and add a subsequent blog post describing how you can enlist.

 

Creating new posts

posted one year ago in downr

As mentioned in the introduction, one of the goals of downr is that it feels natural for developer bloggers who use Visual Studio Code and the .NET CLI. As such, we've created a .NET tool that contains a blog post template.

Install the downr tools

To make your downr blogging experience feel as natural as developing with .NET Core, run the following command to install the downr CLI tools.

dotnet new --install downr-tools::1.0.0

Installing the tools will place a simple template into your dotnet new template list named post.

Create a new post

With the tools installed, creating a new post is simple. Open a terminal window in the wwwroot\posts folder of your site and execute this dotnet new command:

dotnet new post --output new-post

This will create a the following folder structure underneath your posts folder:

|-- posts
    |-- new-post
        |-- index.md
        |-- media
            |-- placeholder.png

The index.md file will contain the defaults if you don't provide any parameters. From executing the command above, you'd get an index.md with this content:

---
title: My new downr blog post
slug: my-new-downr-blog-post
author: author-name
lastModified: 2020-01-19 12:15:38
pubDate: 2020-01-19 12:15:38
categories: blog,post,article
description: This is a description of the post.
---

Your content here in [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) format.

![Sample image](media/placeholder.png)

Post template CLI parameters

If you'd prefer to use the template's CLI parameters to set your metadata up front, you can find out descriptions of the parameters via the dotnet new post --help command, which results with the following output:

Options:                                                                                                      
    -t|--title        The title of your blog post                                                               
                        string - Optional                                                                         
                        Default: My new downr blog post                                                           

    -s|--slug         A URL-friendly slug that will make your post easy to find                                 
                        string - Optional                                                                         
                        Default: my-new-downr-blog-post                                                           

    -au|--author      The name you wish to be recognized by on the blog                                         
                        string - Optional                                                                         
                        Default: author-name                                                                      

    -c|--categories   A comma-separated list of categories in which your blog will appear                       
                        string - Optional                                                                         
                        Default: blog,post,article                                                                

    -d|--description  A description of your site. This will be used in the site RSS feed to introduce your post.
                        string - Optional                                                                         
                        Default: This is a description of the post.

So, you could get started with a new post, complete with the metadata to describe the post rather than the boring defaults, using something like:

dotnet new post -t "My exciting new post" -au happy-blogger -s my-exciting-new-post -o my-exciting-new-post -d "This post is going to be so awesome and you will be a better person for reading it."

If you're a detail-oriented CLI user who isn't afraid of that verbose a command, the results are like blogging zen. A fully-ready document awaiting your creative output.

---
title: My exciting new post
slug: my-exciting-new-post
author: happy-blogger
lastModified: 2020-01-19 12:26:33
pubDate: 2020-01-19 12:26:33
categories: blog,post,article
description: This post is going to be so awesome and you will be a better person for reading it.
---

Now, my metadata needs are satisfied, and I can start writing.

 

downr 3.0

posted one year ago in downr

downr is a very simple blogging engine written for people who like using Markdown to write content and Git to maintain their source code and/or content files. The goals of downr are to create a blogging engine that:

  • Is built using .NET 3.1 so it can run anywhere
  • Feels natural for developer bloggers who use Visual Studio Code to author their content in Markdown
  • Supports being CI/CD'd anywhere
  • Feels natural to .NET developers who frequently use the dotnet CLI
  • Is open source and available on GitHub
  • Is build using Blazor WebAssembly (because why not?)

Getting downr Running Locally

Getting downr running on a development workstation is easy. Open your favorite terminal window and run this:

git clone https://github.com/bradygaster/downr.git
cd downr/server
dotnet run

Blogging with downr

Blogging with downr is deliberately very simple - you just write Markdown. downr operates on two conventions - how you organize your markdown and content files and some simple YAML metadata in each post's Markdown file.

Example post structure

Consider this post, the introduction to downr. This post's slug is introducing-downr-3. This post's folder structure on disk looks like this. You place the Markdown files into the Server\wwwroot\posts folder.

|-- introducing-downr-3
    |-- index.md
    |-- media
        |-- img1.png
        |-- img2.png

This ensures all your posts follow a nice, neat conventional folder structure. Once you have a gaggle of posts published to your site, it'll be all tidy like this:

|-- wwwroot
    |-- posts
        |-- a-post-with-no-pictures
            |-- index.md
        |-- introducing-downr-3
            |-- index.md
            |-- media
                |-- img1.png
                |-- img2.png
        |-- some-other-post
            |-- index.md
            |-- media
                |-- pic1.png
                |-- pic2.png
                |-- pic3.png

Post Metadata

The top section of each Markdown file must contain a YAML header with some simple metadata elements. All of these elements are required. The YAML below demonstrates this convention.

---
title: Introducing downr
slug: introducing-downr
author: bradygaster
lastModified: 2017-01-06 12:00:00
pubDate: 2017-01-06 12:00:00
categories: downr
description: Each post should have a description for the index page and for the RSS feed
---

Customizing your site

If you want to customize the style or HTML layout, you have 4 files to edit in the Client folder:

  • appsettings.json
  • Pages/Index.razor
  • Pages/Posts.razor
  • wwwroot/index.html

Site-wide data can be edited using the downr section of appsettings.json. Customize this to change the title and banner of your site.

"Downr": {
    "title" : "downr",
    "rootUrl" : "http://downr.azurewebsites.net",
    "pageSize": 2,
    "author": "the downr team",
    "indexPageText": "downr is a dirt-simple blogging tool written for people who like to author their content in markdown"
}

Obviously, you can customize your site all you want, but if you're simply into blogging with Markdown you never need to look at the source code.

Dependencies

downr was created using these excellent open-source libraries:

Contributing

Contributions to downr are welcome and encouraged. Fork the downr GitHub repository and submit pull requests to your heart's content.

Naming Disclaimer

Note: Product naming is difficult. I noticed that there were a few other projects out there named similarly to this one. The dotnet markdown blogging tool known as downr has no implied or accidental relationship to any of these other awesome projects.

 

A few months ago I let the community know that I'd be deprecating some features from the Azure Tools for Visual Studio Code. Some amazing new extensions have appeared in the Azure category of the Visual Studio Marketplace that make it easy and fun to party with Azure. With the great work that's getting done by folks in the Visual Studio Code Azure Tools team, I think it's safe to say that full deprecation is in order.

Why? What's the deal?

To make it as short and sweet as possible, I don't want to confuse anyone who is looking in the marketplace for the real Azure tools. This extension has been in the marketplace for a long time, and as a result of frequent updates at our beginning, we've had a great running and our download count has gotten pretty great. We wholly appreciate the great feedback, contributions, and issues we've received on the extension.

I started this extension with a few goals:

  1. Learn more about the Node.js SDK.
  2. Use the Node.js SDK with the VS Code extensibility API.
  3. Have a tool I could use to do things I have to do frequently when I'm building stuff in Azure.

The extension definitely gave an opportunity for those learnings, but it also introduced a lot of folks to developing with Azure within VS Code. Since those early beginnings there's been a huge set of investments in enabling Azure developer experiences within VS Code, and I want to make sure customers don't stumble onto our humble beginnings and miss out on the true awesomeness of the official Azure extensions.

When?

I'll remove the extension from the marketplace on April 27th, 2018.

What's Next Here?

Simply - nothing. The original extension's repository will remain intact so developers can learn from the code or clone-and-package it on your own using the VSCE tools for packaging and publishing your own extensions.

Again - thanks for your use of the extension, contributions, and ideas. Please take my advice, try out the new and official extensions for App Service, Cosmos DB, mssql, Azure Functions, IoT - all of it! Happy coding!

 

In my previous post I got started using .NET Core Razor pages with Semantic UI. After writing the post I was convinced I'd be using Semantic UI for my next blog redesign. One reason is that when you use Semantic UI's gulp build tools alongside .NET's watch tool, you can be really efficient in designing your site and figuring out how you want it to look. This post demonstrates how to use Visual Studio Code and the built-in multiple-tab terminal window to make this a natural development experience.

Copying the default theme into a new folder named brady makes it easy for me to feel comfortable customizing numerous colors and font sizes, and anything else I want to tweak without fearing I've boned up the default theme. Once I get that working I can run dotnet watch run to start up my site.

dotnet watch

I got started with one of the built-in Semantic UI layouts, with a simple menu at the top of my site.

The before UI

Semantic UI offers a handy gulp watch command that, when executed, will watch all of the files in my theme (or any of the Semantic UI override files). Whenever I change any of these files the changes will be picked up and the CSS/JS files will be rebuilt. I don't want to stop the ASP.NET server from running, but I do want to see immediate updates when I make changes to my Semantic UI theme files. So I open up a new tab in Visual Studio Code and cd into the semantic folder in my project root (not the semantic folder inside of wwwroot!).

Adding a terminal tab

Now I can run the gulp watch build step and any change I make will be automatically picked up. So, let's make a quick change to the top menu bar to give the site some color.

Gulp watch

I'll open up the original default menu theme file that I copied into my own brady theme.

Original menu

Now, I'll change the @background variable to be a blue that might look better with my photo. As soon as I save the file the files are rebuit.

Edited menu

Once the build completes I can refresh the browser, and the changes are visible.

Resulting menu

Summary

This post continues my exploration into how Semantic UI and ASP.NET can be great together. I'm in the process of re-writing my blog tool to use Semantic UI, so stay tuned as in the next few days I'll release a new-and-improved site and much simpler codebase for the downr blogging system. Happy coding!