Showing posts with label Web. Show all posts
Showing posts with label Web. Show all posts

Tuesday, September 1, 2020

Hosting Docker images on GitHub

Hosting our own Docker images on GitHub is simpler than you think. On this post, let's review how.
Photo by Annie Spratt on Unsplash

We recently reviewed how to host our NuGet packages on GitHub. Turns out that another popular feature of GitHub Packages is hosting Docker images. Given that GitHub is the world's largest development website and you're probably already hosting your code up there, why not also review how to build, host and consume our own ASP.NET Core Docker images on it?

On this post we will:

Requirements

To run this project on your machine, please make sure you have installed:

If you want to develop/extend/modify it, then I'd suggest you to also have:

About GitHub Packages

GitHub Packages is GitHub's free offering for those wanting to host their own packages or Docker images in GitHub itself. The benefits of using GitHub Packages is that it's free, you can share your images privately or with the rest of the world, integrate with the GitHub API, GitHub Actions, webhooks and even create complex end-to-end DevOps workflows.

Building our Docker Image

So let's quickly build our Docker image. For this demo, I'll use my own aspnet-docker project. If you want to follow along, open a terminal and clone the project with:
git clone https://github.com/hd9/aspnet-docker

Building our local image

Next, cd into that folder and build a local Docker image with:
docker build . -t webapp:0.0.1
Now confirm your image was successfully built with:
docker images
You should see something along the lines of:
webapp      0.0.1               73a91c1204db        21 seconds ago      212MB
For more information on how to setup and run the application, check the project's README file.

Testing our local image

Before pushing our image to GitHub, let's make sure it runs fine with:
docker run --rm -d -p 8080:80 webapp:0.0.1
Test it at http://localhost:8080/. Here's what you should see:

Pushing packages to GitHub

With the image ready and working, let's review how to push your own Docker images to GitHub.

Generating an API Key

In order to authenticate to GitHub Packages the first thing we'll need is an access token. Open your GitHub account, go to Settings -> Developer Settings -> Personal access tokens, click Generate new Token, give it a name, select write:packages and save: 
Now copy the API key provided, we'll use it in the next step.

Logging in with Docker

To push our images to GitHub, first we log in with:
docker login https://docker.pkg.github.com -u <github-username> -p <api-key>
Or, you could echo your api key from a file with:
cat api-key.txt | docker login https://docker.pkg.github.com -u <github-username> --password-stdin
Or even better, using an env var with:
echo $<envvar-name> | docker login https://docker.pkg.github.com -u <github-username> --password-stdin

Tagging our image

With the login successful, we now need to tag the image and push. Let's tag it first with:
docker tag <img-name> docker.pkg.github.com/<gh-user>/<repo>/<img-name>:<version>
Confirm you get both images with docker image ls:
docker image ls
Here's what you should see:
REPOSITORY                                       TAG       IMAGE ID       CREATED             SIZE
webapp                                           0.0.1     73a91c1204db   30 minutes ago      212MB
docker.pkg.github.com/hd9/aspnet-docker/webapp   0.0.1     73a91c1204db   30 minutes ago      212MB

Pushing the image to GitHub

Finally, push it to the remote repo with:
docker push docker.pkg.github.com/<gh-user>/<repo>/<img-name>:<version>
Here's what I got during my tests:

Reviewing our image on GitHub

Let's confirm our image was successfully pushed to GitHub. Open your project's page and click on Packages. Our webapp package looks like this:

Using our image

To consume our image we'll have to (1) login with docker, (2) pull the image and (3) run it. As previously mentioned, I'll run it from a different box. This time on an Alpine Linux VM I love playing with.
To learn how to install and run Docker on Alpine, check this link.
Let's once more login on GitHub with Docker with:
docker login https://docker.pkg.github.com -u <github-username> -p <api-key>

Pulling the image the image

