Sunday, 15 May 2016

Entity Framework 7– Unapplying Migrations to Remove Migrations

In development environments accidents can happen. You could add a wrong migration and want to roll back. The option is there to remove the last migration. But if it is applied to the local db, then the changes in local db should be unapplied before removing the migration.

Let’s look at how to do this with EF 7, step by step.

The problem

Accidently view model entities added as tables to the local db.image

Last added migration has created the view model entities in database.image

image

This has happened because db context class got updated with unwanted namespace and property, while creating a view with Visual Studio.image

How to fix?

Remove the unwanted namespace and property from the db context class.image

Remove the last migration. But this is giving the below error.

dnx ef migrations remove

The migration '20160514193811_SessionTime' has already been applied to the database. Unapply it and try again. If the migration has been applied to other databases, consider reverting its changes using a new migration.image

Option1: If the changes applied to other databases, other than local development db, the way to fix should be via a new migration correcting the issues. It is possible to remove the unwanted namespace and property from the db context class and then create a new migration, which will have drop statements to drop unwanted tables.image

image

image

Option2: If the changes are only in local DB, unapply changes to local db by, updating the database into last known good migration. image

dnx ef database update RemoveEventTimeimage

This will remove last migration changes from local db.image

image

But running is applying the unwanted migration again and remove is failing.image

image

This is because once migration instance created using command line the changes are getting reapplied again for the, latest migration, which is the unwanted migration. The attempt to remove that get failing.

To fix this comment the db context class constructor applying the migrations.image

Note: It is not a good implementation to have constructor calling Database.Migrate(). Better implementation would be having it as a separate method in the db context class and calling it explicitly, from startup.image

image

A discussion on the same can be found here, which is saying the implementation of Database.Migrate() in the constructor is awful, which is exactly the correct way to introduce bad coding Smile

Make sure after fixing the db context class, you have compiled the solution with a rebuild.image

With this fix to “awful” code, in db context Option 2, reverting the migration by unapplying and remove works fine.image

image

image

Tuesday, 10 May 2016

Deploy ASP.Net Core 1.0 to Remote IIS Using MSDeploy

In order to run ASP.Net Core 1.0 in IIS you need to setup IIS with HttpPlatformHandler instructions are here. IIS configurations for ASP.NET Core 1.0 can be found here.

Follow the below steps to use msdeploy to deploy ASP.NET Core 1.0 from a remote machine

1. Install web deploy 3.5, using webpi in remote IIS machine. Make sure you have availability of Deploy menu in IIS. (close and open IIS)image

image

2. Now install Web deploy 3.6 in the IIS  machine, hosting the web site. image

3. Configure web deploy publishing for the site.image

4. In IIS machine hosting the site, create a user say “deployadmin” and add it to administrators group.image

5. Setup deployment execution machine with web deploy 3.5 and the with web deploy 3.6 using webpi

6. Using the below PS script you can deploy the site. To run this script powershell 5.0 is required. Download powershell 5.0 from here.

.\DeploySite.ps1 -MSDeployPath "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3" -packageWWWRoot "C:\temp\Portal\wwwroot" -websiteName DeployTest -targetFQDN yourserver.yourdomain -deployUser yourserver\deployadminuser -deployUserPwd deplyuserpwd

param($MSDeployPath, $packageWWWRoot, $websiteName, $targetFQDN, $deployUser, $deployUserPwd)

. "$MSDeployPath\msdeploy" -verb:sync -source:iisapp=$packageWWWRoot -dest:iisapp="$websiteName",computerName=$targetFQDN,username=$deployUser,password=$deployUserPwd -enablelink:contentlibextension -allowUntrusted

image

image

To solve the issue ERROR_USER_NOT_ADMIN follow the instructions here.image

Registry fix (bit of a hack) for target IIS machine. image

Wednesday, 4 May 2016

Build ASP.NET Core 1.0 with TFS 2013.4 Build Server

To build ASP.NET Core 1.0 with Team foundation 2013.4 XAML builds, following steps should be done.

Prepare the build server
1. Install VS 2015 in the build server
2. Install below by login to the build server as build service user (tfsbuildsvc in this case). Install chocolatey in build server (its easy to do other installations when chocolatey is installed.)

  • To install chocolatey run below command in PS window(run as administrator)
iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
  • install nodejs with below command
choco install nodejs.install
  • Change directory to nodejs install path (C:\Program Files\nodejs)
  • Install bower and gulp for global use using below commands

npm install bower -g
npm install gulp -g

Build Scripts – Pre Build
Pre build script to set dnx is required. use below script.

# bootstrap DNVM into this session.
&{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}

# load up the global.json so we can find the DNX version
$globalJson = Get-Content -Path $PSScriptRoot\..\..\MainSolution\global.json -Raw -ErrorAction Ignore | ConvertFrom-Json -ErrorAction Ignore

if($globalJson)
{
    $dnxVersion = $globalJson.sdk.version
}
else
{
    Write-Warning "Unable to locate global.json to determine using 'latest'"
    $dnxVersion = "latest"
}

