Fingerprint bundles in path, not in query parameter with System.Web.Optimization and Visual Studio 2015

In my previous post (https://www.roelvanlisdonk.nl/?p=4550) I explained how to:

– create a new ASP .NET MVC 5 .NET 4.6 project in Visual Studio 2015

– add static caching, add url rewrites

– add fingerprinting to the “folder part” of each URL, to bust the client cache, when a new build is deployed to the website

 

Now if you don’t want to use the URL Rewrite approach, but you still want to fingerprint the “folder url part” of the bundels created with the System.Web.Optimization (instead of using the standard query parameter cache busting technique), you can use the following class:

 

image

 

Use this class, when the bundles are created and when they are used inside the *.cshtml:

 

image

 

Then inside a *.cshtml page:

 

image

 

In this way, only the “name” of the bundle is fingerprinted and bundeling will only take place in “release” build.

The System.Web.Optimization will take care of the “cache busting”, no need for “URL rewriting”.

 

The code uses the following extension method:

 

image

Cache busting / fingerprinting bundles with System.Web.Optimization and Visual Studio 2015

I like to use client build systems like grunt, gulp, webpack etc. to bundle and minify JavaScript and CSS files, but on a resent project I had to use the Microsoft Web optimization framework.

 

Note: All code used in this blog post  can be found at: https://github.com/roelvanlisdonk/POC/tree/master/ASP.NET/CacheBusting

 

In this I will describe how to create an MVC .NET 4.6 web application, that uses bundeling, minification and fingerprinting for cache busting all by using the System.Web.Optimization framework.

 

Start Visual Studio 2015, then click:

File> New > Project…

 

Choose: Installed\Templates\Visual C#\Web\ASP.NET Web Application

 

image

Choose: “ASP.NET 4.6 Templates”: “Empty” and “Add folders and core references for”: “MVC”

 

image

 

Add a “MVC 5 Layout Page (Razor)” called “_Layout” to the “Views” folder

 

image

 

 

 

Add a “Home” controller to the “Controllers” folder:

image

 

Choose: MVC 5 Controller – Empty

 

image

 

Add a “Index.cshtml” view to the /Views/Home folder:

 

image

 

Choose the “_Layout.cshtml” as “layout page”

 

image

 

Change html:

 

image

 

Add some TypeScript files and CSS files to the /Views/Home folder:

 

image

 

image

 

image

image

To allow static file content serving from the “/Views” folder adjust the Web.config inside the “/Views” folder, remove the “BlockViewHandler”:

image

Add the System.Web.Optimization NuGet package to your project:

 

image

 

Search for “Optimization” and choose: Microsoft.AspNet.Web.Optimization

 

image

 

This will install the following dependencies to your project:

 

image

 

After installing the package we will first upgrade some of the components, just change the filer to “Upgrade available”:

 

image

 

Upgrade all packages until all package are upgraded:

image

 

Add a NonOrderingBundleOrderer.cs class to the “/Common” folder.

This class will prevent automatic ordering of the files inside the bundle.

The files will be placed in the html in the order they are added to the bundle.

 

image

 

Add a BundleConfig.cs class to the “App_Start” folder

 

image

 

Change code like:

The “#if !DEBUG”, means:

In “debug” modus all files are rendered separately to the HTML in “release” modus all JavaScript files are combined to one JavaScript file and all CSS files are combined to one CSS file.

image

 

Change the global.asax

Add “BundleConfig.RegisterBundles(BundleTable.Bundles);”

image

 

Add a class “AssemblyExtensions.cs” to the “/Extensions” folder:

image

 

Edit code like:

image

 

 

Add a class “Bundle.cs” to the “/Common” folder:

image

 

Edit code like:

image

 

Change the “_Layout.cshtml” like:

The layout page contains the actual rendering of the CSS and JavaScript bundles.

image

 

When we run the application at this point we get 4 errors in the Browser console, because all JavasScript files and CSS files are fingerprinted with a version number and do not exist on disk:

 

image

 

To solve this error, we can add Url Rewriting to our Web.config file and start caching files:

 

To start caching files, add the following xml to the Web.config:

 

image

 

 

URL Rewrite extension

To start using Url Rewriting, first install the URL from http://www.iis.net/downloads/microsoft/url-rewrite or from the web platform installer inside IIS.

Note that URL Rewriting will work out of the box with IIS Express in Visual Studio 2015.

 

image

 

Then add the following to the Web.config:

 

image

 

All url’s that start with vx.x.x.x/ will be rewritten (the version number will be removed from the URL before passing it to the reset of ASP .NET. Only the part after the first “/” will be presented to the “match” rule.

So only the part “v1.0.0.0/View/Home/Test1.js” of the url http://localhost:4567/v1.0.0.0/View/Home/Test1.js will be passed to the match rule, that’s why the regex can start with a “^”.

 

Now when you run the application in debug modus you will see:

 

image

 

And when you run in “release mode” you will see:

image

 

As you can see the System.Web.Optimization framework automatically adds a “cache busting query parameter”, but in some browsers this is not enough, that’s why we added a version number inside the “folder” part of the url.

 

 

The final project structure should look like:

 

image

 

For more resources see: http://madskristensen.net/post/cache-busting-in-aspnet

 

 

NOTE

If you use “URLs” inside a CSS file, that is added to a bundle, e.g.

background-image: url(https://www.example.com/bck.png);

Then these URLs should also be fingerprinted.

To fingerprint these URLs you can write a custom BundleTransform:

http://blog.mirajavora.com/deep-dive-into-asp.net-bundling-and-minification/

 

Or use the https://bundletransformer.codeplex.com/.

This extension to the System.Web.Optimization framework, supports automatic transformation of relative paths to absolute paths in CSS-code (by using UrlRewritingCssPostProcessor).

How to send a free SMS from C#

I used the following code to send a free SMS from C#, by using the messagebird REST service.

 

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace DocumentenService.Client
{
public class Program
{
public static void Main(string[] args)
{
SendSms().Wait();
// Wait for the user to close this application.
Console.WriteLine("Press enter to close this application.");
string result = Console.ReadLine();
}
/// <summary>
/// Send a sms
/// </summary>
/// <returns></returns>
public static async Task SendSms()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://rest.messagebird.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("AccessKey", "live_...");
var message = new SmsMessage
{
body = "SMS send from C#, greetings Roel.",
originator = 31611111111, // Sender
recipients = new long[] { 31622222222 } // Receivers
};
HttpResponseMessage response = await client.PostAsJsonAsync("messages", message);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("succes!");
}
}
}
}
public class SmsMessage
{
/// <summary>
/// Example: This is a test message.
/// </summary>
public string body { get; set; }
/// <summary>
/// Example: 31611111111
/// </summary>
public long originator { get; set; }
/// <summary>
/// Example: new long[] { 31622222222 } 
/// </summary>
public long[] recipients { get; set; }
}
}

