You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

This document describes how the new layout of Delta Shell developer projects is defined and how it can be expanded with new products and projects. The Delta Shell Framework is split up into separate NuGet packages that can be imported into C# projects in order to develop plugins for Delta Shell.

Creating a Product File Structure

When you start from scratch with a completely new project where Delta Shell doesn't have any plugins for, you start by creating a new C# solution (*.sln). There is a place to actually add this file to svn, although you are not obliged to put it there. You may also make your own svn repository. But if the Delta Shell team agrees, you could put your new files and folders in svn under https://repos.deltares.nl/repos/delft-tools/trunk/delta-shell/Products/[YourProductName].

Screenshot of the repository where products are stored.

Create a solution and a csproj file in your folder. Make it as the following structure with a src and a test folder.

This is the default way of making a solution and the plugin csprojs that come along. Of course, you can do this in visual studio. The csproj that you add should be a class library, because we are going to make a plugin and the plugin is a dll that will be loaded by Delta Shell. Delta Shell is the application that is going to be booted and it is not recommended to make your own launcher.

Set your C# projects to the .NET Framework 4 version

 

Download the Delta Shell SDK

Now that we have our csproj set up, we need to download the SDK, so we can start making our plugin. The first thing we do, is add the file nuget.config next to our sln file. Remember to fill in the password for dscbuildserver. This file ensures that NuGet will be able to find the download page for the NuGet packages. It is also required on TeamCity later on in this tutorial.

NuGet.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="repositoryPath" value="packages"/>
  </config>
  <packageRestore>
    <add key="enabled" value="True" />
    <add key="automatic" value="True" />
  </packageRestore>
  <packageSources>
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
    <add key="TeamcityAuth" value="https://build.deltares.nl/httpAuth/app/nuget/v1/FeedService.svc/" />
    <add key="Teamcity" value="https://build.deltares.nl/guestAuth/app/nuget/v1/FeedService.svc/" />
  </packageSources>
  <activePackageSource>
    <add key="TeamcityAuth" value="https://build.deltares.nl/httpAuth/app/nuget/v1/FeedService.svc/" />
  </activePackageSource>
  <packageSourceCredentials>
    <TeamcityAuth>
      <add key="Username" value="dscbuildserver" />
      <add key="ClearTextPassword" value="[DSCBUILDSERVERPASSWORD]" />
    </TeamcityAuth>
  </packageSourceCredentials>
</configuration>

Now open the Package Manager Console in Visual Studio. You can download the Delta Shell SDK by calling the command Install-Package DeltaShell.Framework -Version x.x.x.xxxx. This will install DeltaShell.Framework into the packages folder next to your sln file. And it will also add a reference to DeltaShell.Framework in your csproj.

Because we want to make an ApplicationPlugin, we are going to need another package. Install it in the same way via the Package Manager ConsoleInstall-Package DeltaShell.ApplicationPlugin -Version x.x.x.xxxx. To stay consistent, use the same version number.

Make sure that you always use the latest pinned version from TeamCity. Omitting the -Version option will give you the latest successful build, but this is not desired.

DeltaShell.ApplicationPlugin

What's in the DeltaShell.ApplicationPlugin package? Well, it saves you a lot of time setting up your project. First of all, it ensures that your project will build to the correct output location. Which is $(SolutionDir)bin\$(Configuration)\plugins\$(AssemblyName). Doing so speeds up the building process. I will tell more about this concept later on in this tutorial.

It also adds some extra Assembly Info, so that the Mono.Addins library knows that this assembly is a plugin assembly.

DeltaShell.Framework

The DeltaShell.Framework package ensures that all files in the framework are on your computer. It also adds a .targets file to your project so that it will copy the framework files into $(SolutionDir}bin\DeltaShell.

DeltaShell.TestProject

You can also make a unit test project that works in Delta Shell. To do so, install the DeltaShell.TestProject package into your test project. Take notice of the Default Project in the Package Manager Console, because you want the DeltaShell.TestProject to be in your test project and not in your application plugin project. The package sets the output directory of your project to $(SolutionDir)\bin\$(Configuration)

The test project also adds some extra lines to App.config.These lines make sure that your unit test can find the framework and the plugins.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="DeltaShell;plugins;"/>
    </assemblyBinding>
  </runtime>
