Version number in manifest file's dependentAssembly/assemblyIdentity element - c#

I'm working with an application that includes an un-managed client DLL and a managed COM server DLL (which was a challenge in itself: Managed Reg-Free COM Server Won't Activate), and now I'm wondering what is the best way to keep the version numbers in sync. Since we are building both the client and the server, and we try to keep the version numbers of all our files in sync for every build, it looks like I need to have a process that edits all my manifest files on both the client and server ends of all my isolated COM references before a full build happens. Is there an easier way?
Example (client manifest):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="globals" version="1.0.0.0" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="SoftBrands.FourthShift.FSCulture" version="8.0.0.999" publicKeyToken="541b4aff0f04b60a" />
</dependentAssembly>
</dependency>
</assembly>
Server Manifest:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity type="win32" name="SoftBrands.FourthShift.FSCulture" version="8.0.0.999" publicKeyToken="541b4aff0f04b60a" />
<clrClass clsid="{23D4FF3D-EEDF-4F68-AD65-749958EE3B2A}"
name="SoftBrands.FourthShift.FSCulture.FSCulture"
tlbid="{8D480B22-D603-309F-9A26-EA9E9B020207}">
</clrClass>
</asmv1:assembly>
I could just do a global search and replace on version="8.0.0.999" with the current version for every build, but I suspect there might be a better way.

Your best bet is to leverage a custom MSBuild task to manipulate the project artifacts prior to compilation.
The task should accept three properties. One property for the client manifest, another property for the server manifest and the third property for the version.
Here is what the targets file might look like in MSBuild.
Manifests.targets
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<!-- Import Tasks -->
<!-- Be sure to sue the full namespace of the task to import -->
<UsingTask TaskName="Full.Namespace.To.UpdateManifestsTask" AssemblyFile="$(MSBuildThisFileDirectory)\MyCustomTasks.dll" />
<!-- Define the location of the client and server manifest files -->
<PropertyGroup>
<ClientManifest><!-- Location of the client manifest --></ClientManifest>
<ServerManifest><!-- Location of the server manifest --></ServerManifest>
</PropertyGroup>
<!-- Define Generate App Config Target -->
<Target Name="UpdateManifests">
<UpdateManifests ClientManifest="$(ClientManifest)" ServerManifest="$(ServerManifest)" Version="$(Version)" />
</Target>
<!-- Define Before Build Target -->
<!-- This will ensure the above target gets executed prior to compilation -->
<Target Name="BeforeBuild">
<CallTarget Targets="UpdateManifests;" />
</Target>
</Project>
Here is what the custom task might look like -
UpdateManifestsTask.cs
public class UpdateManifestsTask : Task
{
public ITaskItem ClientManifest { get; set; }
public ITaskItem ServerManifest { get; set; }
public ITaskItem Version { get; set; }
public override bool Execute()
{
var newVersion = string.Format("name=\"SoftBrands.FourthShift.FSCulture\" version=\"{0}\"", this.Version.ItemSpec);
var clientFile = File.ReadAllText(this.ClientManifest.ItemSpec);
clientFile = Regex.Replace(clientFile, "name=\"SoftBrands.FourthShift.FSCulture\" version=\"\\d*\\.\\d*\\.\\d*\\.\\d*\"", newVersion);
File.WriteAllText(this.ClientManifest.ItemSpec, clientFile);
var serverFile = File.ReadAllText(this.ClientManifest.ItemSpec);
serverFile = Regex.Replace(clientFile, "name=\"SoftBrands.FourthShift.FSCulture\" version=\"\\d*\\.\\d*\\.\\d*\\.\\d*\"", newVersion);
File.WriteAllText(this.ServerManifest.ItemSpec, serverFile);
return true;
}
}
The RegEx is a little sloppy as this was a quick and dirty example but this is effectively how you would go about doing this kind of thing.
Be sure to add references to the MSBuild libraries.
http://blogs.msdn.com/b/msbuild/archive/2006/01/21/515834.aspx
If you don't want to build a custom task you can write a small console app that does the same thing but in my opinion a custom task is cleaner.
Should you decide to go the console app route, you can leverage the BeforeBuild and AfterBuild events in your project file.
<Target Name="BeforeBuild">
<!-- Invoke console app -->
</Target>
<Target Name="AfterBuild">
</Target>

Related

Unable to get autocomplete to work after installing vsix