After the login, pulling our image is as simple as:
docker pull docker.pkg.github.com/<gh-user>/<repo>/<img-name>:<version>
For context, here's my pull in action:
After the pull confirm with docker image ls:

Run the image

And finally run our image with:
docker run --rm -d -p 8080:80 webapp:0.0.1
If you want, confirm your image is running with:
docker ps

Accessing the container

Lastly, let's confirm we can access it from our host. On Alpine, enter ip a show eth0 to show the VM's internal IP:
And finally, access it from the host (your machine) with your browser. On my case, http://172.27.197.46:8080/:

Final Thoughts

On this post we reviewed how to build our own Docker images, pushed them to GitHub and finally demoed how to consume them on a different machine. Creating and hosting our own Docker images on GitHub is valuable as you can share your images privately, with the rest of the world, integrate with GitHub APIs, GitHub Actions, webhooks, creating complex end-to-end DevOps workflows and even deploy them to a Kubernetes cluster. We'll evaluate that in the future so keep tuned!

Source Code

As always, the source code is available on GitHub.

See Also

Wednesday, July 15, 2020

Hosting NuGet packages on GitHub

On this post let's review how to build, host and consume our own NuGet packages using GitHub Packages
Photo by Leone Venter on Unsplash

Long gone are the days we had to pay to host our NuGet packages. Today, things have changed. We have many options to host our own NuGet packages for free (including privately if we wish) including in our own GitHub repositories. On this tutorial let's review how to build our own packages using .NET Core's CLI, push them to GitHub and finally, how to consume from our own projects.

About NuGet

NuGet is a free and open-source package manager designed by Microsoft and used extensively in the .NET /.NET Core ecosystem. NuGet is the name of the tool and of the package itself. The most common repository for NuGet packages is NuGet.org hosting more than 200k packages! But we can host our own packages on different repos (including private ones) such as GitHub Packages. NuGet is bundled with Visual Studio and with the .NET Core SDK so you probably have it already available on your machine.

About GitHub Packages

GitHub Packages is GitHub's free offering for those wanting to host their own packages. GitHub Packages allows hosting public and private packages. The benefits of using GitHub Packages is that it's free, you can share your packages privately or with the rest of the world, integrate with GitHub APIs, GitHub Actions, webhooks and even create complex end-to-end DevOps workflows. For more information about GitHub Packages, click here.

Why build our own packages

But why build our own packages? Mainly because packages simplify using and distributing self-contained and reusable software (tools, libraries, etc) in a clean and organized way of doing so. Beyond that, other common reasons are:
  1. sharing packages with someone else (and possibly the world)
  2. sharing that package privately with your coworkers so they can be used in different projects.
  3. packaging software so it can be installed or deployed elsewhere.

Building NuGet Packages

So let's get started and build our first NuGet package. The project we'll build is a simple library consisting of POCOs I frequently use as standard onfiguration bindings when developing microservices: Smtp, Redis, RabbitMQ, MassTransit and MongoDB. I chose this example because this is the type of code we frequently duplicate, so why not isolate them in a shareable package and keep our codebase DRY?

Creating our project

