Tag: .NET

Bundling and Minification with Sitecore

There's various ways to add bundling and minification to a site, but one of the easiest is to use Microsoft's support from the Microsoft.AspNet.Web.Optimization package. This implementation has some great features including:

  • Automatically create the bundles and minify them as files are changed
  • Create unique urls to each version of a bundle to force browser refreshing of the file
  • Debug mode which outputs links to the raw files rather than the bundled minified version

The functionality is also fully compatible with Sitecore. To use it in your Sitecore solution follow these steps:

1. Add Microsoft.AspNet.Web.Optimization to your project from NuGet. This is the package from Microsoft that contains the functionality to do bundling and minification

 

2. Create your CSS and Javascript bundles. Where you put the logic for this is up to you but it will need to run when the application starts. Outside of Sitecore my main development is on bespoke ASP.NET MVC and Web API projects so I like to organise startup scripts into an App_Start folder and reference it from the Application_Start event in the global ascx file.

If you are running a Sitecore instance with multiple sites or if you do not have direct access to the production config files, it may be better to keep the logic separate and use a pipeline to create the bundles.

My bundle definitions would look something like this

1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.Optimization;
6
7public class BundleConfig
8{
9 public static void RegisterBundles(BundleCollection bundles)
10 {
11 bundles.Add(new ScriptBundle("~/bundles/scripts").Include(
12 "~/Scripts/jquery-{version}.js",
13 "~/Scripts/bootstrap.js"));
14
15 bundles.Add(new StyleBundle("~/bundles/css").Include(
16 "~/Content/bootstrap.css",
17 "~/css/site.css"));
18 }
19}

And in my Global.asax.cs file I would have some logic like this to call the other function

1protected void Application_Start(object sender, EventArgs e)
2{
3 BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles);
4}

3. Replace your Javascript/CSS references in your layout or rendering files with a call to render the bundle

Webforms

1<%: System.Web.Optimization.Scripts.Render("~/bundles/scripts") %>
2<%: System.Web.Optimization.Styles.Render("~/bundles/css") %>

MVC

1@Scripts.Render("~/bundles/scripts")
2@Styles.Render("~/bundles/css")

4. In your web.config file there are a couple of changes needed to get things to work.

First you need to set an ignore url prefix to stop Sitecore trying to resolve the URL to the bundle. In this example mine is called bundles (note: you should add the prefix the what is already in your config file. e.g. |/bundles)

1<!-- IGNORE URLS
2 Set IgnoreUrlPrefixes to a '|' separated list of url prefixes that should not be
3 regarded and processed as friendly urls (ie. forms etc.)
4-->
5<setting name="IgnoreUrlPrefixes" value="/sitecore/default.aspx|/trace.axd|/webresource.axd|/sitecore/shell/Controls/Rich Text Editor/Telerik.Web.UI.DialogHandler.aspx|/sitecore/shell/applications/content manager/telerik.web.ui.dialoghandler.aspx|/sitecore/shell/Controls/Rich Text Editor/Telerik.Web.UI.SpellCheckHandler.axd|/Telerik.Web.UI.WebResource.axd|/sitecore/admin/upgrade/|/layouts/testing|/bundles" />
6

Next a dependant assembly binding needs to be set up for Web Grease. Without it you will see an error about the Web Grease version number

1<dependentAssembly>
2 <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
3 <bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
4</dependentAssembly>

If you have done this and are still getting a version number error check the assembly binding tag. Older versions of Sitecore have the applies to property set which may be only applying the bindings to .Net 2 and you may be using .Net 4.

1<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" appliesTo="v2.0.50727">

5. If you are using IIS7 you will also need to make a change in your web.config file

1<system.webServer>
2 <modules runAllManagedModulesForAllRequests="true">
3 </modules>
4</system.webServer>

6. Publish your changes into your Sitecore site. Depending if you have compilation mode set to debug or not you will now either have a bundle reference for all your JavaScript and CSS or the individual file references.

Bundling and Minification error with IIS7

.NETs standard tools for bundling and minification are a great asset to the platform solving a lot of problems with only a few lines of code.

However if using IIS 7.0 you may run into a strange issue where the path to your bundles gets created but a 404 is returned whenever there accessed. The functionality is obviously installed and working otherwise the URL wouldn't be created, but a 404 clearly isn't what you want.

The solution lies in your web.config file by setting runAllManagedModulesForAllRequests to true