I am working on a completionprovider project, which will be published as a visual studio extension. The completionprovider code is taken from https://github.com/PacktPublishing/Roslyn-Cookbook/blob/master/Chapter03/CodeSamples/Recipe%205%20-%20CompletionProvider/CompletionProvider.zip.
When I was debugging the vsix, I can get it to work properly. Installation also worked using the vsix file generated in the bin folder after building the project. However, I can't get it to work by testing the extension in the project I used during debugging. I have tried all possible ways to change the vsixmanifest but simply could not get it to work after installation. Below is a sample of the manifest file.
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="MyCompletionProviderVsix.2f4985a4-6bc6-46fc-9082-2c45d3d8ac3f" Version="1.0" Language="en-US" Publisher="ABC" />
<DisplayName>MyCompletionProviderVsix</DisplayName>
<Description>Auto complete test.</Description>
</Metadata>
<Installation AllUsers="true">
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[16.0, 17.0)" />
</Installation>
<Dependencies>
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.5,)" />
</Dependencies>
<Prerequisites>
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[15.0,17.0)" DisplayName="Visual Studio core editor" />
<Prerequisite Id="Microsoft.VisualStudio.Component.Roslyn.LanguageServices" Version="[16.0,17.0)" DisplayName="Roslyn Language Services" />
</Prerequisites>
<Assets>
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="MyCompletionProvider" Path="|MyCompletionProvider|" />
<Asset Type="Microsoft.VisualStudio.Analyzer" d:Source="Project" d:ProjectName="MyCompletionProvider" Path="|MyCompletionProvider|" />
</Assets>
</PackageManifest>

How to programmatically configure nLog targets

