Computed const value constantly one build behind - c#

While updating our build incrementer program that runs during the pre-build event, I noticed a potential problem that can cause quite a bit of issues. Building the application the first time successfully updates BuildInfo.cs and calculates all of the const values. Each subsequent build and successful execution of the pre-build event updates the proper file (as provided below) but each computed const value is out of date from the last build.
// In externally modified file BuildInfo.cs which is updated by our pre-build
// tool to update the version information and produce new consts.
namespace ConstProblem.Properties {
static class BuildInfo {
internal const string AssemblyVersionString = "1.1.0.0";
internal const string BuildDate = "2012-11-07T08:52:32.5480259-07:00";
internal const string FileVersionString = "1.1.12312.852";
internal const string Full = "v1.1 (Build: 2012-11-07 08:52)";
internal const string Short = "1.1";
}
}
// Program.cs. Reproduces the problem for this question.
namespace ConstProblem {
class Program {
const string UserAgent = "ConstProblem/" + Properties.BuildInfo.Short;
static void Main() {
System.Console.WriteLine(UserAgent);
}
}
}
As an example, the application was originally built with the AssemblyVersionString at 1.0.0.0. The above program ran and compiled as expected. Increasing this to 1.1 and building/running the application a second time produced ConstProblem/1.0 as it's output and has this as it's values
// From the Immediate Window
Properties.BuildInfo
ConstProblem.Properties.BuildInfo
base {object}: object
AssemblyVersionString: "1.1.0.0"
BuildDate: "2012-11-07T08:51:46.8404556-07:00"
FileVersionString: "1.0.12312.851"
Full: "v1.0 (Build: 2012-11-07 08:51)"
Short: "1.0"
As you can see, the AssemblyVersionString was updated 1.1.0.0 properly but the rest of the computed values did not. If I were to build and execute a third time (and increase to 1.2) they would update to the information provided above.
I have confirmed that the output file by the pre-build event outputs all of the information correctly and exits with a status of 0 to allow the build to continue. I am at a loss as to why the const's are constantly one build behind. The build utility is also something I wrote and it just uses a template and replaces the contents of the BuildInfo.cs if the file is checked-out.
My environment is running Visual Studio 2010 Ultimate and compiling in .Net 4. I've reproduced this in both Console and Web applications. I got the idea for using const values from the comments in How to get the assembly version and file version of your own assembly?

It's reading the successful build increment from AssemblyInfo.cs
But that only increments by 1 after a successful build, hence why your always 1 behind.
add
[assembly: AssemblyVersion("1.star.star.star")] to AssemblyInfo.cs (in Solution/Properties)
^ star = * (editor limitation)

Related

Does the Visual Studio OneClick publisher change the byte array needed for RSA encryption?

I'm trying to publish a COM add-in for Word and need to have a license file. I'm using Rhino Licensing and the file has no issues during debugging, but when using OneClick to publish the add-in the license is reported as no longer valid. Here is the code for the class I'm using to check the license:
using System;
using System.IO;
using Rhino.Licensing;
namespace Services.Licensing
{
public class LicenseChecker
{
private static string PublicKeyPath;
private static string LicensePath;
public static bool LicenseIsValid(string licPath)
{
bool result = false;
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
String Root = Directory.GetCurrentDirectory();
PublicKeyPath = Root + #"\Licensing\publicKey.xml";
LicensePath = Root + #"\Licensing\license.xml"; //licPath;
// not working on INSTALL, runs fine in debug
try
{
var publicKey = File.ReadAllText(PublicKeyPath);
//Throws an exception if license has been modified
LicenseValidator validator = new LicenseValidator(publicKey, LicensePath);
validator.AssertValidLicense();
if (validator.ExpirationDate > DateTime.Now)
{
result = true;
}
}
catch
{ }
return result;
}
}
}
I'm trying to bundle the license with the exe I'll be giving to a small testing group to save the testers unnecessary trouble managing the license and public key. Currently I have the (valid) license file and public key as embedded resources, set to "copy always."
I'm having the same issue when the license is not bundled with the published exe, but the public key is. When both files are left outside of the solution, there seems to be no problem. Could publishing the solution be changing the byte array of the public key or the license?
I'm using .Net Framework 4.7.2 and Visual Studio 2019.
After a lot of toying, the broad answer seems to be no, ClickOnce publishing does not affect the byte array.
The error seems to be occurring because the ClickOnce is not copying XML files into the Application Files folder it creates at all.
After pulling the licenses into a desktop folder and having the program call them from there, another class that uses XML files to load list items would not initialize, leading me to put Try{} around all functions that use pre-made XML files in my program. Each of these functions returned the Catch{}. I'm assuming that ClickOnce is too simplistic an installer to be used if you are trying to include many/any resource files, especially if they are XML.

