Monday, September 22, 2014

Major update for the SBQueueManager

Also having problems managing the service bus for windows server?
With the latest update of the SBQueueManager you can handle it all.

The improvements include:

  • Topic support
  • Subscription support
  • New user right to manage queues and topics
  • Update queue and topic support
  • Less crashes
  • More feedback
Check it out!


And offcourse: source is available at Github: https://github.com/luuksommers/SBQueueManager

Happy managing!
Luuk

Tuesday, July 8, 2014

Automatically deploy services using TFS2010

All credits for this post goes out to: Hrusikesh Panda and Mike Hadlow (see references below).

To deploy Windows services with TFS2010 there are 2 major challenges; seperate the binaries on a per-project basis and automatically stop and start a service without changing the build workflow. Sounds hard? It isn't!

If you don't want any blabla and download the sample solution directly, goto github.

First add the following files to your Solution folder and make sure they will be committed to TFS:
DeployApplication.targets (this is a copy of the WebDeploy targets from Microsoft with an extra change to copy the .config file).
DeployService.targets (this stops the service, copies the files and starts the service, it also contains the location on where to put the files)
safeServiceStart.bat (helper to start a remote service)
safeServiceStop.bat (helper to stop a remote service)
you can simply add these files to the solution items (right click solution and click add existing item).