One of the most important things to remember: In C# and JavaScript, object references are passed to functions by value not by reference

By default C# and JavaScript pass object references by value not by reference, but what does that mean?

Well if you assign an object to a variable, this variable is just a pointer to that object in memory.

(Examples in C#)

var person = new Person
{
Id = 2,
Name = "John"
};

The variable person is just a pointer to the object in memory, the memory contains the object { Id = 2, Name = “John”}

When passed to a function, a copy of this pointer is supplied to the function, not the object itself.

So when you update properties of the object in the function, the variable outside the function will get updated.

 

But when you set the object to NULL in the function, the variable outside the function will NOT be set to NULL.

 

In C# you can override this by adding the “ref” keyword before the parameter, in that case the pointer of the variable will be passed and thus setting the object to null in the function will set the variable outside the function to NULL.

 

Some unit test to explain this:

namespace Test
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;      
[TestClass]
public class Research
{
[TestMethod]
public void Update_object_properties_should_update_variable()
{
var person = new Person
{
Id = 2,
Name = "John"
};
UpdateObjectProperties(person);
Assert.IsTrue(person.Name == "Mike");
}
public void UpdateObjectProperties(Person person)
{
person.Name = "Mike";
}
[TestMethod]
public void Update_object_pointer_should_not_update_variable()
{
var person = new Person
{
Id = 2,
Name = "John"
};
UpdateObjectPointer(person);
Assert.IsTrue(person.Name == "John");
}
public void UpdateObjectPointer(Person person)
{
person = null;
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
}

 

image

 

More info can be found at:

http://stackoverflow.com/questions/9717057/c-sharp-passing-arguments-by-default-is-byref-instead-of-byval

http://jonskeet.uk/csharp/parameters.html

http://jonskeet.uk/csharp/references.html

How to rename an user in Active Directory with C#

 

If you want to rename an user in Active Directory by using C#, you can use the following code:

using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("This application will rename a user in active directory.");
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Enter domain:");
string domain = Console.ReadLine();
Console.WriteLine("Connecting to domaincontroller.");
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
{
if (context == null)
{
throw new ApplicationException("Domain not found.");
}
Console.WriteLine("Enter current username (e.g. john):");
string currentUserName = Console.ReadLine();
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, currentUserName))
{
if (user == null)
{
throw new ApplicationException("User not found.");
}
Console.WriteLine("Enter new username (e.g. john2):");
string newUserName = Console.ReadLine();
using (DirectoryEntry entry = (DirectoryEntry)user.GetUnderlyingObject())
{
Console.WriteLine("Setting account properties in active directory.");
entry.InvokeSet("uid", newUserName);
entry.InvokeSet("sAMAccountName", newUserName);
entry.InvokeSet("userPrincipalName", string.Format("{0}@{1}", newUserName, domain));
entry.CommitChanges();
Console.WriteLine("Rename common-name (CN).");
entry.Rename("CN=" + newUserName);
entry.CommitChanges();
Console.WriteLine("User successfully renamed.");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine("Press enter to continue...");
Console.ReadLine();
}
}
}

