Don’t use import-css directives when bundling

Consider the following code:

public ActionResult Index( )
{
  StyleBundle b = new StyleBundle( "~/b1");
  b.Include( "~/Content/base.css");
  BundleTable.Bundles.Add( b);
  return( View( "~/Src/b.cshtml"));
}

This Controller method creates a bundle and includes a css-file located at ~/Content/base.css and then returns the view. The css file looks like this :

@import "b2.css";
body
{
  font-family: Verdana;
  font-size: small;
}

This file imports another css file b2.css. This includes a style to render the ‘important’-div red:

#important
{
  color: #FF0000;
}

The last line in our C#-code renders file ~/Src/b.cshtml :

@System.Web.Optimization.Styles.Render( "~/b1")
<div id="important">This is important</div>

This file calls the Render from System.Web.Optimization.Styles. The purpose of the Optimization library is to minimize css-files and scripts when running a release build, saving you the hassle of manually creating minimized files. If you call on this Action in Visual Studio, optimisation is disabled because you’re running in debug-mode resulting in the following view :

result in debug mode

result in debug mode

You see a nice red sentence, just like expected. If you now publish a release build of this code, you’ll see the following :

release-mode

release-mode

The red sentence has turned black. What happened ? If you inspect the network traffic using F12-network, you see the following :

release-build traffic

release-build traffic

The imported css file is not found on the network, caused by optimisation failing to fetch the correct paths for imported css files.

Ergo : Don’t use bundling with imported css-files.

If in full control of your css-files, then don’t import css files using the ‘import’-directive. If you’re not in control of your css files (using jQuery, Openlayers, etc..) then don’t optimize your css files using bundling.

Notes:

  1. Optimisation failing isn’t noticed until you deploy a release build. Even if you run a release build local before deploying, a cached css maybe read thus fooling you. If you would inspect network traffic on a release build locally before deploying, you’d see it fails
  2. Optimization is turned on by the following line in Web.Config :
    <compilation debug="false" targetFramework="4.0"/>
    

    If you publish a release build, the attribute debug="false" is absent which results in ASP.Net using the default which is false:

    <compilation targetFramework="4.0"/>
    
  3. To quickly see if your optimized styles are rendering correct, you can also use the following statement in your C#-code :
    BundleTable.EnableOptimizations = true;
    
Posted in Bundling, Minification, MVC4, Visual Studio 2012 | Leave a comment

Using SSL during a certificate request

If you need to request a certificate to use for a website, you need to generate a certificate request resulting in a certreq.txt you need for buying the actual certificate. Once the certreq.txt is generated, you can not use another certificate for your website because your request is still pending. The below figure shows the dialog you’ll see when trying to setup secure connections for a website for which a certificate request is pending:

request-pending

request-pending

There can be days, even weeks between the actual request for buying a certificate and the moment it is delivered, which voids SSL-communications for your website. To avoid this, you can create a new website, then use a development certificate and use that for your site until your actual certificate is delivered.

Creating a temporary website

Creating a temporary website

If your actual certificate is delivered, you need to delete your temporary website and you can use the actual certificate.

Posted in Certificate, MVC4 | Leave a comment

Intergraph issues database will be public available

Intergraph has an internal database for keeping track of all kinds of software issues, if you file a Trouble- or Change Request, it will end up in this database. This database will become public available in the 3rd quarter of 2013 according to Intergraph sources at Hexagon 2013. Also, if a problem gets fixed, the solution will be described so you know if applies to you. All this information will be public accessible and indexed by Google, so if you are facing a problem in G/Technology (or any other Intergraph product) google will find it and it will show up in the results of your search.

Posted in G/Technology, Intergraph | Leave a comment

Netviewer extensions

It doesn’t take much to create a Netviewer extension:

  1. Derive a class from Microsoft.Practices.CompositeUI.ModuleInit
  2. Create a constructor with a [ServiceDependency()] WorkItem argument
  3. Modify your ProfileCatatalog.xml

The class would look like this:

namespace NetviewerLibrary
{
	#region -- Using directives --
	using System;
	using System.Reflection;
	using Microsoft.Practices.CompositeUI;
	using d = System.Diagnostics.Debug;
	#endregion

	public class Init: ModuleInit
	{
	    public Init([ ServiceDependency()] WorkItem rootWorkItem)
	    {
		   d.WriteLine( "Init");
	    }
	}
}

This code is using a pattern from the Microsoft Enterprise Library version 2.0 (no longer supported by Microsoft) for setting up an external library to be invoked by an application. The external library in this case is your extension, the application is Netviewer. All it takes for Netviewer to invoke the extension is a class derived from Microsoft.Practices.CompositeUI.ModuleInit and create a constructor with an Microsoft.Practices.CompositeUI.ServiceDependency argument. In line 10 a Microsoft.Practices.CompositeUI.ModuleInit-derived class is declared and at line 12 you can see the constructor. If your extension is compiled to an assembly called ‘NetviewerLibrary1′, you include your extension in the ProfileCatalog.xml file and add your command to IngrViewer.exe.config, Netviewer will invoke your extension.

This is the ProfileCatalog.xml :

<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile/2.0">
  <Section Name="Apps">
    <Modules>
      <ModuleInfo AssemblyFile="GTechnology" />
      <ModuleInfo AssemblyFile="NetviewerCommand.dll" />
    </Modules>
  </Section>
</SolutionProfile>

This is not very useful other then illustrating what it takes for Netviewer to invoke your extension. Netviewer works with commands, and each extension can have one more or of it. The ProfileCatalog.xml is where you define your extensions, the IngrViewer.exe.config is where you define your commands. In order to do something useful, we need to add our command to IngrViewer.exe.config and extend our code with a command handler:

