In my previous post (http://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

Tags: ,

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(http://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).

Tags: ,

Roel van Lisdonk on July 9th, 2015

I didn’t want to add the NuGet packages of my Visual Studio solution to TFS, because I download all NuGet packages during build.

 

image

 

To exclude all NuGet packages from TFS:

  • Add a folder “.nuget” to the folder that also contains the “packages” folder and in most cases the “solution file”.
    • add a file to the “.nuget” folder with the name “NuGet.config”
      • contents of the file:
      • <?xml version="1.0" encoding="utf-8"?>
        <configuration>
          <solution>
            <add key="disableSourceControlIntegration" value="true" />
          </solution>
        </configuration>

  • Add a file “.tfignore”  to the folder that also contains the “packages” folder and in most cases the “solution file”.
    • contents of the file:
      • \packages

 

More information: http://stackoverflow.com/questions/26604506/tfs-vs-2013-ignore-all-nuget-packages

Tags:

 

Installation

If you want to use Active Directory Lightweight Directory Services (ADLDS) on Windows 10 you will have to enable (install) it from the “Windows Features” dialog:

Control Panel \ Programs and Features \ Turn Windows features on or off:

 

image

 

After the installation you can start the configuration of ADLDS by starting the "Active Directory Lightweight Directory Services Setup Wizard":

 

image

 

Found at: C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Active Directory Lightweight Directory Services Setup Wizard

 

 

 

 

Configuration

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

image

 

 

 

Create User

To add users to the ADLDS you must start the ADSI Edit:

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\ADSI Edit

 

image

 

 

image

 

 

 

image

 

image

 

image

Now the user is created, you can set a password by using the “reset password” option.

Just right click on the user:

 

image

Tags:

Roel van Lisdonk on June 19th, 2015

 

If you want to undo some changes from a specific user, you can use:

 

Change directory to folder containing "tf.exe"
    • cd "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE"

Check the status of checked out files, to see correct "account"
    • tf status "$/TFS/Path/To/Folder/To/Search/For/Pending/Changes" /s:123.123.123.123 /u:* /recursive /format:detailed

Undo pending changes
    • tf undo /workspace:"S001";MyDomain\myUserName "$/TFS/Path/To/Folder/To/Search/For/Pending/Changes" /recursive

Tags:

I wanted a ASP .NET MVC view (*.cshtml) to render on the server and pass the static text contained in the the ASP .NET project resource file to an Angular controller, so on the initial page request, all static data is returned to the client. Dynamic data, like grid content would then be requested by a separate JSON call.

The resource data is passed to the Angular controller by using ng-init.

 

For the sake of this blog post I stuffed everything in one *.cshtml page, including CSS en JavaScript.

Of course this would be separate files in an real application.

 

Project resource file

image

 

Layout.cshtml

 

<!DOCTYPE html> <html xmlns:ng="http://angularjs.org" id="ng-app" ng-app="app"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Send initialization data from HTML to Angular controller</title> <style> /* Add some initial styling. */ html, body { background-color: #F1F1F1; font-family: "Open Sans", sans-serif; font-size: 13px; height: 100%; } body { margin: 20px; } [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } </style> <!-- Library scripts --> <script src="https://code.angularjs.org/1.4.1/angular.min.js"></script> </head> <body ng-cloak> @RenderBody() <div> <div ng-controller="main" ng-init="resources={ textFromResource: '@WebApplication1.Properties.Resources.TextFromResource'}"> <h1>{{ title }}</h1> {{ resources.textFromResource }} </div> </div> <script> // Angular module. (function () { "use strict"; angular .module("app", []); }()); // Angular controller. (function () { "use strict"; function controller($scope) { $scope.title = "Show ASP .NET MVC resoure (*.resx) data to user on initial load."; } angular .module("app") .controller("main", ["$scope", controller]); }()); </script> </body> </html>

 

 

Result

image

Tags: , ,

Roel van Lisdonk on June 18th, 2015

 

image

 

Found my solution at: http://timourrashed.com/how-to-fix-shellexecute/ and http://www.pcrules.com/article/view/53

Just make sure you delete this key:

 

image

 

And create a key:

 image

image

 

"C:\Program Files (x86)\Notepad++\notepad++.exe" "%1"

In SQL Server a common table expression can be used to calculate totals / subtotals of a table containing hierarchical data:

 

-- Create test data:
if object_id('tempdb..#Hierarchy') is not null
begin
    drop table #Hierarchy
end

create table #Hierarchy (
    Id int not null,
    ParentId int null,
    Amount int not null
)

insert into #Hierarchy (Id, ParentId, Amount) values
    (1, null, 100)
,    (2, 1, 100)
,   (3, 1, 100)
,   (4, 1, 100)
,   (5, 4, 100)
,   (6, 4, 100)
,   (7, 4, 100)
,   (8, 7, 100)

;with CTE (ParentId, Id, Amount, IsParent)
as
(
    -- Add all records as "anchor", because foreach record we are going to calculate the total amount.
    select    h.ParentId
    ,        h.Id
    ,        h.Amount
    ,        0 as IsParent
    from    #Hierarchy h
    union all
    -- Recursively add parent records until root parent foreach record in "anchor".
    select    h.ParentId
    ,        h.Id
    ,        h.Amount
    ,        1 as IsParent
    from    CTE c
    join    #Hierarchy h on c.ParentId = h.Id
)

select        c1.Id
,            c1.ParentId
,            sum(c1.Amount) as TotalAmount
,            case when sum(c1.IsParent) > 0 then 1 else 0 end as IsParent
from        CTE c1
group by    c1.Id, c1.ParentId

Result

image

Tags:

 

If you want to filet the SQL Server Profiler trace, so only queries send from your laptop are captured, just filter on HostName:

 

First:

Enable “Show all events”

Enable “Show all columns”

 

image

 

Click on [Column Filters…]

“Select Column” [HostName]:

image

 

Enter the name of the “laptop”:

 

image

Tags:

Roel van Lisdonk on June 4th, 2015

If you manually want to get / use Angular services in TypeScript you can use the following code:

 

/// <reference path="../libraries/angular/angular.d.ts" />

module app {
    "use strict";

    var appModule = angular.module("app", []);
    var injector: angular.auto.IInjectorService = angular.injector(["ng"]);
    var httpService: angular.IHttpService = injector.get("$http");
    var qService: angular.IQService = injector.get("$q");
}

Tags: