EnsureBclBuildImported pre-build check causing build errors in Visual Studio 2014 Update 4

After the recent update to Update 4 creating a new web application is by default causing a build error. The real error message is as follows:

This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=317567.

Editing the project file revealed the following line:

 <Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
    <Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
  </Target>

I tried installing the Microsoft.Bcl.Build through Nuget, but that installed version 1.0.21 instead of 1.0.14 and further the new version did not have the required tools\Microsoft.Bcl.Build.targets file.

The best option for me was to take out the lines from the project file.

Migrating MS-SQL 2008 to 2012

Pre-migration

  • Update the new servers to have the latest updates for both OS and MS-SQL
  • Setup Windows Failsafe cluster
  • Setup Always-On availability group, replicas and listener
  • Setup shared folder for storing backups from the old database servers
  • Setup shared folder for storing backup/synchronization data for the new database servers
  • Create a copy of the stored procedures used by jobs, and update them to work with availability group
  • Script the SQL server logins
  • If you want to change the databases to read-only mode, remove existing mirroring functionality for the databases

Migration

  1. Put up App_Offline.htm file for the web servers
  2. Take full backup of the database
  3.         BACKUP DATABASE [{DatabaseName}]
            TO DISK = N'{BackupSharedFolder}\{DatabaseName}.bak'
            WITH NOFORMAT, 
            INIT, 
            NAME=N'{DatabaseName}-Full Database Backup', 
            SKIP, 
            NO_COMPRESSION;
        
  4. Take Transactional backup of the database
  5.         BACKUP LOG [{DatabaseName}]
            TO DISK = N'{BackupSharedFolder}\{DatabaseName}.log'
            WITH NOFORMAT, 
            INIT, 
            NAME = N'{DatabaseName}-Transactional Backup', 
            NO_COMPRESSION;
        
  6. Set database to read-only mode
  7.         ALTER DATABASE [{DatabaseName}] SET  READ_ONLY WITH NO_WAIT;
        
  8. Connect to the new server
    1. Restore the database
    2.                 DECLARE @v_DefaultDataPath NVARCHAR(250) = CONVERT(NVARCHAR,SERVERPROPERTY('InstanceDefaultDataPath'));
                      DECLARE @v_DefaultLogPath NVARCHAR(250) = CONVERT(NVARCHAR,SERVERPROPERTY('InstanceDefaultLogPath'));
      
                      DECLARE @v_FinalDataFilePath NVARCHAR(250) = CONCAT(@v_DefaultDataPath,'\{DatabaseName}.mdf');
                      DECLARE @v_FinalLogFilePath NVARCHAR(250) = CONCAT(@v_DefaultLogPath,'\{DatabaseName}_Log.ldf');
      
                      DECLARE @v_LogicalDataFileName NVARCHAR(128), @v_LogicalLogFileName NVARCHAR(128);
      
                      DECLARE @tbl_FileList TABLE
                          (
                            LogicalName NVARCHAR(128) ,
                            PhysicalName NVARCHAR(260) ,
                            [Type] CHAR(1) ,
                            FileGroupName NVARCHAR(128) ,
                            Size NUMERIC(20, 0) ,
                            MaxSize NUMERIC(20, 0) ,
                            FileID BIGINT ,
                            CreateLSN NUMERIC(25, 0) ,
                            DropLSN NUMERIC(25, 0) ,
                            UniqueID UNIQUEIDENTIFIER ,
                            ReadOnlyLSN NUMERIC(25, 0) ,
                            ReadWriteLSN NUMERIC(25, 0) ,
                            BackupSizeInBytes BIGINT ,
                            SourceBlockSize INT ,
                            FileGroupID INT ,
                            LogGroupGUID UNIQUEIDENTIFIER ,
                            DifferentialBaseLSN NUMERIC(25, 0) ,
                            DifferentialBaseGUID UNIQUEIDENTIFIER ,
                            IsReadOnl BIT ,
                            IsPresent BIT ,
                            TDEThumbprint VARBINARY(32)
                          );
      
                      INSERT  INTO @tbl_FileList
                              EXEC
                                  ( 'RESTORE FILELISTONLY FROM DISK = N''{BackupSharedFolder}\{DatabaseName}.bak'''
                                  );
      
                      -- Extract the logical data file name from the backup file
                      SELECT  @v_LogicalDataFileName = LogicalName
                      FROM    @tbl_FileList AS tfl
                      WHERE   [tfl].[Type] = 'D';
      
                      -- Extract the logical log file name from the backup file
                      SELECT  @v_LogicalLogFileName = LogicalName
                      FROM    @tbl_FileList AS tfl
                      WHERE   [tfl].[Type] = 'L';
      
                      RESTORE DATABASE [EyeTeaERP] 
                          FROM  DISK = N'{BackupSharedFolder}\{DatabaseName}.bak' 
                          WITH  FILE = 1,  
                          MOVE @v_LogicalDataFileName TO @v_FinalDataFilePath,  
                          MOVE @v_LogicalLogFileName TO @v_FinalLogFilePath,  
                          NORECOVERY,  
                          NOUNLOAD;
      
                      RESTORE LOG [{DatabaseName}] 
                          FROM  DISK = N'{BackupSharedFolder}\{DatabaseName}.log' 
                          WITH  FILE = 1,  
                          NOUNLOAD;
                  
    3. Set the compatibility level matching the new version
    4.                 DECLARE @v_CompLevel INT = 0;
      
                      SELECT  @v_CompLevel = [d].[compatibility_level]
                      FROM    [sys].[databases] AS d
                      WHERE   [d].[name] = '{DatabaseName}';
      
                      IF @v_CompLevel < 110
                          BEGIN
                          -- 100 = 2008, 110 = 2012
                              ALTER DATABASE [{DatabaseName}] SET COMPATIBILITY_LEVEL = 110;
                          END
                  
    5. Add the database to the availability group
    6.                 ALTER AVAILABILITY GROUP [{AvailabilityGroupName}] ADD DATABASE [{DatabaseName}];
                  
    7. Take a full backup and transactional backup of the database to the synch folder share
  9. Connect to each of the secondary replicas
    1. Restore the database from the synch folder share in recovering mode
    2.                 RESTORE ... --AS ABOVE EXAMPLE +
                      WITH NORECOVERY
                      ...
                  
    3. Add the database to the availability group
    4.                 ALTER DATABASE [{DatabaseName}] SET HADR AVAILABILITY GROUP = [{AvailabilityGroupName}];
                  
  10. Restore server logins as needed on all replicas
  11. Connect to the availabiliy group and update the stored procedures with the modified copy created for working with Always-On availability group
  12. Setup the database mail, and all operators as needed in all of the replicas
  13. Restore the jobs to all of the replicas