C#: Compare whether 2 DLLs are equal binaries or not using C# code not TOOLS

My question is not same as below.
Compare Two DLL's
I am trying to compare whether 2 DLLs are equal binaries or not using C# code. If needed I can refer some third party DLL but the comparision must be done by C# code not manual opening tool.
This is my bigger task..
C# Common libraries same location for different WCF services
I have a dll called MyDll.dll at below locations
C:\Source\MyDll.dll
C:\Destination\MyDll.dll
I wrote a method which gets MyDll.dll from C:\Source and drop/replace into C:\Destination but I do not want to blindly replace MyDll.dll in C:\Destination. I want to check whether C:\Source\MyDll.dll and C:\Destination\MyDll.dll are same or not. If not then only replace.
Please remember everything needs to be happening in C# code since this method runs on a start event of windows service.
public void LoadAssembly()
{
string source = #"C:\Source\MyDll.dl"
string destination = #"C:\Destination\MyDll.dll"
// To copy a file to another location and
// overwrite the destination file if it already exists.
System.IO.File.Copy(source, destination, true);
}
Looked at this not use
C# - comparing two .net dlls using reflection
UPDATE
I created below method and I feel it has performance issue depending on how big my dll is. Is there any way I can improve this.
public static bool AreFilesEqual()
{
string source = #"C:\Source\MyDll.dll";
string dest = #"C:\Destination\MyDll.dll";
byte[] sourceFileBytes = File.ReadAllBytes(source);
byte[] destinationFileBytes = File.ReadAllBytes(dest);
// if two files length are not same then they are not equal
if(sourceFileBytes.Length != destinationFileBytes.Length)
{
return false;
}
return sourceFileBytes.SequenceEqual(destinationFileBytes);
}

Checking Visual Studio projects for consistency

You have a large Visual Studio Solution with dozens of project files in it. How would you verify that all the projects follow certain rules in their property settings, and enforce these rules if a new project is added. For example check that all projects have:
TargetFrameworkVersion = "v4.5"
Platform = "AnyCPU"
WarningLevel = 4
TreatWarningsAsErrors = true
OutputPath = $(SolutionDir)bin
SignAssembly = true
AssemblyName = $(ProjectFolderName)
I know two methods myself that I will add in an answer below, but I was wondering how people go about doing this type of project test. I'm especially interested to learn about available solutions such as libraries or build tasks for this rather than having to have to invent something new or write it from scratch.
*.sln files are plain text and easily parsable, and *.*proj files are xml.
You can add a dummy project with a prebuild step that parses the sln to retrieve all of the project files, validate their settings, print a report, and fail the build if necessary.
Also, you should check this post to ensure the prebuild step is always executed. Essentially, you specify a blank output in the custom build step to force a rebuild.
The following list identifies the key file types that are automatically added to VSS when a solution is added to source control by using the Visual Studio .NET integrated development environment (IDE):
Solution files (.sln). The key items maintained within these files include a list of constituent projects, dependency information, build configuration details, and source control provider details.
Project files (.csproj or *.vbproj). The key items maintained within these files include assembly build settings, referenced assemblies (by name and path), and a file inventory.
Application configuration files. These are configuration files based on Extensible Markup Language (XML) used to control various aspects of your project's run time behavior.
Use a Single Solution Model Whenever Possible an
Also see : https://msdn.microsoft.com/en-us/library/ee817677.aspx,
https://msdn.microsoft.com/en-us/library/ee817675.aspx
AND For CONTINUOUS INTEGRATION :
there are many tools available like MSBuild, Jenkins, Apache's Continuum, Cruise Control (CC), and Hudson(plugin can be extended to c#)
This is what I have myself:
One way to do this is to create an MSBuild target with error conditions:
<Error Condition="'$(TreatWarningsAsErrors)'!='true'" Text="Invalid project setting" />
I like this approach because it is integrated with MSBuild and gives you early errors, however, you have to modify every project to import it in them or get all your team members to use a special command prompt with environment variables that will inject custom pre-build steps into your projects during the build, which is a pain.
The second approach I know is to use some library like VSUnitTest which provides an API to project properties that you can test against. VSUnitTest is currently not open source and unlisted from the NuGet service.
You could write some code to open the the solution as a text file to identify all of the csproj files referenced, in turn opening each of these as xml files, and then writing unit tests to ensure specific nodes of the project match what you expect.
It's a quick and dirty solution, but works for CI and gives you the flexibility to ignore nodes you don't care about. It actually sounds kinda useful. I have a solution with 35 projects I'd like to scan too.
Let's try something completely different: you could ensure that they are consistent by construction by generating them from a template or by using a build generation tool such as CMake. This might be simpler than attempting to make them consistent after the fact.
In our work we use a powershell script that checks project settings and modified them if they are incorrect. For example, we remove Debug configuration this way, disable C++ optimization and SSE2 support. We run it manually, but definitely it is possible to run it automatically, e.g. as pre\post build step.
Below the example:
`function Prepare-Solution {
param (
[string]$SolutionFolder
)
$files = gci -Recurse -Path $SolutionFolder -file *.vcxproj | select - ExpandProperty fullname
$files | %{
$file = $_
[xml]$xml = get-content $file
#Deleting Debug configurations...
$xml.Project.ItemGroup.ProjectConfiguration | ?{$_.Configuration -eq "Debug"} | %{$_.ParentNode.RemoveChild($_)} | Out-Null
$xml.SelectNodes("//*[contains(#Condition,'Debug')]") |%{$_.ParentNode.RemoveChild($_)} | Out-Null
if($xml.Project.ItemDefinitionGroup.ClCompile) {
$xml.Project.ItemDefinitionGroup.ClCompile | %{
#Disable SSE2
if (-not($_.EnableEnhancedInstructionSet)){
$_.AppendChild($xml.CreateElement("EnableEnhancedInstructionSet", $xml.DocumentElement.NamespaceURI)) | Out-Null
}
if($_.ParentNode.Condition.Contains("Win32")){
$_.EnableEnhancedInstructionSet = "StreamingSIMDExtensions"
}
elseif($_.ParentNode.Condition.Contains("x64")) {
$_.EnableEnhancedInstructionSet = "NotSet"
} else {
Write-Host "Neither x86 nor x64 config. Very strange!!"
}
#Disable Optimization
if (-not($_.Optimization)){
$_.AppendChild($xml.CreateElement("Optimization", $xml.DocumentElement.NamespaceURI)) | Out-Null
}
$_.Optimization = "Disabled"
}
}
$xml.Save($file);
} }`
A file is an assembly if and only if it is managed, and contains an assembly entry in its metadata. For more information on assemblies and metadata, see the topic Assembly Manifest.
How to manually determine if a file is an assembly
Start the Ildasm.exe (IL Disassembler).
Load the file you wish to test.
If ILDASM reports that the file is not a portable executable (PE) file, then it is not an assembly. For more information, see the topic How to: View Assembly Contents.
How to programmatically determine if a file is an assembly
Call the GetAssemblyName method, passing the full file path and name of the file you are testing.
If a BadImageFormatException exception is thrown, the file is not an assembly.
This example tests a DLL to see if it is an assembly.
class TestAssembly
{
static void Main()
{
try
{
System.Reflection.AssemblyName testAssembly = System.Reflection.AssemblyName.GetAssemblyName(#"C:\Windows\Microsoft.NET\Framework\v3.5\System.Net.dll");
System.Console.WriteLine("Yes, the file is an assembly.");
}
catch (System.IO.FileNotFoundException)
{
System.Console.WriteLine("The file cannot be found.");
}
catch (System.BadImageFormatException)
{
System.Console.WriteLine("The file is not an assembly.");
}
catch (System.IO.FileLoadException)
{
System.Console.WriteLine("The assembly has already been loaded.");
}
}
}
// Output (with .NET Framework 3.5 installed):
// Yes, the file is an assembly.
Framework is the highest installed version, SP is the service pack for that version.
RegistryKey installed_versions = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\NET Framework Setup\NDP");
string[] version_names = installed_versions.GetSubKeyNames();
//version names start with 'v', eg, 'v3.5' which needs to be trimmed off before conversion
double Framework = Convert.ToDouble(version_names[version_names.Length - 1].Remove(0, 1), CultureInfo.InvariantCulture);
int SP = Convert.ToInt32(installed_versions.OpenSubKey(version_names[version_names.Length - 1]).GetValue("SP", 0));
For .Net 4.5
using System;
using Microsoft.Win32;
...
private static void Get45or451FromRegistry()
{
using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) {
int releaseKey = Convert.ToInt32(ndpKey.GetValue("Release"));
if (true) {
Console.WriteLine("Version: " + CheckFor45DotVersion(releaseKey));
}
}
}
...
// Checking the version using >= will enable forward compatibility,
// however you should always compile your code on newer versions of
// the framework to ensure your app works the same.
private static string CheckFor45DotVersion(int releaseKey)
{
if (releaseKey >= 393273) {
return "4.6 RC or later";
}
if ((releaseKey >= 379893)) {
return "4.5.2 or later";
}
if ((releaseKey >= 378675)) {
return "4.5.1 or later";
}
if ((releaseKey >= 378389)) {
return "4.5 or later";
}
// This line should never execute. A non-null release key should mean
// that 4.5 or later is installed.
return "No 4.5 or later version detected";
}
For similar purposes we use custom MSBuild fragments with common properties that we want to share between the projects, like this (build.common.props file):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<PlatformToolset>v90</PlatformToolset>
<OutputPath>$(SolutionDir)..\bin\$(PlatformPath)\$(Configuration)\</OutputPath>
<!-- whatever you need here -->
</PropertyGroup>
</Project>
And then we just include this fragment to real VS projects we want to apply these properties to:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CommonProps>$(SolutionDir)..\Build\build.common.props</CommonProps>
</PropertyGroup>
<Import Project="$(CommonProps)" />
<!-- the rest of the project -->
</Project>
We handle a lot of things using this approach:
common properties, as you mentioned
static analysis (FxCop, StyleCop)
digital sign of assemblies
etc.
The only disadvantage that you need to include these MSBuild fragments into each project file, but once you do that, you have all the benefits of modular build system that is easy to manage and update.
You could go the search & replace Regex way with a handwritten C#, Script, powershell or similar. But it has the following problems:
Difficult to read (Read your pretty regex in three or more months)
Difficult to enhance(New regex for new search/replace/check feature)
Easy to break (a new release/format of ms build project or a not forecast tag may not work)
Harder to test (you must check that no unintended match occurs)
Difficult to maintain (because of the above)
and the following advantages:
Not doing any extra validation which (may) let it work on any kind of project (mono or visual).
Doesn't care about \r :)
The best could be to use the Microsoft.Build.Evaluation
and build a C# tool which does all your testing/checking/fix and so on.
I've done a command line tool that use a sourcefile list (used by Mono) and update sources of csproj and another which dumps on console the csproj content. It was easy to do, pretty straightforward and easy to test also.
However, it may fail (as I've experienced it) on projects modified by "non" Ms tool (like Mono Studio) or because of missing \r....
Anyway, you can always handle it with an exception catch and a good message.
Here a sample by using Microsoft.Build.dll (don't use Microsof.Build.Engine as it is obsolete):
using System;
using Microsoft.Build.Evaluation;
internal class Program
{
private static void Main(string[] args)
{
var project = new Project("PathToYourProject.csproj");
Console.WriteLine(project.GetProperty("TargetFrameworkVersion", true, string.Empty));
Console.WriteLine(project.GetProperty("Platform", true, string.Empty));
Console.WriteLine(project.GetProperty("WarningLevel", true, string.Empty));
Console.WriteLine(project.GetProperty("TreatWarningsAsErrors", true, "false"));
Console.WriteLine(project.GetProperty("OutputPath", false, string.Empty));
Console.WriteLine(project.GetProperty("SignAssembly", true, "false"));
Console.WriteLine(project.GetProperty("AssemblyName", false, string.Empty));
Console.ReadLine();
}
}
public static class ProjectExtensions
{
public static string GetProperty(this Project project, string propertyName, bool afterEvaluation, string defaultValue)
{
var property = project.GetProperty(propertyName);
if (property != null)
{
if (afterEvaluation)
return property.EvaluatedValue;
return property.UnevaluatedValue;
}
return defaultValue;
}
}
I also faced this issue and created a small solution that creates a csv file with details to identifies the inconsistences. You can look at it in this url
https://github.com/gdlmanuv/VSProjectConsistencyChecker

Visual Studio deleting files it needs to debug

I started running into a small problem regarding debugging my program. It would start off showing no errors, then I would press debug to test it. It would throw me an error saying
"Could not copy the file "obj\x86\Debug[programName].exe" because it was not found."
I have proceeded to tamper with various things, and came to the conclusion that it was a class that I am using to read ini files by importing a dll. The two most likely lines in that class are these:
[DllImport("kernel32")]
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
To test this, I removed the class and all references from the project, and it would build the project successfully. Then, I could look at the path and find the executable that was previously missing. Thinking the problem fixed, I put the class back in and as you would expect, it broke with the same error. It actually deleted the executable file before building, so in my head, it is obvious why it couldn't be found.
However, the not so obvious part is: The program was building and executing with this class in it up until this morning with no changes performed on it. Plus, the class works perfectly inside of my Unity3D game where it is reading the ini file this c# program creates.
Can anyone tell me why this is happening, and if there is a fix to it? I already tried creating a new project and re-importing everything, and it produces the same errors.
EDIT
After commenting and uncommenting each line, I found that the three commented lines in this are causing the problem:
public bool SaveToIni()
{
IniFile file = new IniFile("/LoadUpSettings.ini");
try
{
file.IniWriteValue("Screen", "Screen Height", cbbScreenHeight.SelectedItem.ToString());
file.IniWriteValue("Screen", "Screen Width", cbbScreenWidth.SelectedItem.ToString());
//file.IniWriteValue("Controllers", "Razer Hydra", ckbRazerHydra.Checked.ToString());
//file.IniWriteValue("Controllers", "Oculus Rift", ckbOculusRift.Checked.ToString());
//file.IniWriteValue("Screen", "Fullscreen", ckbFullscreen.Checked.ToString());
return true;
}
catch
{
MessageBox.Show("Please fill out all values");
return false;
}
}
This is the IniWriteValue function inside the IniFile class.
[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
public string IniReadValue(string Section, string Key)
{
StringBuilder temp = new StringBuilder(255);
int i = GetPrivateProfileString(Section, Key, "", temp, 255, this.path);
return temp.ToString();
}
Oddly enough, if i remove the ckbRazerHydra.Checked.ToString(), and put in a standard string such as "True", it still doesn't work, although with those 3 lines commented out, the project builds completely.
EDIT
I managed to fix this problem to an extent. I just have to run my program in release version. If I run it in debug mode, I will always get the error saying the exe couldn't be copied because it wasn't found. However, Release mode seems to almost always work.
The bin and obj folders are meant for output only. When you tell Visual Studio to do a clean or a rebuild it will delete all files in these folders. You can safely delete these folders at any time and you shouldn't lose anything in the process.
You are never meant to place any files in these folders. If you want to add an external assembly (EXE or DLL) to your project you should add it to your project using the Add->Existing Item command on a project. Then you can tell your project to reference that file and it will use the local relative path.
For example, if you create a "lib" folder in your project root and place some.dll inside it, you can then add a reference to the file located in your project and it will use the relative path ..\lib\some.dll.
The problem is with files in your current project that you have set to
Copy to output directory=copy always/copy if newer
When you add a file this way VS will delete all other previous files that other projects dumped into your current project bin/.
In order to avoid this situation add the files and leave them with Copy to output directory=Do not copy option and then use MSBuild Copy task to dump your files.
If you are using docker you can simple put a COPY command - the same thing but not with MSBuild.
I believe this is the default behavior of some this MSBuild internal task and a workaround is the only option.

Auto-Include Version # in Label

I am currently including the version number of my publish/release in a label on my application, but have been unable to figure out how to add it so that it auto-updates for every publish. Currently, I am just using a simple text:
//VERSION LABEL
string version = "1.0.0.15 - BETA";
versionLabel.Text = "v" + version;
Is there a way to auto-update the version with each publish?
How about using the assembly version? Depending if you let it auto-uprev, this could save you some time.
var appVersion = Assembly.GetExecutingAssembly().GetName().Version;
versionLabel.Text = String.Format("v{0}", appVersion);
This would be based on the AssemblyInfo's version.
To elaborate on what I mean, if you look at AssemblyInfo.cs, you'll see something like the following:
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
That's essentially saying that if you make it 1.0.* or 1.0.0.* that VS will assign a revision or build and revision, respectfully, for you with every compilation.

Categories

Resources