</configuration>

Auto-Restore Packages

You don't have to add the packages folder to svn, because TeamCity and Visual Studio already know how to handle and download the packages.

You may right click on your solution in visual studio and click Enable auto restore NuGet packages. This will add some files and a folder to your solution. From now on, the packages will be downloaded automatically when missing before compilation.

Updating to a newer version

If you have received a message that a new version of the framework has been released, you can manually update your packages in your product by executing some NuGet commands via the NuGet Package Console, which can be found under Tools > NuGet package manager. Do not forget to set your package source to TeamcityAuth.

Update-Package DeltaShell.ApplicationPlugin -Version y.y.y.yyyyy -FileConflictVersion Overwrite
Update-Package DeltaShell.TestProject -Version y.y.y.yyyyy -FileConflictVersion Overwrite
Update-Package DeltaShell.Framework -Version y.y.y.yyyyy -FileConflictVersion Overwrite

This will uninstall the old version and then install the new version. You can simply commit the files that have been changed in your projects. You don't have to commit the nuget packages, because we already have auto-restore enabled.

When you are going to commit the updated package, you can verify your commit. There are a couple of files that have changed. Namely, everything that has the version number referenced in their file. So for example, all csproj files will have updated references. Another file is the packages.config file that belongs to the project. It will contain an updated version number as well. All files that were in the content folder of the nuget package are replaced.

Old

New

csproj

<ItemGroup>
  <Reference Include="DelftTools.Functions">
    <HintPath>..\..\packages\DeltaShell.Framework.1.0.4.33577\lib\net40\DeltaShell\DelftTools.Functions.dll</HintPath>
    <Private>False</Private>
  </Reference>
</ItemGroup>

csproj

<ItemGroup>
  <Reference Include="DelftTools.Functions">
    <HintPath>..\..\packages\DeltaShell.Framework.1.0.5.33698\lib\net40\DeltaShell\DelftTools.Functions.dll</HintPath>
    <Private>False</Private>
  </Reference>
</ItemGroup>

packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="DeltaShell.ApplicationPlugin" version="1.0.4.33577" targetFramework="net40" />
  <package id="DeltaShell.Framework" version="1.0.4.33577" targetFramework="net40" />
  <package id="log4net" version="1.2.10" targetFramework="net40" />
  <package id="Mono.Addins" version="1.0" targetFramework="net40" />
  <package id="PostSharp" version="2.1.7.28" targetFramework="net40" />
</packages>

packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="DeltaShell.ApplicationPlugin" version="1.0.5.33698" targetFramework="net40" />
  <package id="DeltaShell.Framework" version="1.0.5.33698" targetFramework="net40" />
  <package id="log4net" version="1.2.10" targetFramework="net40" />
  <package id="Mono.Addins" version="1.0" targetFramework="net40" />
  <package id="PostSharp" version="2.1.7.28" targetFramework="net40" />
</packages>

Creating an ApplicationPlugin derivative

Now that your project is ready to work with, you can add your first class, that will be an ApplicationPlugin. How to actually write the rest of an ApplicationPlugin will be explained in another tutorial.

namespace DeltaShell.Plugins.Unibest
{
    [Extension(typeof(IPlugin))]
    public class UnibestApplicationPlugin : ApplicationPlugin
    {
    }
}

Now you are almost ready to compile.

Setting up compilation

It is of utmost importance to remember the following:

You must always set the references to framework dll's to copy-local=False. This also accounts for Mono.Addings and other dll's that are automatically added to the project.

Why, you ask? Because they are already being copied into $(SolutionDir)\bin\DeltaShell and don't need to be in your own assembly's output folder.

You must always set the references to other project to copy-local=False

Why, you ask? Because they already have their own output folder and you don't want these dlls to be doubled in your bin directory.

 

Sometimes, you just need a reference to an external library that is already compiled. You can add those too. But remember that adding a reference comes with the responsibility of copying it or not.

If you require other files, like native libraries that are not referenced, to go to your output folder; add them as content to the project. The folder structure that is used in the project is mirrored to the output folder. For example, if you have a folder called myNatives in your csproj, there will be a folder called myNatives next to the final dll. Set the content that you want to add to Copy if newer, so that it will be copied to the output folder.

 

 