# install DNX
# only installs the default (x86, clr) runtime of the framework.
# If you need additional architectures or runtimes you should add additional calls
# ex: & $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -r coreclr
& $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -Persistent

# run DNU restore on all project.json files in the src folder including 2>1 to redirect stderr to stdout for badly behaved tools
Get-ChildItem -Path $PSScriptRoot\..\..\MainSolution -Filter project.json -Recurse | ForEach-Object { & dnu restore $_.FullName 2>1 }

dnvm upgrade -r clr

Make sure to add global.json file to the location of the solution file and check it in to version control.

image

Global.json content below specifying version globally.

{
  "projects": [ "Portal" ],
  "sdk": {
    "version": "1.0.0-rc1-update1"
  }
}

Build Scripts –  Post Build Publish Script
In publish script environment variable settings to path should be added with below. This will allow to run PrePublish script specified in project.json
$env:Path += ";C:\Program Files\nodejs;C:\Users\tfsbuildsvc\AppData\Roaming\npm"

image
param($solutionName, $projectName, $projectPath, $buildConfiguration, $buildStagingDirectory)
 
$VerbosePreference = "continue"
$ErrorActionPreference = "stop"
     
&{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}
$globalJson = Get-Content -Path "$PSScriptRoot\..\..\$solutionName\global.json" -Raw -ErrorAction Ignore | ConvertFrom-Json -ErrorAction Ignore
 
if($globalJson)
{
    $dnxVersion = $globalJson.sdk.version
}
else
{
    Write-Warning "Unable to locate global.json to determine using 'latest'"
    $dnxVersion = "latest"
}
 
& $env:USERPROFILE\.dnx\bin\dnvm install $dnxVersion -Persistent
 
$dnxRuntimePath = "$($env:USERPROFILE)\.dnx\runtimes\dnx-clr-win-x86.$dnxVersion"
     
#& "dnu" "build" "$PSScriptRoot\src\$projectPath" "--configuration" "$buildConfiguration"
Write-Warning "Path is $PSScriptRoot\..\..\$projectPath"

$env:Path += ";C:\Program Files\nodejs;C:\Users\tfs10buildsvc\AppData\Roaming\npm"

$publichLocation = "$buildStagingDirectory\$projectName"
[IO.Directory]::CreateDirectory($publichLocation)
 
& "dnu" "publish" "$PSScriptRoot\..\..\$projectPath" "--configuration" "$buildConfiguration" "--out" "$publichLocation" "--runtime" "$dnxRuntimePath"

Check in Build Scripts
Scripts are in below folder structure. Path changes ($PSScriptRoot\..\..\) to script required if it is checked in to different folder hierarchy.

image
Set Build definition to Run Build scripts
In build definition set to execute scripts as shown below. Set tool version in build definition to use VS 2015 tools. /tv:14image
RunPreBuildScript.ps1
Invoke-Expression "$PSScriptRoot\SetDNX.ps1"

RunPostBuildScript.ps1

param($buildConfiguration)

Invoke-Expression "$PSScriptRoot\PublishWebSite.ps1 -solutionName MainSolution -projectName WebPortal -projectPath 'MainSolution\WebPortal' -buildConfiguration $buildConfiguration -buildStagingDirectory $Env:TF_BUILD_BINARIESDIRECTORY"

RunPreBuildScript and RunPostBuildScript are used since there could be more scripts that need to be executed and only one is allowed in XAML build definition. These script could invoke other scripts.

You could run into

npm WARN deprecated graceful-fs@3.0.8: graceful-fs version 3 and before will fail on newer node releases. Please update to graceful-fs@^4.0.0 as soon as possible.
npm WARN deprecated graceful-fs@2.0.3: graceful-fs version 3 and before will fail on newer node releases. Please update to graceful-fs@^4.0.0 as soon as possible.
npm WARN deprecated npmconf@2.1.2: this package has been reintegrated into npm and is now out of date with respect to npm
npm ERR! cb() never called!
npm ERR! not ok code 0

image
This is discussed in here. To disable this warning raising as an error change the project.json prepublish script section as below (Add --loglevel=error to npm install).image
You can get a successful build with TFS build 2013.4, for ASP.NET Core 1.0.image
image

Configure On-Prem Agent for Visual Studio Team Services

To configure an on premise agent for VS Team Services, follow the steps specified below.

Navigate to VS Team Services admin mode, and go to control panel. select the Agent Pool tab.image

To setup a new pool for On Premise agents click New pool. Provide appropriateimage

image

Go to the on premise machine and navigate to VS Team services Control Panel Agent pools tab. Click on Download agent.image

image

Extract the downloaded zip file.image

Run a command prompt as Administrator, execute ConfigureAgent.cmdimage

Provide a name for agent, VS Team Services url, agent pool and a local working directory.image

A popup will ask for the credentials for the VS Team Services account. Once provided agent will be configured.image

image

In the DefaultCollection Agent queues tab you can see the on premise agent availability. It is visible on Agent pools tab as well.image

image

In a build definition you can set new agent pool.image

image

image

azureps above is demand for azure powershell. Agent version should be greater than 1.87. You can setup Azure PowerShell in your agent and then add the capability to agent. This then can be used as a demand in build or release definition.image