Last night one of my CI builds ran into error by executing CMake based build with following error message:
Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the system
variable OPENSSL_ROOT_DIR: Found unsuitable version "0.9.8y", but required is at least "1.0.0"
Running following command to get current version of installed OpenSSL
$ openssl version -a
Gave me
Even though build was pretty recent the version number was still lower from that what I needed.
Since I am using Homebrew as package manager I could install newer version with following command.
$ brew install openssl
This however, downloads and builds OpenSSL into Homebrew local folder and does not change symlinks for currently installed version. Running the following command should update symlinks in /usr/bin
$ brew link openssl --force
But running the
$ openssl version -a
Showed the same version again so I had to update symlinks manually.
$ sudo ln -s /usr/local/Cellar/openssl/1.0.2d_1/bin/openssl /usr/bin
If you are running latest version of OSX (10.11.1 El Capitan at this moment) chances are that "System Integrity Protection" is enabled thus not allowing you to edit content under /usr/bin. You can check if this protection is enabled by running
If this protection is enabled here you can read about how to disable it before executing these commands.
There are many different reasons why you would want to deploy your builds from Visual Studio Online build system directly to your Azure VM. You might have test or staging environment running on Azure and you want to setup contentious integration build to run every time someone of you teammates checks something in. After each build run is finished it would be nice to for latest changes to be deployed automatically so that your test team can get latest version as soon as possible without you doing the deployment manually.
In essence we want to make WebDeploy profile for our application and instruct MSBuild running on Visual Studio Online to execute that profile once build run is finished. At the moment of writing this there are some improvements to this process on VS Online portal so you might check that out but my approach might be better for simpler use-cases.
Preparing your VM
It doesn't necessarily have to be Azure Cloud virtual machine, it could be machine running anywhere even your local on premise server as long as it is publicly accessible and running IIS Web Deploy agent. For sake of this example I will use Azure VM.
First we need to create Web Deploy Publishing profile for our application. In solution explorer right click on project you want to deploy and click on Publish.
When dialog pops up expand it by clicking on More Options to reveal Microsoft Azure Virtual Machines. From there you can pick up existing VM running on Azure or create new one.
From this dialog you can create new VM and make sure to check "Enable IIS and Web Deploy" because it will make configuration a lot easier. If already have your existing machine running here are detailed instructions how to enable IIS and Web Deploy. If you are creating new VM pay attention to Visual Studio Output window because this process can take some time.
Configure Build Process
Now that we have our machine ready for hosting and accepting our deployments it's time to configure our Build. Once again I will use Visual Studio Online Builds but same method applies if you are running Team Foundation Server on premise or even if you are just building your solution from command line manually or using scripts. Point is, whatever method for compiling your application you are using it will directly or indirectly run MSBuild in background and MSBuild can run our Publish profile as part of the process.
At the moment of writing creating build process directly in VS Online portal in browser is still in beta so I will do it from local Visual Studio. First make sure that you commit at least one version of your solution to source control because you will need it to define build process. It doesn't matter if you are using Team Foundation or Git VCS, VS Online Build will work with both.
Switch to Team Explorer and click on Builds. From top of the window choose "New Build Definition".
First step is quite self-explanatory. Leave it at enabled and give it some meaningful name. Give it some name that will clearly describe what application suite it is building, what configuration, how often (like nightly, CI etc.) because that list can grow over time.
On Trigger tab choose how you want your build to run. Manually, on each check in etc. I want to have continuous integration, meaning on every source code change application will get built and deployed to my designated environment.
Source Settings tab setts where your solution is to be found on VCS. Settings for Team Foundation Server and Git use different notation but Visual Studio should detect this step automatically if your code has already been committed (checked in) to VCS.
On Build Defaults tab you can leave everything by default.
Now we come to most important step of all. Build processing.
Items to build setting needs to point to your solution or project file. This will probably be detected automatically. If not just click trough. Under advanced settings you need to enter additional MSBuild Arguments. This is where we set our deployment profile. Remember that we could technically configure multiple publish profiles for one single application. We could make one profile for test and another for staging environment. We could also build in Debug configuration for test and Release for staging environment. Since I am deploying for test I use following command:
/p:configuration="Debug;PublishProfile="bojan-webdeploy";AllowUntrustedCertificate=True;Password=PassowrdForWebDeployProfile;VisualStudioVersion=12.0
Settings are split with semicolon. Configuration is "Debug" in this case. PublishProfile is the name of publishing profile we set up in first step. You can find it inside application Properties/Publish Profiles.
It is the file with .pubxml extension. I found that "AllowUntrustedCertificate=True" and "VisualStudioVersion=12.0" are necessary for this process to work. Password had to be the one used by Web Deploy on your target server.
Hit Save and you should be able to see your new Build definition inside Visual Studio Builds in Team Explorer as well as in Visual Studio Online. Right click on it and then on "Queue New Build".
Your Build should kick of at this point and you should be able to see progress both in Visual Studio and VS Online Portal.
If everything went ok with the build your application should be successfully deployed to target environment. Double-clicking on Build in both VS and VS Online Profile allows you to see logs and eventually diagnose if something went wrong.
Deploying specific project in solution
There is a special case when you have two or more Web type projects in solution(Web Application, Web Site, Web API). Even though you define publishing profile in specific project in solution and it works if you publish using wizards and UI from Visual Studio it will not work from the command line and build systems for that matter. It will not know which project it needs to be deployed with that specific profile. To work around that you need to add custom Property Group inside .proj file of application you want to deploy.
Simple unload and edit your csproj file by adding something like following:
Then you add this custom property you defined in project to MSBuild configuration arguments list and set it to true.
/p:configuration="Debug;DeployThisOnAppOnBuild=true;PublishProfile="bojan-webdeploy";AllowUntrustedCertificate=True;Password=PassowrdForWebDeployProfile;VisualStudioVersion=12.0
Recently I had a chance to upgrade older web site based on Umbraco 6 to most recent version 7.2.2. Upgrade went more or less smooth as one would expect. Problem was upgrading third party components (when I say 3rd party i mean uComponents). I could live without uComponents but I also had custom Multi User Picker Data Type.
With Umbraco 7 you get User Picker Data type ( property editor) but that allows you to select just one User. I needed Data type that would give me list of CMS Users where I would be able select from (using checkboxes probably). At the time of writing there was no such components available for Umbraco 7.x so that meant building my own.
The whole idea behind these property editors in Umbraco is to simply show some values stored in data store to user in user friendly fashion and give them ability to edit those values. Before Umbraco version 7 it was possible to wrap different kinds of , let's call it code, into macro and use that as "property editor" for your data type. That was the time and version of Umbraco where those kinds of macros and property editors where in one way or another executed and effectively rendered on server side (XSLT, asp.net user controls etc). Umbraco version 7 was completely redesigned and everything that runs under your /umbraco/# part of the site was build as single page web application using AngularJS. This means if you want something injected and rendered in Umbraco back office you need to follow this pattern and build your Plugin (Data Type Property Editor) using AngularJS and available Umbraco Angular services and factories. Umbraco 7 documentation is not that great but at least they have basic introduction and some samples.
Custom Property Editor in Umbraco 7.x
First thing when build custom property editor is you need to create folder for it under App_Plugins folder. In my case it's called MultiUserPicker.
This folder will always consist of at least three files. Package manifest, describing your editor so that Umbraco knows how to deal with, AngularJS controller and some HTML file used as AngularJS template. For MultiUserPicker editor package.manifest is defined:
{
//you can define multiple editors
propertyEditors: [
{
/*this must be a unique alias*/
alias: "MultiUserPicker",
/*the name*/
name: "Multi User Picker",
/*the html file we will load for the editor*/
editor: {
view: "~/App_Plugins/MultiUserPicker/MultiUserPickerEditor.html",
valueType: "JSON"
}
}
]
,
//array of files we want to inject into the application on app_start
javascript: [
'~/App_Plugins/MultiUserPicker/MultiUserPicker.controller.js'
]
}
This is more or less self explanatory. Important in this case to notice is valueType: "JSON". This tells Umbraco what the internal data storage type for this field is. You can find more about this types here. You could use INT, STRING, TEXT, DATETIME or JSON as value type. View is path your editor HTML file and the last line tells where our AngularJS controller is.
Once package.manifest is defined you are already able to use it in Umbraco as custom data type. In Developer section expand Data types and click on Create new.
You should be able to select our new Multi User Picker editor from the drop down.
Next we need a way to get Umbraco Users to our front end client side code. The way we do that is by creating specialized Umbraco WEB API controller.
namespace UmbracoProject.Controllers {
public class UmbracoUser {
public int Id { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
[PluginController("CustomEditors")]
public class MultiUserPickerApiController : UmbracoAuthorizedJsonController {
[HttpGet]
public IEnumerable<UmbracoUser> GetAllUsers() {
int totalUsers = 0;
var allUsers = Services.UserService.GetAll(0, int.MaxValue, out totalUsers);
var retVal = allUsers.Select(user => new UmbracoUser {
Id = user.Id,
Name = user.Name,
Selected = false
}).ToList();
return retVal;
}
}
}
This controller exposes simple JSON API with one GetAllUsers method that returns list of all users in CMS. We will call this method (endpoint) from our AngularJS controller.
AngularJS controller code:
//adds the resource to umbraco.resources module:
angular.module('umbraco.resources').factory('multiUserPickerResource',
function ($q, $http, $routeParams) {
var apiCallsFactory = {};
//the factory object returned
//this cals the Api Controller
apiCallsFactory.getAllUsers = function () {
return $http.get("/umbraco/backoffice/CustomEditors/MultiUserPickerApi/GetAllUsers/");
}
return apiCallsFactory;
}
);
angular.module("umbraco")
.controller("multiUserPickerController", function ($scope, multiUserPickerResource) {
// Fire when page is loaded and Plugin gets pulled in
Reload();
// Loads users from actual Umbraco page
// Then calls Users API and adds missing users if one was added meanwhile
function Reload() {
//Bind Umbraco model to our local model
$scope.Users = $scope.model.value;
// Get Users from API
var promiseGet = multiUserPickerResource.getAllUsers();
promiseGet.then(function (pl) {
var usersFromWebApi = pl.data;
// Check if have some values comming from Actual Umbraco Fields value
// if not just map all users from API to local model
if ($scope.Users != "") {
angular.forEach(usersFromWebApi, function (usrFromApi, key1) {
var found = false;
angular.forEach($scope.Users, function (usrFromContent, key2) {
if (usrFromApi.Id == usrFromContent.Id) {
found = true;
}
});
if (!found) {
$scope.Users.push(usrFromApi);
}
});
} else {
$scope.Users = usersFromWebApi;
}
},
function (errorPl) {
$log.error('failure loading Users from API', errorPl);
});
}
// Map our local model to Umbraco page model to be autmaticaly saved to database
$scope.SyncWithUmbracoModel = function (users) {
$scope.model.value = users;
};
});
Basically what this code does is, on top of the listing I am registering my custom Angular factory that will be used for calling my custom .NET JSON API endpoint. Under the factory I am registering new controller within Angular application and passing in my factory as parameter (DI). Reload method is called on load, so each time page with our property editor loads we want to automatically show some values. When we defined our valueType in package.manifest as JSON we told umbraco to store values of this field in database as JSON (string) so anytime our controller gets instantiated we will get $scope object trough dependency injection. $scope.model.value is what holds value to be stored to database when the page is saved. When Reload method get triggered it assigns this value coming from Umbraco to my custom local Users model. This doesn't have to be this way necessarily, I could work only with $scope.model.value, but I found it more meaningful this way. Reload method then calls our .NET endpoint and gets the list of all Umbraco users defined on system. It adds new Users to local model if some users were defined since last page save. Removing of the users is intentionally left out because Umbraco doesn't let you delete any users once defined. Last method from controller simply maps local model back to $scope.model.value to be saved to Umbraco database when page where editor is gets saved.
Last piece of the puzzle is HTML template and it is defined as follows:
<div ng-controller="multiUserPickerController">
<div>
<label ng-repeat="usr in Users">
<input type="checkbox" ng-model="usr.Selected" ng-click="SyncWithUmbracoModel(Users)" value="{{usr.Id}}" />
{{usr.Name}}
</label>
</div>
</div>
What goes on in template is pretty straight forward Angular approach. Top element defines controller responsible for this context. Next we use ng-repeat to iterate trough all the users in $scope. ng-model on checkbox handles binding between control and the model and at last ng-click does the sync with Umbraco model to be saved to database.
Here is what end result looks like:
Here is the full solution if you need the code:
UmbracoProject.zip (8.9MB)Let me know if it works for you as it did for me.
Typically when you create your EF data model wizard will politely add all necessary settings in you app or web.config. That's all fine and dandy, but what if you have SQL Compact Database and you have multiple copies or database names could change and run-time. There is tone of other reasons why you might not want to store your connection strings in plain text config files. Basically you must pass connection string to your Entity Model at run-time.
First we need to extend our generated DbContext class with additional constructor that accepts connection string and pass it on to base class. At the moment of writing, this applies to EF 6.x and EF 5.x and I am using Database first approach, not sure if it works for Code First. Generated DbContext partial class can be found in solution tree if you expand .edmx file it is the one with EdmxFileName.Context.cs name.
public partial class DBEntities : DbContext
{
public DBEntities()
: base("name=DBEntities")
{
}
public DBEntities(string connectionString)
: base(connectionString) {
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}}}
And this would be the method for getting connection string:
public static string GetSqlCeConnectionString(string fileName, string password) {
var connectionStringBuilder = new SqlCeConnectionStringBuilder();
connectionStringBuilder.DataSource = fileName;
connectionStringBuilder.Password = password;
var entityConnectionStringBuilder = new EntityConnectionStringBuilder();
entityConnectionStringBuilder.Metadata = "res://*/YourEdmxFileName.csdl|res://*/YourEdmxFileName.ssdl|res://*/YourEdmxFileName.msl";
entityConnectionStringBuilder.Provider = "System.Data.SqlServerCe.4.0";
entityConnectionStringBuilder.ProviderConnectionString = connectionStringBuilder.ToString();
return entityConnectionStringBuilder.ConnectionString;
}
Next, just pass that connection string to DBContext constructor:
using (var db = new DBEntities(connectionString)) {
....
}
If something goes wrong when connecting to database or accessing compiled resources this blog post can be very useful.