I am trying to figure out how to programatically configure a NLog FallbackGroup target that has two email type sub-targets. Based on some things that happen during the start of the application, I would like to override the "to" part of the two sub-targets of the FallbackGroup target.
Currently, the app has a NLog.config file that has these targets in it. But, the values are hard-coded in it. Any change will require a redeploy of the app... That's not what we want... What we really need is the ability to modify the "to" setting in the two targets in some logic called on startup.
Here's the NLog.config file:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<targets>
<target name="logfile" xsi:type="File" fileName="BAM_logfile.txt" />
<target xsi:type="FallbackGroup"
name="email-error"
returnToFirstOnSuccess="true">
<target xsi:type="Mail"
name="mailserver1"
to="kevin.orcutt#acme.com"
from="noreply#acme.com"
subject="Exception Message from: ${processname} v:${assembly-version} on ${machinename}"
smtpServer="smtp.acme.com"
smtpPort="25"
layout="${longdate}${newline}${windows-identity} running ${processname} v:${assembly-version} on ${machinename}${newline}At: ${callsite}${newline}Message: ${message}${newline}Exception:${newline}${exception:format=toString,Data:maxInnerExceptionLevel=10}${newline}" />
<target xsi:type="Mail"
name="mailserver2"
to="kevin.orcutt#acme.com"
from="noreply#acme.com"
subject="Exception Message from: ${processname} v:${assembly-version} on ${machinename}"
smtpServer="mail.acme.com"
smtpPort="25"
layout="${longdate}${newline}${windows-identity} running ${processname} v:${assembly-version} on ${machinename}${newline}At: ${callsite}${newline}Message: ${message}${newline}Exception:${newline}${exception:format=toString,Data:maxInnerExceptionLevel=10}${newline}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Info" maxlevel="Warn" writeTo="logfile" />
<logger name="*" level="Error" writeTo="email-error" />
</rules>
<extensions>
<add assembly="NLog.MailKit"/>
</extensions>
</nlog>
So my question is... Is there a way of overriding the "to" part of the sub-targets in the NLog.config file programatically, or is it best to configure the entire FallbackGroup target on application start? A second and less obvious question is I'm looking for some examples of either solution... I haven't quite figured out the code to do either... :-(
It works something like this:
Load the configuration from the appropriate XML file. This can be your app.config or a separate XML file. Then find the target by name, and cast it to the appropriate type. From there you can modify its properties however you see fit.
var xmlConfig = new XmlLoggingConfiguration("nlog.config");
var target = xmlConfig.FindTargetByName("mailserver1") as MailTarget;
target.To = "...";
You can do this with any target: load it by name, then cast it to the appropriate type. When you're done making changes, apply the configuration:
LogManager.Configuration = xmlConfig;
This should be done at startup, before you get any loggers. I think any loggers you get before applying these changes will not be affected.

sonar-dotnet-shared-library does not compile due non-existing dependencies, How to make it work?

I am trying to compile in my machine the sonar-csharp-plugin, but in the pom.xml file there is two dependencies that do not exist in the Maven public repositories:
<dependency>
<groupId>org.sonarsource.dotnet</groupId>
<artifactId>sonar-dotnet-tests-library</artifactId>
<version>1.5.0.393</version>
</dependency>
<dependency>
<groupId>org.sonarsource.dotnet</groupId>
<artifactId>sonar-dotnet-shared-library</artifactId>
<version>1.0.1.138</version>
</dependency>
I download the code of both projects and try to compile them and generate the .jar files for each one.
Trying to compile sonar-dotnet-shared-library-1.0.1.138, I installed the https://www.nuget.org/packages/SonarAnalyzer.CSharp/1.20.0 package and proceed to install it in my maven local repository then when I compile sonar-dotnet-shared-library-1.0.1.138 I get :
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-antrun-plugin:1.7:run (unzip-nuget) on project sonar-dotnet-shared-library: An Ant Build Exception has occured: C:\Temp\sonar-dotnet-shared-library-1.0.1.138\target\analyzer\SonarAnalyzer.Scanner\protobuf does not exist.
[ERROR] around Ant part ...<copy todir="src/main/protobuf">... # 8:35 in C:\Temp\sonar-dotnet-shared-library-1.0.1.138\target\antrun\build-main.xml
I think I am in Maven hell.
What should I do to build the code from the latest release sonar-csharp-plugin??
Edit: when I installed the SonarAnalyzer I used
mvn install:install-file -DgroupId=org.sonarsource.dotnet -DartifactId=SonarAnalyzer.Scanner -Dversion=1.20.0 -Dpackaging=nupkg -Dfile="C:\Temp\SonarAnalyzer.CSharp.1.20.0-RC1.nupkg"
I disable the tasks that generate the error, now the java code start its compilation but I get errors related to
import org.sonarsource.dotnet.protobuf.SonarAnalyzer;
I think that it is a reference to the SonarAnalyzer Dll's, but neither Eclipse nor Maven are able to find it (protobuf is missing)
Edit2:
the POM.XML includes these tasks:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>unzip-nuget</id>
<phase>validate</phase>
<configuration>
<exportAntProperties>true</exportAntProperties>
<tasks>
<unzip src="${sonarAnalyzer.workDirectory}/SonarAnalyzer.Scanner.nupkg" dest="${sonarAnalyzer.workDirectory}/SonarAnalyzer.Scanner/" />
<delete>
<fileset dir="src/main/protobuf" excludes=".gitignore"></fileset>
</delete>
<copy todir="src/main/protobuf">
<fileset dir="${sonarAnalyzer.workDirectory}/SonarAnalyzer.Scanner/protobuf">
<include name="*.proto"/>
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>compile-protobuf-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<fileset id="fileset" dir="${project.basedir}/src/main/protobuf">
<include name="*.proto" />
</fileset>
<pathconvert refid="fileset" property="protos" pathsep=" " />
<mkdir dir="${project.build.directory}/generated-sources/protobuf" />
<chmod file="${protobuf.compiler}" perm="u+x" />
<exec failonerror="true" executable="${protobuf.compiler}">
<arg value="proto_path=${project.basedir}/src/main/protobuf" />
<arg value="java_out=${project.build.directory}/generated-sources/protobuf" />
<arg line="${protos}" />
</exec>
</target>
</configuration>
</execution>
</executions>
As I understand, in the SonarAnalyzer.Scanner.nupkg should be a protobuf folder, and the content of that folder is copied to src/main/protobuf.....well the SonarAnalyzer.Scanner.nupkg downloaded from Nuget does not contain that folder....so....
guys from Sonar...... Where do I get that nupkg?
I had the same problem, I've found the solution on this thread from SonarQube's Google group.
You need to fetch the missing artifacts from sonarsource's Artifactory server. As suggested by Duarte Meneses, you can add these lines to [user_home]/.m2/settings.xml :
<profiles>
<profile>
<id>sonarsource-repo</id>
<activation>
<property>
<name>!skip-sonarsource-repo</name>
</property>
</activation>
<repositories>
<repository>
<id>sonarsource</id>
<name>SonarSource Central Repository</name>
<url>https://repox.sonarsource.com/sonarsource</url>
<releases>
<enabled>true</enabled>
<updatePolicy>interval:60</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>sonarsource</id>
<name>SonarSource Central Repository</name>
<url>https://repox.sonarsource.com/sonarsource</url>
<releases>
<enabled>true</enabled>
<!-- no need to always check if new versions are available when
executing a maven plugin without specifying the version -->
<updatePolicy>interval:60</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
I used the above configuration.I also had mirrors declared in my settings.xml, so I had to exclude sonarsource from the mirrored repositories :
<mirrors>
<mirror>
<id>nexus</id>
<mirrorOf>*,!sonarsource</mirrorOf>
<url>http://ci-server/nexus/content/groups/public</url>
</mirror>
</mirrors>
Of course there are other ways to achieve the same result, for example by declaring a proxy repository in your company's Nexus server.
With this configuration, I built SonarQube successfully.

Run C# WPF application with uiAccess = true in manifest at startup

The application needs to stay on top of metro, hence the need for the uiAccess flag. This is a recent change in the application. In the previous version, where the uiAccess flag was not set, we could set the application to run on user access using this scheduled task:
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2014-04-23T11:31:11.9188616</Date>
<Author>MU15\Utente</Author>
</RegistrationInfo>
<Triggers>
<LogonTrigger>
<Enabled>true</Enabled>
</LogonTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>MU15\Utente</UserId>
<LogonType>InteractiveToken</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>false</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
<Priority>7</Priority>
<RestartOnFailure>
<Interval>PT1M</Interval>
<Count>3</Count>
</RestartOnFailure>
</Settings>
<Actions Context="Author">
<Exec>
<Command>"C:\Program Files (x86)\path\to\application.exe"</Command>
</Exec>
</Actions>
</Task>
We recently added the following application manifest:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="true" />
</requestedPrivileges>
<applicationRequestMinimum>
<defaultAssemblyRequest permissionSetReference="Custom" />
<PermissionSet ID="Custom" SameSite="site" Unrestricted="true" />
</applicationRequestMinimum>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
</application>
</compatibility>
</assembly>
The scheduled task now fails with error 0x800702e4: the requested operation requires elevation.
We tried putting a shortcut in %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup, with no success.
Is there a way to run an application with the uiAccess flag set?
The problem is that the Task Scheduler uses by default CreateProcess, which won't work for running processes with a manifest that requires elevation: you'd need to use ShellExecuteEx for that.
There are probably other ways to do this, but at least one of them, with the task scheduler, is configure the task to stop other existing instances if the task is already running.
Via the GUI: Settings -> "If task is already running (etc.)", set to "Stop the existing instance", or in the XML:
<MultipleInstancesPolicy>StopExisting</MultipleInstancesPolicy>

Fetching asmv1:assemblyIdentity from manifest

After compilation the following is present in the app manifest, if I publish it by hand in VS the version picked is the first one, i.e. 3.9.0.3
<asmv1:assemblyIdentity name="MyApp.exe" version="3.9.0.3" publicKeyToken="0000000000000000" language="neutral" processorArchitecture="x86" type="win32" />
<description asmv2:iconFile="Logo.ico" xmlns="urn:schemas-microsoft-com:asm.v1" />
<application />
<entryPoint>
<assemblyIdentity name="MyApp" version="3.8.0.25806" language="neutral" processorArchitecture="x86" />
If instead I try running it in a MSBuild script and use
<Target Name="GetVersion">
<Message Text="Getting version info..."/>
<GetAssemblyIdentity AssemblyFiles="#(GetVersionAssembly)">
<Output TaskParameter="Assemblies"
ItemName="GetVersionAssemblyInfo"/>
</GetAssemblyIdentity>
<Message Text="%(GetVersionAssemblyInfo.Version)..."/>
</Target>
Where #(GetVersionAssembly) is the path to the executable, the 3.8.0.25806 version is picked, how do I get the published version rather than assembly version extracted in MSBuild, to make it match the manual publish?
What I ended up doing was use the MSBuild.Community.Tasks library and in the GetVersion target add below line, to allow the published version to be stored in the version.txt file. Not sure if there is a way of accessing the publish number within Visual Studio and increment that one when publishing with msbuild, which would prevent having to manually update these versions if you switch between the two ways of publishing. I would characterize this as a half solution since it still involve a manual step.
<Version VersionFile="version.txt" RevisionType="Increment"> <Output TaskParameter="Major" PropertyName="Major" /> <Output TaskParameter="Minor" PropertyName="Minor" /> <Output TaskParameter="Build" PropertyName="Build" /> <Output TaskParameter="Revision" PropertyName="Revision" /> </Version>
Within the script I then changed all %(GetVersionAssemblyInfo.Version) references to $(Major).$(Minor).$(Build).$(Revision)

Categories