Edit the DeployService.targets for the right paths on the remote machine. The directory where the service is located should be available for the user running the build using a standard windows share (\\<servername>\<project directory>\<servicename>, the servername is determined during the build and can be configured for each build quality.

Copy the Deploy.targets into the project you want to deploy, unload the project file and edit it with visual studio. Lookup the following line:
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
And add this line below:
<Import Project="Deploy.targets" Condition="'$(DeployOnBuild)'=='True'" />
Save the file and reload the project

Once you've reloaded the project, edit the Deploy.targets (just double click on it) and change the service name and service location. Commit all changes to TFS.

The next step is to install the service on the remote machine. (using installutil, or whatever method you like, in the sample we can install a service by running it with the -I command line argument). The automated deployment will only start and stop the service and is not able to install and delete the service. (In my case, the service is running as a domain user, and therefor I prefer to pre-install the service with the right credentials or else you'll have to enter the credentials in the deployment script).

To enable automatic deployment, create a new Build Configuration on your TFS2010 server and set it up with a scheduled trigger (or whatever trigger you want). In the process section add the following MSBuild arguments:
 /p:DeployOnBuild=True /p:DeploymentServerName=\\<server-to-deploy-to>
If you also want to configure transformations (change the .config file during deployment), have a look at SlowCheetah. This works without a problem with this configuration. To make sure SlowCheetah only works during deployment, I've edited the project file again and added AND '$(DeployOnBuild)'=='True' in the following line:
<Import Project="$(SlowCheetahTargets)" Condition="Exists('$(SlowCheetahTargets)') AND '$(DeployOnBuild)'=='True'" Label="SlowCheetah" />

(If you don't see this line, make sure you've installed SlowCheetah extension and added the transformations by right click on a .config file and click add transformations)

References:
http://mrchief.calepin.co/deploying-windows-service-via-msbuild
http://mikehadlow.blogspot.nl/2009/06/tfs-build-publishedwebsites-for-exe-and.html
https://github.com/luuksommers/TFSDeployedService

Happy deploying!

Luuk

Monday, March 24, 2014

Running Transmission as a Windows service

I've recently updated my netbook server to a full-blown core i3 system with Windows 8.1. Transmission, the torrent client of my choice, can be very easily installed under windows as a service.

Follow these steps:

  1. Download the client and cygrunsrv  (both .zip). from: http://sourceforge.net/projects/transmissiondaemon/files/
  2. Extract the transmission executables to a folder (in my case c:\apps\transmission)
  3. Extract cygrunsrv to the same folder
  4. Starts a command prompt as administrator and go to the transmission directory (cd c:\apps\transmission)
  5. Execute cygrunsrv --install TransmissionBT --path c:/Apps/transmission/transmission-daemon.exe -a "--pid-file transmission-daemon.pid --foreground" -e HOME=c:/Apps/transmission/ -e TRANSMISSION_WEB_HOME=c:/Apps/transmission/web --stdout c:/Apps/transmission/log/transmissionbt.log --stderr c:/Apps/transmission/log/transmissionbt.error.log
To make the whole setup beyond awesome, install the chrome plugin .torrent to transmission. Now you can just right click every .torrent or magnet link and just sent it to transmission.

Happy leeching!

Luuk 

Sunday, October 27, 2013

Bind WPF controls to attributes using Caliburn Micro

To bind for example an DecimalUpDown control to a RangeAttribute specified in a domain model, or a maxlength to a StringLengthAttribute you need to change the automatic binding of Caliburn Micro.

The example below is for a DecimalUpDown, but you can use it for all kind of fun stuff. In my github working example you can also see a Textbox.

First we need to add an ElementConvention for out DecimalUpDown in the BootStrapper's Configure method. Override this method and add the following convention (edit 2014-03-26 added attribute check to prevent binding errors):
ConventionManager.AddElementConvention<DecimalUpDown>(DecimalUpDown.ValueProperty, "Value", "ValueChanged").ApplyBinding =
(viewModelType, path, property, element, convention) =>
{
    if (!ConventionManager.SetBindingWithoutBindingOrValueOverwrite(viewModelType, path, property, element, convention, DecimalUpDown.ValueProperty))
        return false;

    if (property.GetCustomAttributes(typeof (RangeAttribute), true).Any())
    {
        if (!ConventionManager.HasBinding(element, DecimalUpDown.MaximumProperty))
        {
            var binding = new Binding(path) {Mode = BindingMode.OneTime, Converter = RangeMaximumConverter, ConverterParameter = property};
            BindingOperations.SetBinding(element, DecimalUpDown.MaximumProperty, binding);
        }

        if (!ConventionManager.HasBinding(element, DecimalUpDown.MinimumProperty))
        {
            var binding = new Binding(path) {Mode = BindingMode.OneTime, Converter = RangeMinimumConverter, ConverterParameter = property};
            BindingOperations.SetBinding(element, DecimalUpDown.MinimumProperty, binding);
        }
    }

    return true;
};
As you can see the binding uses a RangeMaximumConverter and a RangeMinimumConverter. These are fairly simple with the AttributeConverter baseclass:
public sealed class RangeMaximumConverter : AttributeConverter<RangeAttribute>
{
    public override object GetValueFromAttribute(RangeAttribute attribute)
    {
        return attribute.Maximum;
    }
}
And the AttributeConverter base class:
public abstract class AttributeConverter<T> : IValueConverter
    where T : Attribute
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var property = parameter as PropertyInfo;

        if (property == null)
            return new ArgumentNullException("parameter").ToString();

        if (!property.IsDefined(typeof(T), true))
            return new ArgumentOutOfRangeException("parameter", parameter,
                "Property \"" + property.Name + "\" has no associated " + typeof(T).Name + " attribute.").ToString();

        return GetValueFromAttribute((T)property.GetCustomAttributes(typeof(T), true)[0]);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    public abstract object GetValueFromAttribute(T attribute);
}
You can find a working example in GitHub.

Happy coding,
Luuk

Thursday, October 17, 2013

Using WiX installers the right way

Wix is the way to go for creating installers for your visual studio projects. Because Wix is rather complex to start with, I want to give you a working example so you can start building your own installers. You can also skip this short description and go directly to the source code.

What we will setup in this post is:
  1. Heat.exe (automatically include your dll files)
  2. Transformations (automatically edit the file generated by heat.exe)
  3. Service installers (register your windows service)
  4. Custom forms (manipulate your config file)
First off, we need to setup head.exe so it automatically detects when new dll's are added to your service. To do that, we need to edit the pre-build event:
$(WIX)bin\heat.exe" dir "$(SolutionDir)MyWindowsService\$(OutDir)." -srd -sreg -nologo -scom -srd -sfrag -ag -cg "Binaries" -dr "INSTALLDIR" -t "$(ProjectDir)XslTransform.xslt" -var var.MyWindowsService.TargetDir -o "../../Binaries.wxs

This will generate a Binaries.wxs in your installer dir.
The next trick is to use transformations to edit the generated file. For example: we want to install a windows service and remove vshost.exe files. This is done with the XslTransform.xslt file.

The following example creates a service:
<xsl:template match="wix:Component[wix:File[@Source='$(var.MyWindowsService.TargetDir)\MyWindowsService.exe']]">
 <xsl:copy>
  <xsl:apply-templates select="node() | @*" />
  <wix:ServiceInstall Id="MyServiceInstall" DisplayName="[SERVICENAME]" Description="[SERVICENAME]" Name="[SERVICENAME]" ErrorControl="ignore" Start="auto" Type="ownProcess" Vital="yes" Interactive="no" Account="[SERVICEUSER]" Password="[SERVICEPSWD]" />
  <wix:ServiceControl Id="MyServiceControl" Name="[SERVICENAME]" Start="install" Stop="both" Remove="uninstall" Wait="yes"/>
  <util:User Id="user" CreateUser="no" Name ="[SERVICEUSER]" Password="[SERVICEPSWD]" LogonAsService="yes" />
 </xsl:copy>
</xsl:template>
After installation, the service is running with the parameters from the product.wxs file.

The following example manipulates the app.config file:
<xsl:template match="wix:Component[wix:File[@Source='$(var.MyWindowsService.TargetDir)\MyWindowsService.exe.config']]">
 <xsl:copy>
  <xsl:apply-templates select="node() | @*" />
  <util:XmlFile Id="AppConfigSetSetting1" File="[INSTALLDIR]MyWindowsService.exe.config" Action="setValue" Name="value" Value="[SETTING1]" ElementPath="//configuration/appSettings/add[\[]@key='setting1'[\]]" Sequence="1" />
  <util:XmlFile Id="AppConfigSetSetting2" File="[INSTALLDIR]MyWindowsService.exe.config" Action="setValue" Name="value" Value="[SETTING2]" ElementPath="//configuration/appSettings/add[\[]@key='setting2'[\]]" Sequence="1" />
 </xsl:copy>
</xsl:template>
Custom forms is a whole different deal. You need to copy code from the original source and add it to your installer. No need to worry, I've got a good basic installer flow defined below. It is based on the WixUI_Common template without the license window.
<Fragment>
 <UI Id="CustomInstallerUI">
  <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
  <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
  <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />

  <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
  <Property Id="WixUI_Mode" Value="InstallDir" />

  <DialogRef Id="SettingsDlg" />
  <DialogRef Id="BrowseDlg" />
  <DialogRef Id="DiskCostDlg" />
  <DialogRef Id="ErrorDlg" />
  <DialogRef Id="FatalError" />
  <DialogRef Id="FilesInUse" />
  <DialogRef Id="MsiRMFilesInUse" />
  <DialogRef Id="PrepareDlg" />
  <DialogRef Id="ProgressDlg" />
  <DialogRef Id="ResumeDlg" />
  <DialogRef Id="UserExit" />

  <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
  <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>

  <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>

  <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish>
  <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>

  <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
  <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
  <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
  <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
  <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="SettingsDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
  <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
  <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>

  <Publish Dialog="SettingsDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">1</Publish>
  <Publish Dialog="SettingsDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg"></Publish>

  <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1">NOT Installed</Publish>
  <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
  <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>

  <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>

  <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
  <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
  <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>

  <Property Id="ARPNOMODIFY" Value="1" />
 </UI>

 <UIRef Id="WixUI_Common" />
</Fragment>
The custom SettingsDlg.wxs looks like this:


Last but not least, to fix 'ICE80: This 32BitComponent '' uses 64BitDirectory INSTALLDIR' you can add '-arch x64' to the Compiler parameters in the project properies' Tool Settings.
The heat.exe searches for all binaries in the output folder. This causes problems with build servers. In TFS2012 you can enable that the build server puts the binaries in seperate folders. I don't have TFS2012 running so I can't try this.

Full source is available at GitHub, so you can simply test and edit it yourself: https://github.com/luuksommers/WixInstallerDemo

Sources:
http://ahordijk.wordpress.com/2013/03/26/automatically-add-references-and-content-to-the-wix-installer/
http://www.chriskonces.com/using-xslt-with-heat-exe-wix-to-create-windows-service-installs/
http://kentie.net/article/wixtipstricks/

Cheers,
Luuk

PS: Next blog post is also in progress, Caliburn Micro and Attribute binding :)