This is the line in IngrViewer.exe.config which adds the command:

<command name="NetviewerCommand1" autocreate="true" tooltip="NetviewerCommand1" label="CustomCommand1" />

This is the code:

namespace NetviewerLibrary
{
  #region -- Using directives --
  using System;
  using System.Reflection;
  using Microsoft.Practices.CompositeUI;
  using Microsoft.Practices.CompositeUI.Commands;
  using Intergraph.OneMobile.Infrastructure.Interface;
  using d = System.Diagnostics.Debug;
  #endregion

	public class Init: ModuleInit
	{
		public WorkItem WorkItem{   get; set;   }

		public Init([ ServiceDependency()] WorkItem rootWorkItem)
		{
			d.WriteLine( "Init");
			this.WorkItem = rootWorkItem;
		}

		public override void Load()
		{
			d.WriteLine( "Load");

			base.Load();

			ControlledWorkItem workItem = this.WorkItem.WorkItems.AddNew();
			workItem.Controller.Run();
		}
	}

	public partial class MyController :
		Intergraph.OneMobile.Infrastructure.Interface.WorkItemController
	{
		[ CommandHandler( "NetviewerCommand1")]
		public void MyCommand_Handler( object sender, EventArgs eventArgs)
		{
			d.WriteLine( "MyCommand_Handler");
		}
	}
}

If you now run Netviewer, there will be an extra button with a label “NetviewerCommand1″ and if you click it, your commandhandler will be invoked.

Netviewer command

Netviewer command

Now let’s turn this extension in something useful, for instance placing a pinpoint. We want our command to ask the user to click in the Window and then place a pinpoint at the cursur. To do so, we need to extend our code with the following:

  1. A reference to the Netviewer MapviewService instance for setting up eventhandlers
  2. A Commandhandler for a left-mouse click
  3. Infrastructure code

The modified code looks like this:

namespace NetviewerLibrary
{
  #region -- Using directives --
  using System;
  using System.Reflection;
  using Microsoft.Practices.CompositeUI;
  using Microsoft.Practices.CompositeUI.Commands;
  using Microsoft.Practices.CompositeUI.EventBroker;
  using Intergraph.OneMobile.Infrastructure.Interface;
  using Intergraph.OneMobile.Map.Interface.Constants;
  using Intergraph.OneMobile.Map.Services;
  using Intergraph.Controls.oneViewer;
  using d = System.Diagnostics.Debug;
  #endregion

  public static class Global
  {
    public static int CallCount {   get; set;   }
  }

 public class Init: ModuleInit
 {
    public WorkItem WorkItem      {   get; set;   }

      public Init([ ServiceDependency()] WorkItem rootWorkItem)
      {
        d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

        this.WorkItem = rootWorkItem;
      }

      public override void Load()
      {
        d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

        base.Load();

        ControlledWorkItem workItem = this.WorkItem.WorkItems.AddNew();
        workItem.Controller.Run();
      }
  }

  public partial class MyController :
    Intergraph.OneMobile.Infrastructure.Interface.WorkItemController
  {
    #region -- Properties --
    public IMapViewService  MapviewService    {   get; set; }
    public string      OldMapLocateMode  {   get; set; }
    #endregion

    [ CommandHandler( "NetviewerCommand1")]
    public void MyCommand_Handler( object sender, EventArgs eventArgs)
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      this.MapviewService.SetStatusBar( "Click to place pinpoint");

      SwitchMapMode  ( );
      SetupEventSink  ( );
    }

    [ EventSubscription( EventTopicNames.MapViewLoaded)]
    public void MapViewLoaded_Handler( object sender, EventArgs eventArgs)
    {
        d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

        this.MapviewService = WorkItem.Services.Get();
    }

    private void SwitchMapMode( )
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      this.OldMapLocateMode = this.MapviewService.GetMapMode( );
      this.MapviewService.SetMapMode( Intergraph.Controls.oneViewer.MapModes.Custom);
    }

    private void SetupEventSink( )
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      this.MapviewService.RedlineLButtonDown    += new Intergraph.Controls.oneViewer.RedlineButtonEventHandler( MapviewService_RedlineLButtonDown );
    }

    void MapviewService_RedlineLButtonDown( object sender, Intergraph.Controls.oneViewer.RedlineButtonEventArgs e )
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      string  point    = string.Format( "{0}, {1}", e.XWorldPos, e.YWorldPos);
      string  pointType  = "UOR";
      string  fontName  = "G_MapPins";
      short  fontSize  = 24;
      string  fontColor  = "FF0000"; // --- Red
      string  charValue  = "F";    // --- Solid filled push pin

      this.MapviewService.PlaceLocationPinAtPoint(
                    point,
                    pointType,
                    fontName,
                    fontSize,
                    fontColor,
                    charValue,
                    "POI");
      StopCommand( );
    }

    private void StopCommand()
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      RestoreMapMode  ( );
      ReleaseEventSink( );

      this.MapviewService.SetStatusBar( string.Empty);
   }

    private void RestoreMapMode( )
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      this.MapviewService.SetMapMode( this.OldMapLocateMode);
    }

    private void ReleaseEventSink( )
    {
      d.WriteLine( string.Format( "{0}.{1} ({2}):{3}", GetType().Name, System.Reflection.MethodInfo.GetCurrentMethod().Name, Global.CallCount++, string.Empty));

      this.MapviewService.RedlineLButtonDown -= new Intergraph.Controls.oneViewer.RedlineButtonEventHandler( MapviewService_RedlineLButtonDown );
    }
  }
}

After running this command, a pinpoint is placed to indicate some point of interest :

pinpoint

pinpoint

You can download the complete source for this example over here.

Posted in Netviewer, Visual Studio | Tagged , , , | 6 Comments