I’m trying to upgrade my project from wix v3 to wix v4.
The wix project are as follow :
A wix setup
A wix bundle
A wpf .net 6 class library managed
bootstaper
I followed this example https://github.com/wixtoolset/Bal.wixext/tree/master/src/test/examples/WPFCoreMBA and this doc https://wixtoolset.org/docs/development/wips/modify-burn-api/
When I publish the boostraper project, build the bundle and launched it I get this log and errors. How can I fix that ?
[0DA8:0DB4][2023-01-02T18:23:27]e000: Error 0x80131522: Failed to create delegate
through GetFunctionPointer.
[0DA8:0DB4][2023-01-02T18:23:27]e000: Error 0x80131522: Failed to create the .NET Core
bootstrapper application factory.
[0DA8:0DB4][2023-01-02T18:23:27]e000: Error 0x80131522: Failed to create BA.
[0DA8:0DB4][2023-01-02T18:23:27]e000: Error 0x80131522: Failed to load BA.
[0DA8:0DB4][2023-01-02T18:23:27]e000: Error 0x80131522: Failed while running
The bundle.wxs
<BootstrapperApplication>
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\LanguageSelector.dll" Name="LanguageSelector.dll" bal:BAFactoryAssembly="yes" />
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\LanguageSelector.deps.json" Name="LanguageSelector.deps.json"/>
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\LanguageSelector.runtimeconfig.json" Name="LanguageSelector.runtimeconfig.json" />
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\WixToolset.Mba.Core.dll" Name="WixToolset.Mba.Core.dll" />
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\mbanative.dll" Name="mbanative.dll" />
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\GalaSoft.MvvmLight.dll" Name="GalaSoft.MvvmLight.dll" />
<bal:WixDotNetCoreBootstrapperApplicationHost />
The LanguageSelectorFactory0cs
[assembly: WixToolset.Mba.Core.BootstrapperApplicationFactory(typeof(LanguageSelector.LanguageSelectorFactory))]
namespace LanguageSelector
{
using WixToolset.Mba.Core;
public class LanguageSelectorFactory : BaseBootstrapperApplicationFactory
{
private static int loadCount = 0;
protected override IBootstrapperApplication Create(IEngine engine,
IBootstrapperCommand bootstrapperCommand)
{
if (loadCount > 0)
{
engine.Log(LogLevel.Standard, $"Reloaded {loadCount} time(s)");
}
++loadCount;
return new LanguageSelector(engine, bootstrapperCommand);
}
}
}
In your project file (.csproj) for bootstrapper application (your custom UI application known as BA) you have to add a reference to WixToolset.Dnc.HostGenerator package using Package manager console:
Install-Package WixToolset.Dnc.HostGenerator -Version 4.0.0-rc.1
Alternatively, make sure you have the required references in the mentioned BA project file:
<ItemGroup>
<PackageReference Include="WixToolset.Mba.Core" Version="4.0.0-rc.1" />
<PackageReference Include="WixToolset.Dnc.HostGenerator" Version="4.0.0-rc.1" />
</ItemGroup>
The managed BA assembly targeting .NET 6 or later requires WixToolset.Dnc.HostGenerator. Dnc is the abbreviation for Dot Net Core.
Once you have all this set, build and published you have to ensure the entire project output goes to Wix Payload. Including WixToolset.Mba.Core.dll and mbanative.dll. So, your Bundle.wxs have to include these DLLs. In your case should be something like:
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\mbanative.dll" />
<Payload SourceFile="..\LanguageSelector\bin\Release\net6.0-windows\publish\win-x86\WixToolset.Mba.Core.dll" />
It could be a lot of DLLs in the project output. So, I personally use the HarvestDirectory functionality in .wixproj to harvest project output directory as a PayloadGroup section. Let me know if you need more details on this.
Related
I have an issue with using System.Text.Json insinde my C# class library, which is a SolidWorks addin. It is probably an instance of DLL hell as described here.
Since this approach does not work, I might be able to figure something out if I understand a bit more about this issue. Maybe someone can help?
First - my code.
My 'csproj' file:
<Project Sdk="Microsoft.NET.Sdk">
<!-- general stuff -->
<PropertyGroup>
<TargetFrameworks>net48</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings>
</PropertyGroup>
<!-- references: the top two are SolidWorks API (needed for making a SolidWorks addin -->
<ItemGroup>
<PackageReference Include="com.solidworks.core" Version="29.5.1" />
<PackageReference Include="com.solidworks.tools" Version="21.5.0" />
<PackageReference Include="System.Text.Json" Version="6.0.2" />
</ItemGroup>
<!-- In order to have the addin available within SolidWorks,
it's dll needs to be registered in the codebase. For convenience
we automatically register on build and unregister on clean. -->
<Target Name="Register" AfterTargets="AfterBuild">
<Exec Command="%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe "$(TargetPath)" /codebase" />
</Target>
<Target Name="Unregister" BeforeTargets="BeforeClean">
<Exec Command="%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe "$(TargetPath)" /u" />
</Target>
</Project>
The relevant parts of my cs file:
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using SolidWorks...; // all the SolidWorks usings required
namespace SwxAddin
{
[Guid("acb6f17b-9738-4f11-a324-30e05625ff89")]
[ComVisible(true)]
public class SwxAddinImpl : ISwAddin
{
// will be called on addin load in SolidWorks
public bool ConnectToSW(object swx, int addinId)
{
var jsonText = "{ \"foo\": { \"bar\": 2 } }";
var doc = System.Text.Json.JsonDocument.Parse(jsonText); // exception occurs
return swx != null;
}
// will be called on addin unload in SolidWorks
public bool DisconnectFromSW() { return true; }
// This is run when registering the dll. It writes some stuff into the
// SolidWorks registry to make the addin available.
[ComRegisterFunction]
protected static void RegisterFunction(Type type) { ... }
// This is run when unregistering the dll. It removes the stuff from the
// SolidWorks registry that was written into it by RegisterFunction.
[ComUnregisterFunction]
protected static void UnregisterFunction(Type type) { ... }
}
}
When I run SolidWorks after building (and thus, registering my dll in the codebase) and debug it, I get a runtime error on
var doc = System.Text.Json.JsonDocument.Parse(jsonText);
saying
Exception has occurred: CLR/System.IO.FileNotFoundException An
exception of type 'System.IO.FileNotFoundException' occurred in
System.Text.Json.dll but was not handled in user code: 'Could not load
file or assembly 'System.Runtime.CompilerServices.Unsafe,
Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or
one of its dependencies. The system cannot find the file specified.'
. As mentioned above, I did try adding
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
to my csproj file, resulting in the following .dll.config file in my bin/Debug folder:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
but the runtime error still occurs.
So I'd like to actually understand the issue instead of just following cooking recipes. Here are some things I tried and thoughts:
The error says the issue is inside System.Text.Json.dll. I understand it so that the file System.Text.Json.dll, which lies in location A, expects a file System.Runtime.CompilerServices.Unsafe.dll of version 4.0.4.1 in location B, but in location B there is a different version of file System.Runtime.CompilerServices.Unsafe.dll (or no file of that name at all).
=> Can anyone tell me which locations A and B we are talking about? Is it a certain folder? Is it the GAC? In case it is the GAC, are we actually talking about files, or something else?
I checked the (for me) most probable location, the folder $myProjectPath\bin\Debug\net48. There I can find (amongst others) both dlls System.Text.Json.dll and System.Runtime.CompilerServices.Unsafe.dll. I opened both in some decompilation tool to check their versions and the versions of their references. This is what I found:
System.Text.Json.dll has version 6.0.0.2 and references System.Runtime.CompilerServices.Unsafe.dll of version 6.0.0.0.
System.Runtime.CompilerServices.Unsafe.dll has version 6.0.0.0.
=> So the required version and the present version of System.Runtime.CompilerServices.Unsafe.dll do align. Why do I then get the error? Doesn't this just mean that location A and B are NOT $myProjectPath\bin\Debug\net48? Or is the referenced version ignored under some circumstances? What kind of cirumstances?
I built a standalone console app, just using System.Text.Json and containing the two lines
var jsonText = "{ \"foo\": { \"bar\": 2 } }";
var doc = System.Text.Json.JsonDocument.Parse(jsonText);
inside it Main method. No runtime error occurs there. So SolidWorks must be the culprit somehow, even if it is not mentioned in the runtime error message.
This article covers dll hell and gives suggestions for troubleshooting. I checked the modules (Debug -> Windows -> Modules) in Visual Studio. It turns out that just before the error occurs
System.Text.Json version 6.0.0.0 is already loaded (from my $myProjectPath\bin\Debug\net48 folder).
System.Runtime.CompilerServices.Unsafe is not loaded.
=> But if System.Runtime.CompilerServices.Unsafe has not been loaded before, why does System.Text.Json want to load version 4.0.4.1 instead of the version specified in its own references (6.0.0.0)? Where does the 4.0.4.1 come from?
Thanks to M Kloster's comment, I could work around the issue by manually loading the assembly - although this unfortunately does not help understanding the issue.
First I inserted the line
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);
into the ConnectToSW method (as first line).
Then I implemented MyResolveEventHandler like so:
private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
{
var nameCompilerServicesUnsafe = "System.Runtime.CompilerServices.Unsafe";
if (args.Name == nameCompilerServicesUnsafe + ", Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
{
var assemblyPath = Assembly.GetCallingAssembly().Location;
if (Path.GetFileName(assemblyPath) == "System.Text.Json.dll")
{
var assemblyFolder = Path.GetDirectoryName(assemblyPath);
var pathCompilerServicesUnsafe = Path.Combine(assemblyFolder, nameCompilerServicesUnsafe + ".dll");
if (File.Exists(pathCompilerServicesUnsafe))
return Assembly.LoadFile(pathCompilerServicesUnsafe);
}
}
return null;
}
Now, whenever an assembly cannot be loaded by the automatic mechanism, MyResolveEventHandler will be called.
Here I just check if it is System.Text.Json.dll trying to load System.Runtime.CompilerServices.Unsafe version 4.0.4.1, and if yes, I return the assembly System.Runtime.CompilerServices.Unsafe.dll from System.Text.Json.dll's location folder.
Strangely, this allowed me to confirm that the System.Text.Json.dll trying to load System.Runtime.CompilerServices.Unsafe version 4.0.4.1 really is the one located in my $myProjectPath\bin\Debug\net48 folder. Which makes no sense to me, as the decompilation tool told me that the file $myProjectPath\bin\Debug\net48\System.Text.Json.dll references System.Runtime.CompilerServices.Unsafe version 6.0.0.0, not 4.0.4.1.
And as I said in my question, the issue does not occur outside of SolidWorks (e.g. in a standalone console app). So SolidWorks must somehow interfere in the (automatic) assembly resolving mechanism, maybe redirecting bindings? Very mysterious... Is there a way to turn that off?
I'm creating a .NET MAUI application using the current preview 11.
When I tried to implement Push notifications I added the Xamarin.Firebase.Messaging package and just adding this package causes a crash when starting the app with the exception:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/datatransport/TransportFactory;
at com.google.firebase.datatransport.TransportRegistrar.getComponents(TransportRegistrar.java:32)
at com.google.firebase.components.ComponentRuntime.discoverComponents(ComponentRuntime.java:109)
at com.google.firebase.components.ComponentRuntime.(ComponentRuntime.java:91)
at com.google.firebase.components.ComponentRuntime.(ComponentRuntime.java:45)
at com.google.firebase.components.ComponentRuntime$Builder.build(ComponentRuntime.java:360)
at com.google.firebase.FirebaseApp.(FirebaseApp.java:427)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:299)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:267)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:252)
at com.google.firebase.provider.FirebaseInitProvider.onCreate(FirebaseInitProvider.java:51)
at android.content.ContentProvider.attachInfo(ContentProvider.java:2388)
at android.content.ContentProvider.attachInfo(ContentProvider.java:2358)
at com.google.firebase.provider.FirebaseInitProvider.attachInfo(FirebaseInitProvider.java:45)
at android.app.ActivityThread.installProvider(ActivityThread.java:7239)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:6780)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6697)
at android.app.ActivityThread.access$1300(ActivityThread.java:237)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1913)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.android.datatransport.TransportFactory" on path: DexPathList[[zip file "/data/app/.../base.apk"],nativeLibraryDirectories=[/data/app/.../lib/x86_64, /data/app/.../base.apk!/lib/x86_64, /system/lib64, /system_ext/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:207)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 24 more
During the build I get the following warnings:
Warning in obj\Debug\net6.0-android\lp\153\jl\classes.jar:com/google/firebase/datatransport/TransportRegistrar.class:
Type com.google.android.datatransport.runtime.TransportRuntime was not found, it is required for default or static interface methods desugaring of Lcom/google/firebase/datatransport/TransportRegistrar;lambda$getComponents$0(Lcom/google/firebase/components/ComponentContainer;)Lcom/google/android/datatransport/TransportFactory;
Via trail and error I found out this happens for all Xamarin.Firebase.* packages, but not when referencing e.g. Xamarin.Google.Android.DataTransport.TransportRuntime directly.
How can I fix this?
I found a workaround:
Basically the newest version of the firebase packages are broken. Using the following packages worked:
<ItemGroup>
<PackageReference Include="Xamarin.Build.Download" Version="0.11.0" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.Contains('-android'))">
<PackageReference Include="Xamarin.Google.Dagger" Version="2.39.1" />
<PackageReference Include="Xamarin.Firebase.Messaging" Version="122.0.0.2" />
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="117.6.0.2" />
</ItemGroup>
As soon as I use the versions ending with .3 instead of .2 for the last two its broken...
Unity gradle build fail with error. How can i fix it?
I use
android.useAndroidX = true
android.enableJetifier = true
Build fail with error:
Failed to transform '...\Temp\gradleOut\libs\com.android.support.support-v4-26.1.0.aar' using Jetifier. Reason: The given artifact contains a string literal with a package reference 'android.support.v4' that cannot be safely rewritten. Libraries using reflection such as annotation processors need to be updated manually to add support for androidx.. (Run with --stacktrace for more details.)
That's my dependencies:
<dependencies>
<packages>
<package>com.android.support:appcompat-v7:24.0.+</package>
<package>com.android.support:support-v4:26.1.+</package>
<package>com.google.android.gms:play-services-ads:15.0.1</package>
<package>com.google.games:gpgs-plugin-support:0.9.62</package>
<package>com.sglib.easymobile:easy-mobile:1.+</package>
</packages>
<files>
<file>Assets/Plugins/Android/android.arch.core.common-1.0.0.jar</file>
<file>Assets/Plugins/Android/android.arch.lifecycle.common-1.0.0.jar</file>
<file>Assets/Plugins/Android/android.arch.lifecycle.runtime-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.annotation.annotation-1.0.0.jar</file>
<file>Assets/Plugins/Android/androidx.arch.core.core-common-2.0.0.jar</file>
<file>Assets/Plugins/Android/androidx.arch.core.core-runtime-2.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.asynclayoutinflater.asynclayoutinflater-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.browser.browser-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.collection.collection-1.0.0.jar</file>
<file>Assets/Plugins/Android/androidx.coordinatorlayout.coordinatorlayout-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.core.core-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.cursoradapter.cursoradapter-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.customview.customview-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.documentfile.documentfile-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.drawerlayout.drawerlayout-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.fragment.fragment-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.interpolator.interpolator-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.legacy.legacy-support-core-ui-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.legacy.legacy-support-core-utils-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.lifecycle.lifecycle-common-2.0.0.jar</file>
<file>Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-2.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.lifecycle.lifecycle-livedata-core-2.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.lifecycle.lifecycle-runtime-2.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.lifecycle.lifecycle-viewmodel-2.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.loader.loader-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.localbroadcastmanager.localbroadcastmanager-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.print.print-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.slidingpanelayout.slidingpanelayout-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.swiperefreshlayout.swiperefreshlayout-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.versionedparcelable.versionedparcelable-1.0.0.aar</file>
<file>Assets/Plugins/Android/androidx.viewpager.viewpager-1.0.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.animated-vector-drawable-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.appcompat-v7-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-annotations-26.1.0.jar</file>
<file>Assets/Plugins/Android/com.android.support.support-compat-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-core-ui-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-core-utils-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-fragment-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-media-compat-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-v4-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.android.support.support-vector-drawable-26.1.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-ads-18.1.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-ads-base-18.1.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-ads-identifier-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-ads-lite-18.1.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-auth-16.0.1.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-auth-api-phone-16.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-auth-base-16.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-base-16.0.1.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-basement-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-drive-16.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-games-16.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-gass-18.1.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-measurement-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-measurement-base-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-measurement-impl-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-measurement-sdk-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-measurement-sdk-api-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-nearby-16.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-stats-17.0.0.aar</file>
<file>Assets/Plugins/Android/com.google.android.gms.play-services-tasks-16.0.1.aar</file>
<file>Assets/Plugins/Android/com.google.games.gpgs-plugin-support-0.9.62.aar</file>
<file>Assets/Plugins/Android/com.sglib.easymobile.easy-mobile-1.2.0.aar</file>
</files>
</dependencies>
I have update Google Mobile Ads Unity Plugin and problem was solved
Try using the newest SDK version in build.gradle
Ex:
compileSdkVersion 29
Tools
MSBuild v14
Visual Studio 2013
Jenkins v2.111 running on Windows Server 2012
Git (bare repo on local file server)
Windows Batch
My goal
Build a c# Visual Studio project using MSBuild that pulls back the major and minor version numbers from the projects AssemblyInfo.cs for use during the build. The build would produce something like 1.2.$BUILD_NUMBER resulting in something like 1.2.121, 1.2.122, 1.2.123 and so on. Once the user opts to 'release' the build, a clickonce deployment with correct version in the folder name is copied to its target destination and a tag applied to the Git repository.
Pipeline example
Below is a 'work in progress' of what I've got up to. Any suggestions to improve are welcome. For those that are wondering why I'm coping the codebase out to a temporary folder. I'm using a multi-branch job in Jenkins and the folders that are auto-generated are extremely long! This gave me errors along the lines that my file name, project name or both are too long (because the entire path is above the 255 or so character length). So the only way to get around this was to copy out contents so the build and publish would work.
pipeline {
agent none
stages {
stage ('Checkout'){
agent any
steps
{
checkout scm
}
}
stage ('Nuget Restore'){
agent any
steps
{
bat 'nuget restore "%WORKSPACE%\\src\\Test\\MyTestSolution.sln"'
}
}
stage('Build Debug') {
agent any
steps
{
bat "xcopy %WORKSPACE%\\src\\* /ey d:\\temp\\"
bat "\"${tool 'MSBuild'}\" d:\\temp\\Test\\MyTestSolution.sln /p:Configuration=Debug /target:publish /property:PublishUrl=d:\\temp\\ /p:OutputPath=d:\\temp\\build\\ /p:GenerateBootstrapperSdkPath=\"C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v8.1A\\Bootstrapper\" /p:VersionAssembly=1.0.$BUILD_NUMBER /p:ApplicationVersion=1.0.$BUILD_NUMBER"
}
}
stage('Deploy to Dev'){
agent none
steps {
script {
env.DEPLOY_TO_DEV = input message: 'Deploy to dev?',
parameters: [choice(name: 'Deploy to dev staging area?', choices: 'no\nyes', description: 'Choose "yes" if you want to deploy this build')]
}
}
}
stage ('Deploying to Dev')
{
agent any
when {
environment name: 'DEPLOY_TO_DEV', value: 'yes'
}
steps {
echo 'Deploying debug build...'
}
}
stage ('Git tagging')
{
agent any
steps
{
bat 'd:\\BuildTargets\\TagGit.bat %WORKSPACE% master v1.0.%BUILD_NUMBER%.0(DEV) "DEV: Build deployed."'
}
}
}
}
At the moment I've hard coded the major and minor version in the above script. I want to pull these values out of the AssemblyInfo.cs so that developers can control it from there without editing the Jenkinsfile. Any suggestions/best practice to achieve this?
Because I'm doing a clickonce deployment for a winforms app I've had to use MSBuild's VersionAssembly and ApplicationVersion switches to pass in the version. This seems to help with correctly labelling folders when MSBuild publishes the files. Have I have missed something in my setup which would negate these switches and make life simpler?
The last action in my pipeline is to trigger a .bat file to add a tag back into the master branch of the repository. This is another reason that I need to make the major and minor version accessible to the pipeline script.
MSBuild target for editing AssemblyInfo.cs
This code was taken from here: http://www.lionhack.com/2014/02/13/msbuild-override-assembly-version/
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CompileDependsOn>
CommonBuildDefineModifiedAssemblyVersion;
$(CompileDependsOn);
</CompileDependsOn>
</PropertyGroup>
<Target Name="CommonBuildDefineModifiedAssemblyVersion" Condition="'$(VersionAssembly)' != ''">
<!-- Find AssemblyInfo.cs or AssemblyInfo.vb in the "Compile" Items. Remove it from "Compile" Items because we will use a modified version instead. -->
<ItemGroup>
<OriginalAssemblyInfo Include="#(Compile)" Condition="%(Filename) == 'AssemblyInfo' And (%(Extension) == '.vb' Or %(Extension) == '.cs')" />
<Compile Remove="**/AssemblyInfo.vb" />
<Compile Remove="**/AssemblyInfo.cs" />
</ItemGroup>
<!-- Copy the original AssemblyInfo.cs/.vb to obj\ folder, i.e. $(IntermediateOutputPath). The copied filepath is saved into #(ModifiedAssemblyInfo) Item. -->
<Copy SourceFiles="#(OriginalAssemblyInfo)"
DestinationFiles="#(OriginalAssemblyInfo->'$(IntermediateOutputPath)%(Identity)')">
<Output TaskParameter="DestinationFiles" ItemName="ModifiedAssemblyInfo"/>
</Copy>
<!-- Replace the version bit (in AssemblyVersion and AssemblyFileVersion attributes) using regular expression. Use the defined property: $(VersionAssembly). -->
<Message Text="Setting AssemblyVersion to $(VersionAssembly)" />
<RegexUpdateFile Files="#(ModifiedAssemblyInfo)"
Regex="Version\("(\d+)\.(\d+)(\.(\d+)\.(\d+)|\.*)"\)"
ReplacementText="Version("$(VersionAssembly)")"
/>
<!-- Include the modified AssemblyInfo.cs/.vb file in "Compile" items (instead of the original). -->
<ItemGroup>
<Compile Include="#(ModifiedAssemblyInfo)" />
</ItemGroup>
</Target>
<UsingTask TaskName="RegexUpdateFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<Files ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Regex ParameterType="System.String" Required="true" />
<ReplacementText ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Reference Include="System.Core" />
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Text.RegularExpressions" />
<Using Namespace="Microsoft.Build.Framework" />
<Using Namespace="Microsoft.Build.Utilities" />
<Code Type="Fragment" Language="cs">
<![CDATA[
try {
var rx = new System.Text.RegularExpressions.Regex(this.Regex);
for (int i = 0; i < Files.Length; ++i)
{
var path = Files[i].GetMetadata("FullPath");
if (!File.Exists(path)) continue;
var txt = File.ReadAllText(path);
txt = rx.Replace(txt, this.ReplacementText);
File.WriteAllText(path, txt);
}
return true;
}
catch (Exception ex) {
Log.LogErrorFromException(ex);
return false;
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
Git tagging
This bat file is kicked off and passed values used to create and push a tag to the defined repository.
echo off
set gitPath=%1
set gitBranchName=%2
set gitTag=%3
set gitMessage=%4
#echo on
#echo Adding tag to %gitBranchName% branch.
#echo Working at path %gitPath%
#echo Tagging with %gitTag%
#echo Using commit message: %gitMessage%
d:
cd %gitPath%
git checkout %gitBranchName%
git pull
git tag -a %gitTag% -m %gitMessage%
git push origin %gitBranchName% %gitTag%
If there are any other gold nuggests that would help streamline or improve this overall workflow, would welcome those too!
I recently had the same problem which i solved by creating a Windows Script.
for /f delims^=^"^ tokens^=2 %%i in ('findstr "AssemblyFileVersion" %1\\AssemblyFile.cs') DO SET VERSION=%%i
This script extracts the version number from the AssemblyInfo.cs and put it inside an variable so it can be used later to tag the commit (in the same step though) :
CALL FindAssemblyVersion .\Properties
git tag %VERSION%
git push http://%gitCredentials%#url:port/repo.git %VERSION%
Not exactly from the assembly file but a very handy workaround to get the file version from the DLL while working with Jenkins, and using batch (or powershell) command:
Goto the directory where your DLL exists [CD Foo/Bar ]
FOR /F "USEBACKQ" %F IN (`powershell -NoLogo -NoProfile -Command (Get-Item "myApi.dll").VersionInfo.FileVersion`) DO (SET fileVersion=%F )
echo File version: %fileVersion%
i justed started working on an older Project i started once, but unfortunately the PWM Controller is not working anymore with the Lightning Driver. I am using Visual Studio 2017, the RPi2 is running at 10.0.15063.414 and I've installed the following Nuget-Packages:
Microsoft.IoT.Lightning (v1.1.0)
Microsoft.NETCore.UniversalWindowsPlatform (v5.3.3)
WinRTXamlToolkit.Controls.DataVisualization (v2.3.0)
The Project includes references to
Analyzer
Microsoft.IoT.Lightning
Microsoft.NETCore.UniversalWindowsPlatform
%ClassesLibrary%
UniversalWindows
Windows IoT Extensions for the UWP
WinRTXamlToolkit.Controls.DataVisualization,
where %ClassesLibrary% is an user-defined Project containing some classes for my Project. In the configuration web Interface of Windows IoT Core in the devices section, the Direct Memory Mapped Driver (Current Driver) is selected.
My initialization Code Looks like this
private static async Task InitOnboardHardware()
{
if (LightningProvider.IsLightningEnabled)
{
LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();
GpioController gpioController = GpioController.GetDefault();
var pwmControllers = await PwmController.GetControllersAsync(LightningPwmProvider.GetPwmProvider());
if (pwmControllers != null)
{
m_PWMController = pwmControllers[1];
//m_PWMController = (await PwmController.GetControllersAsync(LightningPwmProvider.GetPwmProvider()))[1];
m_PWMController.SetDesiredFrequency(100);
m_RPin = m_PWMController.OpenPin(18);
m_GPin = m_PWMController.OpenPin(23);
m_BPin = m_PWMController.OpenPin(24);
m_WPin = m_PWMController.OpenPin(25);
m_RPin.SetActiveDutyCyclePercentage(0);
m_GPin.SetActiveDutyCyclePercentage(0);
m_BPin.SetActiveDutyCyclePercentage(0);
m_WPin.SetActiveDutyCyclePercentage(0);
m_RPin.Start();
m_GPin.Start();
m_BPin.Start();
m_WPin.Start();
m_IsHardwareInitialized = true;
}
}
}
The PwmController.GetControllersAsync-method never completes and my application gets stuck on starting up. Also the commented Shorter Version is not working anymore?!
I have really no clue what i could be missing. Therefore, i would greatly appreciate any help.
Thank you in advance!
EDIT: I also tried another sample (https://github.com/lprichar/WindowsIotPwmExample), where i replaced the embedded C/C++ lightning library by the NuGet Package (same Version as in my Project). The sample also Fails: the Pins are all null, because PwmController.GetControllersAsync never completes :-(
EDIT2: I forgot to mention that my package.appxmanifest file also includes the following changes
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10"
IgnorableNamespaces="uap mp iot">
as well as
<Capabilities>
<Capability Name="internetClient" />
<iot:Capability Name="lowLevelDevices" />
<DeviceCapability Name="109b86ad-f53d-4b76-aa5f-821e2ddf2141" />
</Capabilities>
Please also see my comment to the first post. I had to Change this line
GpioController gpioController = GpioController.GetDefault();
to an async method call
GpioController gpioController = await GpioController.GetDefaultAsync();
and now everythings runs fine!