Now you may press the compile button. Have a look in your bin folder next to your solution folder. You will see that there are two folders. One is for the framework, the other contains all the plugins.

If something went wrong during compilation and you see that your bin folder contains more than you wanted, it is the easiest and cleanest to just delete your bin folder in the solution folder. This is quicker and safer than pressing clean in Visual Studio.

Verify your build output

You can find your own dll in bin\$(Configuration)\plugins\$(AssemblyName).

Your test project is compiled into the bin folder directly, because it has to know about the plugins and the framework. This may look a bit odd, but we are still looking for a good workaround for that. There will also be a folder called test-data that contains a symbolic link. This will be explained later in this tutorial.

Always take notice that your plugin folder only contains the dlls you expect. And always take notice that $(SolutionDir)bin\$(Configuration) only contains test dlls and test utils dlls.

The bin folder should look like the following. The test dlls are directly in the Debug or Release folder and finds the dlls via app.config probing. The plugin dlls are in its plugin directory and should not contain any dlls like PostSharp or other 3rd party dlls. And there shouldn't be any deltashell framework dlls either.

Debugging Delta Shell

Since your assemblies are just dll's and don't have an actual startup point, you will have to set it yourself. We wanted to add this information in the install script of the NuGet packages, but it seems that this is information found in the .suo file.

  1. Pick any application plugin as Startup Project
  2. Set it as startup project
  3. Make sure you have compiled the project
  4. Go to the Debug settings of the project
  5. Set the Start Action to Start external program and browse to bin\Debug\DeltaShell\DeltaShell.Gui.exe.
  6. Now you can press F5.

Unit Test Data

Your unit test project is actually already set up correctly when you have followed the steps explained above. There is just one last thing when you want to add test data. We don't want to copy over the unit test data every time we are going to compile the project. So what can you do to avoid that? Add your test data in a folder next to the testcsproj called test-data. A post-build event has been added to your testcsproj when you installed DeltaShell.TestProject. This post-build event creates a symbolic link to your test-data folder and you can access it via TestHelper.GetDataDir().

Setting up TeamCity

We have already set up a couple of templates in teamcity for you to automatically let your unit tests run and let your installers create what it needs to.

  • Run Product Tests
  • Run Product Tests Updated Trunk
  • Build Solution (Release)
  • Build MSI via MSBuild

Run Product Tests

Make a new TeamCity configuration and make it based on the template for unit tests. Fill in the name of your sln file in product_sln_file. You may exclude or include some categories if you want.

Make sure your csproj ends with Tests. This is because the TeamCity template is only looking for dlls that end with *Tests.dll

Run Product Tests Updated Trunk

Is almost the same as Run Product Tests, but also updates to the latest trunk version of the nuget packages. This can be convenient for framework developers to see if anything breaks with their changes.

Build Solution (Release)

Just builds the solution and returns a zip as artifact that can be downloaded. Actually uses a .proj file to run MSBuild. You will have to add a .proj file next to your solution in order to make this work.

The template performs the task BuildRelease on the proj file and therefore can do something like the following example. It shows that it first builds the solution as visual studio would. Then it removes the pdb and pssym files, so that the zip file artifact will be as small as possible for users to download.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <BuildPath>$(MSBuildProjectDirectory)</BuildPath>
    <SolutionDir>$(MSBuildProjectDirectory)\</SolutionDir> 
  </PropertyGroup>

  <Target Name="BuildRelease">
    <MSBuild Projects="Unibest.sln" Targets="Build" Properties="Configuration=Release;SolutionDir=$(SolutionDir);" />
    
    <ItemGroup>
      <PdbFiles Include="$(BuildPath)\bin\**\*.pdb"/>
      <PsSymFiles Include="$(BuildPath)\bin\**\*.pssym"/>
    </ItemGroup>
    <Delete Files="@(PdbFiles)" />
    <Delete Files="@(PsSymFiles)" />
  </Target>

</Project>

 

Build MSI via MSBuild

This template actually requires one more thing at the moment. The product must be in the svn of the trunk in order to find it. The split of the setup has not yet been done completely and is still under construction. How to set up your installer is not discussed in this document, but can be found in the examples in the delta shell trunk.

Once we have changed the wix installers so they can be stand-alone and used by all products via a nuget package, we will edit this document right away.

 

  • No labels