Sunday, July 14, 2013

PetaPoco as it's meant to be; with repository and fluent mappings

When your domain objects get decorated with DataLayer column mappings, you create an unwanted dependency with your DayaLayer. To prevent this, you can create a mapping. This blog describes how I've done it. Comments are always welcome in the comment section below.

In the recently updated PetaPoco for Informix, I've created a FluentMapper. With this you can create a mapping of your domain object, without decorating them.

Here's how you can also benefit from this seperation. First create the domain object (DO):
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public double Revenue { get;set; }
}
Followed by the mapper of the DO
public class CustomerMapper : FluentMapper<Customer>
{
    public CustomerMapper() : base("tblCustomer", "CustomerId")
    {
        this.Property(a=>a.Id, "CustomerId")
            .Property(a=>a.Name, "CustomerName")
            .Property(a=>a.Revenue, "Revenue", fromDbValue=>(int)fromDbValue / 10d, toDbValue => (int)((double)toDbValue * 10));
    }
}
Once the mapper is in place, we want to make sure we hook it up every time. This is why I make a DataContext class (which is used in the repository):
public class MyDataContext : Database
{
    //Because the PetaPoco.Mappers is static, we also hook up our mappers static
    static MyDataContext()
    {
        PetaPoco.Mappers.Register(typeof(Customer), new CustomerMapper());
    }
    public MyDataContext()
        : base(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString))
    {
        
    }
}
Now we can create the repository for the customer related DataLayer functions (CRUD operations):
public class CustomerRepository
{
    private MyDataContext _dataContext
    public CustomerRepository(MyDataContext dataConext)
    {
        _dataContext = dataConext;
    }