1<system.webServer>
2 <modules runAllManagedModulesForAllRequests="true">
3 </modules>
4</system.webServer>
Creating Training Buddy's Live Tile

Creating Training Buddy's Live Tile

Live tiles are probably the best known feature about Windows Phone. Unlike iOS's plain grid of app icons Microsoft designed their phones home screen to provide users with data without having to open the app. With Windows Phone 8 the feature was updated so that 3rd party apps like Training Buddy could offer full width tiles along with new layout templates.

Adding a live tile to your app is a great idea as it is one of the features users often look for when their choosing an app. The app store also handily points out if an app uses a live tile or not.

The Design

There are 3 tile templates to choose from when you add a live tile to your app. These are Flip, Iconic and Cycle.

Flip gives the illusion that the tile has a front and a back and will flip over after a few seconds.

Iconic has space for an image and a large number, a bit like the icon for messages and emails. When in its largest size there is also wide content zones that can contain text.

Cycle lets you choose 9 images that the app will Cycle through.

For Training Buddy I have used the Iconic template. You will probably find like myself that the type of app you are creating will more than likely determine what template you are going to use. As Training Buddy's live tile was ultimately going to show details of the users last activity, Iconic was the obvious choice. The smaller sizes don't really have enough space to give any activity stats and the large version gives you an additional space for a smaller image that was perfect for the activity type image (running, cycling, walking).

Another alternative is to make a completely custom design and write something in your app to render it as an image. You can then display the image using either the flip or cycle template.

The Code

The second reason you everyone should add live tiles to their app is because the code is so simple (this is the actual code from Training Buddy).

1// Application Tile is always the first Tile, even if it is not pinned to Start.
2 ShellTile TileToFind = ShellTile.ActiveTiles.First();
3
4 // Application should always be found
5 if (TileToFind != null)
6 {
7 string WideContent1 = "";
8 string WideContent2 = "";
9 string WideContent3 = "";
10 string activityLogo = "";
11 if (App.settings.LiveTile)
12 {
13 var lastActivity = (from a in AllActivities
14 orderby a.StartDateTime descending
15 select a).Take(1);
16
17 if (lastActivity.Count() &gt; 0)
18 {
19 if (App.settings.DistanceMeasurement == "Miles")
20 {
21 WideContent3 = "Distance: " + lastActivity.First().Distance.ToString("0.##") + " miles";
22 }
23 else
24 {
25 WideContent3 = "Distance: " + (lastActivity.First().Distance * 1.609344).ToString("0.##") + " km";
26 }
27 WideContent2 = "Date: " + lastActivity.First().StartDateTime.ToShortDateString();
28 switch (lastActivity.First().ActivityType.ToLower())
29 {
30 case "running":
31 WideContent1 = "Last Run";
32 break;
33 case "walking":
34 WideContent1 = "Last Walk";
35 break;
36 case "cycling":
37 WideContent1 = "Last Cycle";
38 break;
39 case "swimming":
40 WideContent1 = "Last Swim";
41 break;
42 }
43
44 activityLogo = "/Assets/" + lastActivity.First().ActivityType + "Black-70.png";
45
46 if (lastActivity.First().CaloriesBurned &gt; 0)
47 {
48 WideContent3 += " Calories: " + lastActivity.First().CaloriesBurned.ToString("0.#");
49 }
50
51 }
52
53 }
54
55 IconicTileData tileDate = new IconicTileData
56 {
57 Title = "Training Buddy",
58 WideContent1 = WideContent1,
59 WideContent2 = WideContent2,
60 WideContent3 = WideContent3,
61 IconImage = new Uri("/Assets/RunningBlack-150.png", UriKind.Relative),
62 SmallIconImage = new Uri(activityLogo, UriKind.Relative)
63 };
64
65 // Update the Application Tile
66 TileToFind.Update(tileDate);
67 }

First I'm finding the application tile. It is possible to create additional tiles for your app which is another great feature, but if you want to just update the main tile it will be the first one returned.

Next I'm checking to see if the user has turned on the live tile or not. If they haven't then I'm just setting the tile back to its default state.

The following lines are then getting the content to display on the tile and building up the strings on local variables.

Lastly and most importantly I'm creating a new instance of IconicTileData and setting each of its properties with the data to show. Then it's just a case of calling Update on the tile instance and providing it with the new IconicTileData object.

The Tile

And here's the result

Live tiles are really easy to create so if your developing an app you should definitely take the time to add one.