To quickly create my project let's use the .NET Core CLI (feel free to use Visual Studio if you will):
dotnet new classlib -o HildenCo.Core
Then I'll add those config classes. For example the SmtpOptions looks like:
public class SmtpOptions
{
    public string Host { get; set; }
    public int  Port { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string FromName { get; set; }
    public string FromEmail { get; set; }
}

Creating our first NuGet package

Let's then create our first package. The simplest way to do so is by configuring it via Visual Studio. For that, select the Project and Alt-Enter it (or right-click it with the mouse) to view Project Properties and check Generate NuGet package on build on the Package tab:
Don't forget to add relevant information about your package such as Id, Name, Version, Authors, Description, Copyright, License and RepositoryUrl. All that information is required by GitHub:
If you prefer, you can edit the above metadata directly in the csproj file.
Now, build again to confirm our package was built by inspecting the Build Output in VS (Ctrl-W, O):
1>------ Build started: Project: HildenCo.Core, Configuration: Debug Any CPU ------
1>HildenCo.Core -> C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Debug\netstandard2.0\HildenCo.Core.dll
1>Successfully created package 'C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Debug\HildenCo.Core.0.0.1.nupkg'.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Congrats! You now have built your first package!
Don't forget to add RepositoryUrl with your correct username/repo name. We'll need it to push to GitHub later.

Creating our package using the CLI

As always, the CLI may be a better alternative. Why? In summary because it allows automating package creation on continuous integration, integrating with APIs, webhooks and even creating end-to-end DevOps workflows. So, go ahead and uncheck that box and build it again with:
dotnet pack --configuration Release
This time, we should see this as output:
Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  All projects are up-to-date for restore.
  HildenCo.Core -> C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Release\netstandard2.0\HildenCo.Core.dll
  Successfully created package 'C:\src\nuget-pkg-demo\src\HildenCo.Core\bin\Release\HildenCo.Core.0.0.1.nupkg'.
TIP: You may have realized that we now built our package as release. This is another immediate benefit from decoupling our builds from VS. On rare occasions should we push packages built as Debug.

Pushing packages to GitHub

With the basics behind, let's review how to push your own packages to GitHub.

Generating an API Key

In order to authenticate to GitHub Packages the first thing we'll need is an access token. Open your GitHub account, go to Settings -> Developer Settings -> Personal access tokens, click Generate new Token, give it a name, select write:packages and save:

Creating a nuget.config file

With the API key created, let's create our nuget.config file. This file should contain the authentication for the package to be pushed to the remote repo. A base config is listed below with the fields to be replaced in bold:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <packageSources>
        <clear />
        <add key="github" value="https://nuget.pkg.github.com/<your-github-username>/index.json" />
    </packageSources>
    <packageSourceCredentials>
        <github>
            <add key="Username" value="<your-github-username>" />
            <add key="ClearTextPassword" value="<your-api-key>" />
        </github>
    </packageSourceCredentials>
</configuration>

Pushing a package to GitHub

With the correct configuration in place, we can push our package to GitHub with:
dotnet nuget push ./bin/Release/HildenCo.Core.0.0.1.nupkg --source "github"
This is what happened when I pushed mine:
dotnet nuget push ./bin/Release/HildenCo.Core.0.0.1.nupkg --source "github"
Pushing HildenCo.Core.0.0.1.nupkg to 'https://nuget.pkg.github.com/hd9'...
  PUT https://nuget.pkg.github.com/hd9/
  OK https://nuget.pkg.github.com/hd9/ 1927ms
Your package was pushed.
Didn't work? Check if you added RepositoryUrl to your project's metadata as nuget uses it  need it to push to GitHub.

Reviewing our Package on GitHub

If you managed to push your first package (yay!), go ahead and review it in GitHub on the Package tab of your repository. For example, mine's available at: github.com/hd9/nuget-pkg-demo/packages and looks like this:

Using our Package

To complete the demo let's create an ASP.NET project to use our own package:
dotnet new mvc -o TestNugetPkg
To add a reference to your package, we'll use our own nuget.config since it contains pointers to our own repo. If your project has a solution, copy the nuget.config to the solution folder. Else, leave it in the project's folder. Open your project with Visual Studio and open the Manage NuGet Packages. You should see your newly created package there:
Select it and install:
Review the logs to make sure no errors happened:
Restoring packages for C:\src\TestNugetPkg\TestNugetPkg.csproj...
  GET https://nuget.pkg.github.com/hd9/download/hildenco.core/index.json
  OK https://nuget.pkg.github.com/hd9/download/hildenco.core/index.json 864ms
  GET https://nuget.pkg.github.com/hd9/download/hildenco.core/0.0.1/hildenco.core.0.0.1.nupkg
  OK https://nuget.pkg.github.com/hd9/download/hildenco.core/0.0.1/hildenco.core.0.0.1.nupkg 517ms
Installing HildenCo.Core 0.0.1.
Installing NuGet package HildenCo.Core 0.0.1.
Committing restore...
Writing assets file to disk. Path: C:\src\TestNugetPkg\obj\project.assets.json
Successfully installed 'HildenCo.Core 0.0.1' to TestNugetPkg
Executing nuget actions took 960 ms
Time Elapsed: 00:00:02.6332352
========== Finished ==========

Time Elapsed: 00:00:00.0141177
========== Finished ==========
And finally we can use it from our second project and harvest the benefits of clean code and code reuse:

Final Thoughts

On this post we reviewed how to build our own NuGet packages using .NET Core's CLI, pushed them to GitHub and finally described how to consume them from our own .NET projects. Creating and hosting our own NuGet packages is important for multiple reasons including sharing code between projects and creating deployable artifacts.

Source Code

As always, the source code for this post is available on GitHub.

See Also

Monday, April 20, 2020

How to profile ASP.NET apps using Application Insights

Application Insights can monitor, log, alert and even help us understand performance problems with our apps.
Photo by Marc-Olivier Jodoin on Unsplash
We've been discussing AppInsights in depth on this blog and to complete the series, I'd like to discuss the performance features it offers. On the previous posts, we learned how to collect, suppress and monitor our applictions using AppInsights data.

On this post let's understand how to use the performance features to identify and fix performance problems with our app.

What's profiling?

Wikipedia defines profiling as:
a form of dynamic program analysis that measures, for example, the space (memory) or time complexity of a program, the usage of particular instructions, or the frequency and duration of function calls. Most commonly, profiling information serves to aid program optimization.
Profiles usually monitor:
  • Memory
  • CPU
  • Disk IO
  • Network IO
  • Latency
  • Speed the of application
  • Access to resources
  • Databases
  • etc

Profiling ASP.NET Applications

ASP.NET developers have multiple ways of profiling our web applications, being the most popular: 
Those are awesome tools that definitely you should use. But today we'll focus on what can we do to inspect our deployed application using Application Insights.

How can Application Insights help

Azure Application Insights collects telemetry from your application to help analyze its operation and performance. You can use this information to identify problems that may be occurring or to identify improvements to the application that would most impact users. This tutorial takes you through the process of analyzing the performance of both the server components of your application and the perspective of the client so you understand how to:
  • Identify the performance of server-side operations
  • Analyze server operations to determine the root cause of slow performance
  • Identify slowest client-side operations
  • Analyze details of page views using query language

Using performance instrumentation to identify slow resources

Let's illustrate how to detect performance bottlenecks in our app with some some. The code for this exercise is available on my github. You can quickly get it by:
git clone https://github.com/hd9/aspnet-ai.git
cd aspnet-ai
git branch performance
# insert your AppInsights instrumentation key on appSettings.Development.json
dotnet run
This project contains 5 endpoints that we'll use to simulate slow operations:
  • SlowPage - async, 3s to load, throws exception
  • VerySlowPage - async, 8s to load
  • CpuHeavyPage - sync, loops over 1 million results with 25ms of interval
  • DiskHeavyPage - sync, writing 1000 lines to a file
 Running the tool and get back to azure. We should have some data there.

Performance Tools in AppInsights

Our AppInsights resource in Azure greets us with an overview page already that shows us consolidaded information about failed requests, server response time, server requests and availability:

Now, click on the Performance section. Out of the box, AppInsights has already captured previous requests and shows a consolidated view. Look below to already see our endpoints sorted out by duraction:

You should also have access to an Overall panel where you'd see requests per time:
There's also good stuff on the The End-to-end transaction details widget:

For example, we could click on a given request and  get additional information about it:

Tracing

We now know which are the slowest pages on our site, let's now try to understand why. Essentially, have two options:
  1. use AppInsights's telemetry api (as on this example) 
  2. or integrating directly to your logging provider, using System.Diagnostics.Trace on this case.

Tracing with AppInsights SDK

Tracing with AppInsights SDK is done via the TrackTrace method from TelemetryClient class an is as simple as:
public IActionResult Index()
{
    _telemetry.TrackPageView("Index");
    return View();
}

Tracing with System.Diagnostics.Trace

Tracing with System.Diagnostics.Trace is also not complicated but requires the NuGet package Microsoft.ApplicationInsights.TraceListener. For more information regarding other logging providers, please check this page. Let's start by installing it with:
dotnet add package Microsoft.ApplicationInsights.TraceListener --version 2.13.0

C:\src\aspnet-ai\src>dotnet add package Microsoft.ApplicationInsights.TraceListener --version 2.13.0
  Writing C:\Users\bruno.hildenbrand\AppData\Local\Temp\tmpB909.tmp
info : Adding PackageReference for package 'Microsoft.ApplicationInsights.TraceListener' into project 'C:\src\aspnet-ai\src\aspnet-ai.csproj'.
info : Restoring packages for C:\src\aspnet-ai\src\aspnet-ai.csproj...
(...)
info : Installing Microsoft.ApplicationInsights 2.13.0.
info : Installing Microsoft.ApplicationInsights.TraceListener 2.13.0.
info : Package 'Microsoft.ApplicationInsights.TraceListener' is compatible with all the specified frameworks in project 'C:\src\aspnet-ai\src\aspnet-ai.csproj'.info : PackageReference for package 'Microsoft.ApplicationInsights.TraceListener' version '2.13.0' added to file 'C:\src\aspnet-ai\src\aspnet-ai.csproj'.
info : Committing restore...
info : Writing assets file to disk. Path: C:\src\aspnet-ai\src\obj\project.assets.json
log  : Restore completed in 4.18 sec for C:\src\aspnet-ai\src\aspnet-ai.csproj.

Reviewing the results

Back in Azure we should now see more information about the performance of the pages:
And more importantly, we can verify that our traces (in green) were correctly logged:

Where from here

If you used the tools cited above, you now should have a lot of information to understand how your application performs on production. What next?

We did two important steps here: understood the slowest pages and added trace information to them. From here, it's with up to you. Start by identifying the slowest endpoints and add extra telemetry on them. The root cause could be in a specific query in your app or even on an external resource. The point is, each situation is peculiar and extends the scope of this post. But the essential you have: which are the pages, methods and even calls that take longer. On that note, I'd recommend adding custom telemetry data so you have a real, reproducible scenario.

Conclusion

On this post, the last on the discussion about AppInsights, we reviewed how Application Insights can be used to understand, quantify and report about the performance or our apps. Once again, AppInsights demonstrates to be an essential tool for developers using Azure.

More about AppInsights

For more information, consider reading my previous articles about App Insights:
  1. Adding Application Insights telemetry to your ASP.NET Core website
  2. Suppressing Application Insights telemetry on .NET applications
  3. Monitoring ASP.NET applications using Application Insights and Azure Alerts

References

See Also

Monday, January 6, 2020

Countdown to .NET 5

2020 is an excellent year for .NET. This is the year we'll finally see .NET 5 merging .NET Core, .NET Framework and Xamarin.
2020 brings great news for .NET developers. This is the year that, Microsoft expects to consolidate .NET Core and .NET Framework on a single platform called .NET 5 including .NET mobile (Xamarin), ASP.NET Core, Entity Framework Core, WinForms, WPF and ML.NET.. The first preview is expected in the first half of the year with the official release foretasted for Nov, 2020. Excited? You should be!

Update: The first beta release is available now!

Great news for .NET developers

That's great news for folks working on .NET Core since there'll be an influx of projects to work, contribute and develop. But that's even better news for teams working on slow-moving projects (aka, most of us) which have been deferring an update to the more modern, faster and container-friendly .NET Core.

I posted some time ago my insights regarding this update. TLDR, I'm super excited! Being a long time Fedora Linux user and a big open source enthusiast, I have been using .NET Core for my personal projects on Linux (and running them successfully on both Docker, AWS and Azure). While I'm transitioning more and more my workflow to open source software (such as Vim, i3, etc) and and have been working a decent portion of my time with Go and Python, .NET is still my default framework.

So let's take another look at what's coming up next with .NET.

Highlights of .NET 5

Apart from the single codebase, my preferred highlights of .NET 5 are:
  • .NET will become a single platform including Xamarin, ASP.NET Core, Entity Framework Core, WinForms, WPF and ML.NET
  • Unified .NET SDK experience:
    • Single BCL (Base Class Library) across all .NET 5 applications. Today Xamarin applications use the Mono BCL but will move to use the.NET Core BCL, improving compatibility across our application models.
    • Mobile development (Xamarin) is integrated into .NET 5. This means the .NET SDK will support mobile. For example, you can use “dotnet new XamarinForms” to create a mobile application.
  • Native Applications supporting multiple platforms: Single Device project that supports an application that can work across multiple devices for example Window Desktop, Microsoft Duo (Android), and iOS using the native controls supported on those platforms.
  • Cloud Native Applications: High performance, single file (.exe) <50MB microservices and support for building multiple project (API, web front ends, containers) both locally and in the cloud.
  • Open source and hosted on GitHub
  • Cross-platform and better performance
  • Decent command-line interface (CLI)
  • Java, Objective-C and Swift interoperability
  • Support of static compilation of .NET (ahead-of-time – AOT)
  • Smaller footprints

A Unified Platform

This is a more holistic view of what .NET 5 will be:

The Schedule

The proposed merge is expected to happen by November 2020. Here's the plan:
You can also check the release status in real time on GitHub (Jan, 2020):

What's Next

So what's next? Well, the best thing to do is to keep an eye on .NET's official blog as they'll be updating the status of the project through there. Would you like to contribute? Jump into .NET Core and CoreFx repositories in GitHub. For more information on the topic, consider reading .NET Core and .NET merging as .NET 5.0.

References

See Also

For more posts on .NET Core, please click here.

Monday, November 26, 2018

JavaScript caching best practices in ASP.NET

Looking to improve the performance of your site with a few simple tips? Read to understand.

One of the first things a developer should do when inspecting the performance of their ASP.NET website is to understand how the static assets of the site are served and if they are correctly being cached by the visitor's browser. On this post let's review a solution that works well, is built into the ASP.NET framework and helps you reduce costs and improve the performance of your site.

How caching works

Before getting to solution, it's important to understand how web browsers cache static resources. In order to improve performance and reduce network usage, browsers usually cache JavaScript and external resources a web page may depend on. However, under certain circumstances, modifications on those files won’t be automatically detected by the browser resulting in users seeing stale content.

Approaching the Problem

A common solution to this problem is to add query string parameters to the referenced JavaScript files. Assuming that the suffix has changed, the browser treats the new url as a new resource (even if it’s the same file name), issuing a new request and refreshing the content. Whenever that resource changes, the query string changes and the browser automatically refreshes the resource making users always seeing the most up to date content. Also note how we can use that approach for all linked resources: JavaScript files, CSS, images and even icons.

So how to ensure that our pages output references as showed above? In ASP.NET, the solution to that is to use bundles.

Bundling and Minification

According to Microsoft,
Bundling and minification are two techniques you can use in ASP.NET 4.5 to improve request load time. Bundling and minification improves load time by reducing the number of requests to the server and reducing the size of requested assets (such as CSS and JavaScript.)
Another benefit of bundling is that, by default, the Asp.Net framework comes with a cache-prevention feature
Bundles set the HTTP Expires Header one year from when the bundle is created. If you navigate to a previously viewed page, Fiddler shows IE does not make a conditional request for the bundle, that is, there are no HTTP GET requests from IE for the bundles and no HTTP 304 responses from the server. You can force IE to make a conditional request for each bundle with the F5 key (resulting in a HTTP 304 response for each bundle). You can force a full refresh by using ^F5 (resulting in a HTTP 200 response for each bundle.)

Bundling in practice

Before reviewing the actual solution, let’s compare a page serving bundled content and a page showing unbundled content and understand how the browser behaves on each of them.

Reviewing a request with bundled content

Let's take a look at a request using bundles to understand this a little better:
From the above, note that:
  • in yellow, the auto-added suffix. We'll see later why this is there and how to do it ourselves;
  • in red, a confirmation that that resource was cached by the browser and loaded locally, not issuing any request to the server;
  • the time column on the right, shows the time spent by the browser to load that resource. For most files it was 0ms (or, from cache);
Now if you expand the bundle request, we can see that the cache is set to 1 year from the request date, meaning that the file won't be refreshed for the next 365 days:

Serving unbundled content

Now if you take a look at a request to a page that has unbundled content, you'll see that the resources are also being cached (column Size). However, individual requests are still being issued for each file referenced causing two problems:
  1. In HTTP 1.1, there’s a virtual limit of max 6 concurrent requests per domain. On that case, after the 6th request is issued, others will be waiting until a new slot is available
  2. Because after each deploy file names won’t change, the browser will reuse the cached version event if modified (because by seeing the same file name, it understands the resource didn’t change). Our problem is that updates on those files won’t be automatically refreshed making users see stale content.

Bundling in ASP.NET

Because the ASP.NET framework already provides bundling, it's Simply by using bundles and referencing them in our scripts solves the issue. In ASP.NET we do it by registering our bundle in our Global.asax.cs file in the Application_Start method:
protected void Application_Start()
{
    // ...
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    // ...
}
Where the RegisterBundles method, looks like:
public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new StyleBundle("~/Content/css")
        .Include("~/Content/images/icon-fonts/entypo/entypo.css")
        .Include("~/Content/site.css"));
}
Now, build and deploy your site. Just don't forget to remove debug=true on your web.config, compilation element:
<compilation targetFramework="4.7.2" />
Whenever that content changes or a new deploy happens, that querystring value for each bundle is automatically modified by the framework ensuring that users will always have your latest JavaScript, optimized, without risking serving an obsolete version to your users.