    public Customer GetById(int customerId)
    {
        _dataContext.Get<Customer>(customerId);
    }

    public void Update(Customer customer)
    {
        _dataContext.Update(customer);
    }

    // etc
}
We can use it all together in the following way:
using(var dataContext = new MyDataContext())
{
    var customerRepository = new CustomerRepository(dataContext);
    var customer = customerRepository.GetById(1234);
}
As you can see the usage of the repository is super clean. Nobody knows where the data comes from, and nobody cares.

Let me know what you think of this solution!

Cheers,
Luuk

Friday, July 12, 2013

Introducing PetaPoco for Informix

I've created a fork of PetaPoco, with support for Informix and named parameters. I've also added multiple key support.

The code is available on GitHub.

An example:
[TableName("ship")]
public class Ship
{
    [PrimaryKey]
    [Column("shipid")]
    public int Id { get; set; }

    [Column("name")]
    public string Name { get; set; }
}

[TableName("positionlog")]
public class PositionLog
{
    [PrimaryKey]
    [Column("shipid")]
    public int ShipId { get; set; }

    [PrimaryKey]
    [Column("epochdate")]
    public int EpochDate { get; set; }

    [Column("lat")]
    public int Latitude {get;set;}

    [Column("lon")]
    public int Longitude {get;set;}
}

var db = new Database(new IfxConnection("<ConnectionString>");
int shipId = 1234;
var ship = db.Query<Ship>("select first 1 * from ship where shipid = @id", new { id = shipId }).FirstOrDefault();

ship.Name = "Submarine";

db.Update(ship);

The code will be updated with support of more features as we move along with our project (which uses Informix).

Cheers,
Luuk