Most developers say: code comments are evil, I agree and I don’t agree…

Most developers I know say: don’t write any comments, because they are evil and little puppies will dye if you do.

The arguments they give:

  • code comments will get out of date
  • code should be self explaining.

 

I totally agree, but there are counter arguments, to write comments:

 

Code comments out of date?

If you look at the AngularJS code, the comments are used to generate the documentation on the site, so when the comments are not updated, the documentation on the site will be outdated. This is one trick to keep your comments up to date.

 

Code should be self explaining

I totally agree, code should be self explaining!

But it’s not the problem, that code comments are written, but the way they are written.

The most comments explains what the code does, not why. I do not care, “what” the code does, I want to know “why” it is written and “why” it is written in the manner it is written.

 

I recently had to make changes to C# code that was written ages ago (13 months in this case). I red the code and the “WTF counts per minute” started to pile up. I red the code comments and they exactly explained what the code did, but I am an experienced C# developer, I know what the code does, because I can read C#, but I did not understand why the code was written and why it was written in the way it was written.

So I checked source control to find this “terrible” developer that had written this code to ask him, what on earth he was thinking and as you will probably expect it was me, myself and I, 13 months ago Smile.

 

So please, if you write inline comments, don’t write “what the code does”, write “why” the code is written and “why” you write it in the way it is written”.

Post arbitrary JSON data to a MVC controller action method

If you want to sent arbitrary JSON data to a MVC controller action method, you can use the following code:

[HttpPost]
public ActionResult HandleRequest()
{
// Read the RAW JSON from the request, 
// because MVC does not support a dynamic input parameter or an input parameter of type JObject.
// ASP .NET Web API does support a dynamic input parameter or an input parameter of type JObject.
string json = new StreamReader(this.Request.InputStream).ReadToEnd();
dynamic clientData = JObject.Parse(json);

Reliable bring external process window to foreground with C#

If you want to reliable bring the main window of an external process to the foreground in C#, use the “simulate alt key” technique found at: http://stackoverflow.com/questions/10740346/setforegroundwindow-only-working-while-visual-studio-is-open

Just start Notepad, then run the following test in Visual Studio.

It should bring Notepad as a maximized window in the foreground.

namespace Research.EndToEndTests
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[TestClass]
public class ResearchTester
{
[TestMethod]
public void Test()
{
Reliable_set_window_to_forground();
Assert.IsTrue(true);
}
public void Reliable_set_window_to_forground()
{
Process[] processes = Process.GetProcesses();
foreach (Process proc in processes)
{
if (ProcessIsNotepad(proc))
{
ActivateWindow(proc.MainWindowHandle);
}
}
}
public bool ProcessIsNotepad(Process proc) 
{
return proc.MainWindowTitle.EndsWith("Notepad", StringComparison.InvariantCultureIgnoreCase);
}
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x1;
private const int KEYUP = 0x2;
private const int SHOW_MAXIMIZED = 3;
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void ActivateWindow(IntPtr mainWindowHandle)
{
// Guard: check if window already has focus.
if (mainWindowHandle == GetForegroundWindow()) return;
// Show window maximized.
ShowWindow(mainWindowHandle, SHOW_MAXIMIZED);
// Simulate an "ALT" key press.
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// Simulate an "ALT" key release.
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// Show window in forground.
SetForegroundWindow(mainWindowHandle);
}
}
}

Changing C# on the fly (without stopping the debugger) in an ASP .NET vNext web application with Visual Studio 14 CTP3

The roslyn compiler found in Visual Studio 14 enables us, to adjust C# code during runtime, by compiling the new C# code in-memory. Now we can edit the UI part (HTML, CSS, JavaScript) of a single page app, including the backend C# ASP .NET Web Api service dynamically in runtime.

 

On of the things, that disrupts my workflow, when creating a single page app with AngularJS, backed by a web api C# service in Visual Studio 2013, is the fact that, when I find a bug in my C# code while testing the UI, I have to stop the debugger, adjust the web api C# code, re-compile, re-run and then recreating state in the web app before I can resume testing the UI.

This pain will go away, when using Visual Studio 14

 

Download and install Visual Studio 14 CTP 3 from http://msdn.microsoft.com/en-US/subscriptions/downloads/

Open Visual Studio, choose File > New > Project …

 

image

 

image

 

Start the web application by pressing CTRL + F5 (so don’t start the debugger).

 

image

 

Click on the Contact page in the browser:

You will see the text “Your contact page”.

image

 

Now go to the Controllers\HomeController.cs

image

 

Adjust the the C# code: ViewBag.Message = "Your contact page.";

to

ViewBag.Message = "My contact page.";

 

image

 

Save the file and in the browser press F5, you might see a short delay, because the roslyn compiler is now dynamically compiling the code.

 

The C# code is changed without disrupting my workflow.

 

image