Conclusion

On this post we reviewed some practices for increasing the performance of your site. Caching, bundling and minification are standard practices that developers should consider to increase the performance of their ASP.NET websites.

References

See Also

Monday, October 15, 2018

Customizing your Blogger title to improve SEO

How to use this simple tip and make your blog have more visibility.

Last week we discussed how to prevent archived pages from being indexed by crawlers. On this post we will discuss another nice improvement that we can add to our site: how to customize the tile of your page if you're using Blogger.

Changing Theme Settings

In order to do that, we will have to edit the html for our blog. As mentioned in the previous post, to edit our html, inside Blogger, we click Theme -> customize button:


Once the html opens, just at the beginning we can find the <tilte> tag. I replaced mine by:



Modified Template

After making this change, this is the expected logic:
  • if the page is an archive page (myblog/2018/05), show the blog title and add a noindex to the page so it won't show up in search results
  • else if the landing page, only show blog title
  • if it's a post page, then show the post title.

And this is my final source:
<b:if cond='data:blog.pageType == "archive"'>
<meta content='NOINDEX' name='ROBOTS'/>
<title><data:blog.title/></title>
<b:elseif cond='data:blog.pageType == "index"'/>
<title><data:blog.title/></title>
<b:else/>
<title><data:blog.pageName/></title>
</b:if>

Conclusion

There are many customizations that we can done to our pages. For more information check Blogger Help. Links specific to this post are referenced below.

See Also

For more posts like this, please click here.

References

Blogger Help - Widget Tags for Layouts
Blogger Help - Layouts Data Tags

About the Author

Bruno Hildenbrand      
Principal Architect, HildenCo Solutions.