Post-Migration

  • Update the configuration files connections string to point to the correct data source
  • Remove the App_Offline.htm file from the web servers
  • Confirm the failover is working as intended
  • Confirm the jobs are working as intended

Packaging

Package the above steps through an application created in language of your choice with care to set Connection Timeout in the connection string, and also appropriate CommandTimeout you are all set to go!

ASP.NET vNext, a quick look into the future

  1. MVC Controllers and WebAPI Controllers are now merged to form single controller class
  2. No need for physical folders for Areas, just decorating a Controller with [Area(“AreaName”)] gets you the desired result. But the problem is rendering engines still look for Views in Areas/{area name}/Views/{controller} path. So I guess you are better of placing your Controllers also in Areas/{area name}/Controller folder for better organizing them
  3. Route mapping looks a bit better now with the following syntax
  4. // MVC 6 route
    routes.MapRoute(
        name: &quot;Default&quot;,
        template: &quot;{controller=Home}/{action=Index}/{id?}&quot;
    );
    
  5. Even if you omit the {action} token from the route template, your Controllers can still respond to Action names corresponding to the Request method (GET, POST, UPDATE…). So, this neatly ties up the merger of MVC Controllers and WebAPI Controllers
  6. OWIN and Katana seems to be all the rage now, and for good reasons. So, the startup scripts looks thus (no need for Global.asax .. will miss you my friend!)
  7. using Microsoft.AspNet.Routing;
    using Microsoft.AspNet.Builder;
    using Microsoft.Framework.DependencyInjection;
    
    public class Startup
    {
        public void Configure(IBuilder app)
        {
            app.UseServices(services =&gt;
            {
                services.AddMvc();
            });
    
            app.UseMvc(routes =&gt;
            {
                routes.MapRoute(
                    name: &quot;Default&quot;,
                    template: &quot;{controller=Home}/{action=Index}/{id?}&quot;);
            });
    
        }
    }
    
  8. Now your Visual Studio project file is a simple JSON file, instead of the lengthy XML one

So, overall seems to be a nice upgrade.

Do check out Getting started with MVC 6 for a more elaborate look into the features.

Evolution of Visual Studio, a lot to love about!

A pleasant thing I noticed in the last few years regarding Visual Studio is it’s attitude towards supporting various open source languages and platforms.

You would have felt the same if you were looking to improve your IDE experience when trying to work on projects not based on the Microsoft .NET family. It may have been PHP or Python (with Django) or the D Language. It is quite nice to have the option to use a single IDE which you are familiar with to work on various language and platforms.

For anyone interested, below is my toolset/plugin setup for supporting the above mentioned language and platforms:

  1. PHP – [Free]: PHP Language Support / [Commercial]:PHP Tools for Visual Studio 2013
  2. Python – [Free]:Python Tools for Visual Studio / Project Page on CodePlex / Great intro by Hanselman
  3. D Language – [Free] Visual D / Project page on GitHub

To add to the good news, Visual Studio also supports Git for source control. Oh! and now we have Visual Studio Online Basic where you can have upto 5 users for Free with unlimited team projects (can be private too) which allows you to host your repo either based on TFS or Git! As an alternative you can also sign up and use BitBucket who are just cool with allowing free private repos and supporting custom domain names for accessing your repos.

What a good time to be in development, I am loving it! :)