How to Auto Increment Assembly or Assembly File Version, from MSBuild? - msbuild

Constraints are:
Using Visual Studio 2017.
Needs to ultimately be called from a powershell script calling MSBuild.
Not sure its relevant, but needs to be able to build the following:
asp.net 461
asp.net-core 1.1 and 2.0 assemblies
Unsuccessful attempts so far:
How to have an auto incrementing version number (Visual Studio)? <- This works when building from VS only.
Code Generation in a Build Process -Described as Microsoft's latest document on using "TextTemplating" with MSBuild. States need to copy certain DLLs to build server.. Files are not located where specified in doc, and dont know where to copy them, I have found all files. Additionally modified .csproj's import Microsoft.TextTemplating.targets path to correct location but when running MSBuild I get. "error MSB4018: The "TransformTemplates" task failed unexpectedly."
This SO Answer - MSBuild support for T4 templates in Visual Studio 2017 RTM
<- Give same MSBuild Runtime error as above.
Example attempt of "Code Generation in a Build Process" That works on build from VS but not MSBuild:
placed in root of project - handleVersioning.tt:
<## template language="C#" #>
using System.Reflection;
[assembly: AssemblyVersion("1.0.0.*")]
[assembly: AssemblyFileVersion("<#= this.Year #>.<#= this.Month #>.<#= this.Day #>.<#= this.Minute #>")]
<#+
int Year = DateTime.UtcNow.Year;
int Month = DateTime.UtcNow.Month;
int Day = DateTime.UtcNow.Day;
int Minute = unchecked((int)DateTime.UtcNow.TimeOfDay.TotalMinutes);
#>
.csproj:
<Import Project="...hardcoded...\Microsoft.CSharp.targets" />
<!-- This is the important line: -->
<Import Project="...hardcoded...\TextTemplating\Microsoft.TextTemplating.targets" />
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
<OverwriteReadOnlyOutputFiles>true</OverwriteReadOnlyOutputFiles>
<TransformOutOfDateOnly>false</TransformOutOfDateOnly>
</PropertyGroup>
Called like so:
msbuild myProject.csproj /t:TransformAll

U can write simple console application and in Project Properties > Build Events, add a "Pre-build event command line" like this: "D:\SomePath\MyAssemblyInfoPatcher.exe" "$(ProjectDir)Properties\AssemblyInfo.cs"
sample application code (works on VS 2022)
using System;
using System.IO;
using System.Linq;
namespace MyAssemblyInfoPatcher
{
internal class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
string path = args[0].ToString();
Console.WriteLine(string.Format("Current App version is set to: {0}", path));
string now_date = DateTime.Now.ToString("yyyy.MM.dd.HHmm");
if (File.Exists(path))
{
string _AssemblyVersion = string.Empty;
string _AssemblyFileVersion = string.Empty;
var lines = File.ReadLines(string.Format(path));
for (int i = 0; i < lines.Count(); i++)
{
if (lines.ElementAt(i).ToString().StartsWith("[assembly: AssemblyVersion"))
{
_AssemblyVersion = lines.ElementAt(i).ToString();
}
else if (lines.ElementAt(i).ToString().StartsWith("[assembly: AssemblyFileVersion"))
{
_AssemblyFileVersion = lines.ElementAt(i).ToString();
}
}
string _replace_assembly = File.ReadAllText(path);
if (_AssemblyVersion != string.Empty)
{
_replace_assembly = _replace_assembly.Replace(_AssemblyVersion, string.Format("[assembly: AssemblyVersion(\"{0}\")]", now_date));
}
if (_AssemblyFileVersion != string.Empty)
{
_replace_assembly = _replace_assembly.Replace(_AssemblyFileVersion, string.Format("[assembly: AssemblyFileVersion(\"{0}\")]", now_date));
}
File.WriteAllText(path, _replace_assembly);
}
}
}
}
}

Related

Project Doesn't Build After Installed Sitecore TDS

After setting up Sitecore TDS, my project will not build. I'm new to Visual Studio and also new to working with Sitecore. It seems that it cannot find a particular setting, but a Google search is not coming up with anything:
Severity Code Description Project Path File Line Suppression State
Error The "AnalyzeProject" task failed unexpectedly.
System.MissingFieldException: Field not found: 'HedgehogDevelopment.SitecoreProject.Tasks.SitecoreDeployInfo.ParsedItem'.
at HedgehogDevelopment.SitecoreProject.Analysis.TemplateStructure.Validate(Dictionary`2 projectItems, XDocument scprojDocument)
at HedgehogDevelopment.SitecoreProject.Tasks.ProjectAnalysis.AnalysisEngine.<>c__DisplayClass4_1.<GetReport>b__0()
at HedgehogDevelopment.SitecoreProject.Tasks.ProjectAnalysis.ExecutionTimer.Time(Action action)
at HedgehogDevelopment.SitecoreProject.Tasks.ProjectAnalysis.AnalysisEngine.GetReport(Dictionary`2 projectItems, XDocument scprojDocument)
at HedgehogDevelopment.SitecoreProject.Tasks.AnalyzeProject.Execute()
at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext() B2B.Core C:\Program Files (x86)\MSBuild\HedgehogDevelopment\SitecoreProject\v9.0 C:\Program Files (x86)\MSBuild\HedgehogDevelopment\SitecoreProject\v9.0\HedgehogDevelopment.SitecoreProject.targets 144
Apparently my project does still build and will run, but that error pops up each time regardless.
This can happen when you have TDS validations enabled and are missing some DLLs.
In this directory:
C:\Program Files (x86)\MSBuild\HedgehogDevelopment\SitecoreProject\v9.0\
Add the following DLLs:
Microsoft.Web.Infrastructure.dll
TDSWebDeploy.Services.Contracts.dll
If you have TDS installed, you may be able to source those DLLs from somewhere in your C:\Program Files (x86)\MSBuild\HedgehogDevelopment directory. If not, someone else on your team may have them.
You can also try disabling and enabling validations by right clicking your TDS project --> Properties --> Validations tab.
I have seen this issue on numerous occasions across numerous dev boxes. We have opened support tickets regarding it, but no conclusions were drawn.
The specific error is that the HedgehogDevelopment.SitecoreProject.Tasks.SitecoreDeployInfo.ParsedItem field is missing on an object. The fact that ParsedItem is mentioned implies that some form of parsing may be occurring, and that it didn't work as expected. This is conjecture, but if parsing is occurring, it would be worth ensuring that your serialized item files are accessible to the user/group that is performing this parsing.
Here is the code that is failing:
public override IEnumerable<Problem> Validate(Dictionary<Guid, SitecoreDeployInfo> projectItems, XDocument scprojDocument)
{
List<Problem> problems = new List<Problem>();
foreach (KeyValuePair<Guid, SitecoreDeployInfo> projectItem in projectItems)
{
// ** Presumably, it's failing here **
string item = projectItem.Value.ParsedItem.Properties["template"];
if (string.IsNullOrEmpty(item))
{
continue;
}
Guid guid = new Guid(item);
if (guid == TemplateStructure.TEMPLATE)
{
problems.AddRange(this.ValidateTemplate(projectItems, projectItem.Value.Item));
}
else if (guid != TemplateStructure.TEMPLATE_SECTION)
{
if (guid != TemplateStructure.TEMPLATE_FIELD)
{
continue;
}
problems.AddRange(this.ValidateField(projectItems, projectItem.Value.Item));
}
else
{
problems.AddRange(this.ValidateSection(projectItems, projectItem.Value.Item));
}
}
problems.RemoveAll((Problem r) => r == null);
return problems;
}
Here is the definition for SitecoreDeployInfo:
using HedgehogDevelopment.SitecoreCommon.Data.Items;
using System;
namespace HedgehogDevelopment.SitecoreProject.Tasks
{
public class SitecoreDeployInfo
{
public IItem ParsedItem;
public SitecoreItem Item;
public SitecoreDeployInfo()
{
}
}
}

Setting the version number for .NET Core projects

What are the options for setting a project version with .NET Core / ASP.NET Core projects?
Found so far:
Set the version property in project.json. Source: DNX Overview, Working with DNX projects. This seems to set the AssemblyVersion, AssemblyFileVersion and AssemblyInformationalVersion unless overridden by an attribute (see next point).
Setting the AssemblyVersion, AssemblyFileVersion, AssemblyInformationalVersion attributes also seems to work and override the version property specified in project.json.
For example, including 'version':'4.1.1-*' in project.json and setting [assembly:AssemblyFileVersion("4.3.5.0")] in a .cs file will result in AssemblyVersion=4.1.1.0, AssemblyInformationalVersion=4.1.1.0 and AssemblyFileVersion=4.3.5.0
Is setting the version number via attributes, e.g. AssemblyFileVersion, still supported?
Have I missed something - are there other ways?
Context
The scenario I'm looking at is sharing a single version number between multiple related projects. Some of the projects are using .NET Core (project.json), others are using the full .NET Framework (.csproj). All are logically part of a single system and versioned together.
The strategy we used up until now is having a SharedAssemblyInfo.cs file at the root of our solution with the AssemblyVersion and AssemblyFileVersion attributes. The projects include a link to the file.
I'm looking for ways to achieve the same result with .NET Core projects, i.e. have a single file to modify.
You can create a Directory.Build.props file in the root/parent folder of your projects and set the version information there.
However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.
For example:
<Project>
<PropertyGroup>
<Version>0.0.0.0</Version>
<FileVersion>0.0.0.0</FileVersion>
<InformationalVersion>0.0.0.0.myversion</InformationalVersion>
</PropertyGroup>
</Project>
Another option for setting version info when calling build or publish is to use the undocumented /p option.
dotnet command internally passes these flags to MSBuild.
Example:
dotnet publish ./MyProject.csproj /p:Version="1.2.3" /p:InformationalVersion="1.2.3-qa"
See here for more information: https://github.com/dotnet/docs/issues/7568
Not sure if this helps, but you can set version suffixes at publish time. Our versions are usually datetime driven, so that developers don't have to remember to update them.
If your json has something like "1.0-*"
"dotnet publish --version-suffix 2016.01.02" will make it "1.0-2016.01.02".
It's important to stick to "semvar" standards, or else you'll get errors. Dotnet publish will tell you.
Why not just change the value in the project.json file. Using CakeBuild you could do something like this (optimizations probably possible)
Task("Bump").Does(() => {
var files = GetFiles(config.SrcDir + "**/project.json");
foreach(var file in files)
{
Information("Processing: {0}", file);
var path = file.ToString();
var trg = new StringBuilder();
var regExVersion = new System.Text.RegularExpressions.Regex("\"version\":(\\s)?\"0.0.0-\\*\",");
using (var src = System.IO.File.OpenRead(path))
{
using (var reader = new StreamReader(src))
{
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if(line == null)
continue;
line = regExVersion.Replace(line, string.Format("\"version\": \"{0}\",", config.SemVer));
trg.AppendLine(line);
}
}
}
System.IO.File.WriteAllText(path, trg.ToString());
}
});
Then if you have e.g. a UnitTest project that takes a dependency on the project, use "*" for dependency resolution.
Also, do the bump before doing dotnet restore. My order is as follows:
Task("Default")
.IsDependentOn("InitOutDir")
.IsDependentOn("Bump")
.IsDependentOn("Restore")
.IsDependentOn("Build")
.IsDependentOn("UnitTest");
Task("CI")
.IsDependentOn("Default")
.IsDependentOn("Pack");
Link to full build script: https://github.com/danielwertheim/Ensure.That/blob/3a278f05d940d9994f0fde9266c6f2c41900a884/build.cake
The actual values, e.g. the version is coming from importing a separate build.config file, in the build script:
#load "./buildconfig.cake"
var config = BuildConfig.Create(Context, BuildSystem);
The config file looks like this (taken from https://github.com/danielwertheim/Ensure.That/blob/3a278f05d940d9994f0fde9266c6f2c41900a884/buildconfig.cake):
public class BuildConfig
{
private const string Version = "5.0.0";
public readonly string SrcDir = "./src/";
public readonly string OutDir = "./build/";
public string Target { get; private set; }
public string Branch { get; private set; }
public string SemVer { get; private set; }
public string BuildProfile { get; private set; }
public bool IsTeamCityBuild { get; private set; }
public static BuildConfig Create(
ICakeContext context,
BuildSystem buildSystem)
{
if (context == null)
throw new ArgumentNullException("context");
var target = context.Argument("target", "Default");
var branch = context.Argument("branch", string.Empty);
var branchIsRelease = branch.ToLower() == "release";
var buildRevision = context.Argument("buildrevision", "0");
return new BuildConfig
{
Target = target,
Branch = branch,
SemVer = Version + (branchIsRelease ? string.Empty : "-b" + buildRevision),
BuildProfile = context.Argument("configuration", "Release"),
IsTeamCityBuild = buildSystem.TeamCity.IsRunningOnTeamCity
};
}
}
If you still want to have the Solution Level SharedVersionInfo.cs you can do it by adding these lines to your project.json file:
"buildOptions": {
"compile": {
"includeFiles": [
"../../SharedVersionInfo.cs"
]
}
}
Your relative path may vary, of course.
use external version.txt file with version, and prebuild step to publish this version in projects

C# Executable project (console app) for a test project

I have a test project which is a library. I want to write a console application to be able to reference the DLL of the test project and call the methods and classes from my test project.
Also while writing the console app, I want to how to execute the exe from command prompt with parameters. My console app code should take in the input I give and execute the tests.
I just need some example code, so that I can pick it up from there.
You have to follow these steps:
Add your DLL file as reference to your console project.
Project>>Add Reference>>Browse and select your dll file.
add usign myNamespaceOfMyDll;
Then in your code you can use the methods from your dll file.
Sample (Using the GMmap's dll):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GMap.NET;
usign myNamespace;
namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
//GPoint is a user data type declared in GMap.NET
//method is a method definied in myNamespace (your dll)
GPoint s=method(param1,param2);
}
}
}
Suppose that you have the next code, you have to add an array of strings as param in your main method.
using System;
class Program
{
static void Main(string[] args)
{
if (args == null)
{
Console.WriteLine("args is null"); // Check for null array
}
else
{
//Here you can to use then content of your args array.
}
Console.ReadLine();
}
}
Thus if you type:
c:\> myApp param1 param2
args[0]="param1", args[1]="param2", and the length of the array is 2.

CSS Intellisense not working for MVC 4 project in Visual Studio 2012 Ultimate

Have created a brand new Visual Studio 2012 Ultimate SP2 MVC4 project but unable to get CSS class selector intellisense to work?
When I type <p class="m" .... I should get the class "myClass" appearing in intellisense dropdown but nothing happens.
The file I have listed below is: \Views\Shared\_Layout.cshtml
Any Ideas ?
Edit: Have re-installed VS2012 on brand new windows 7 system (running on Mac OSX parallels 8) and still acting in the same way. Also seems the same for MVC 3 projects.
Extensions installed:
Try adding Web Essentials 2012 extension for Visual Studio 2012: http://visualstudiogallery.msdn.microsoft.com/07d54d12-7133-4e15-becb-6f451ea3bea6?SRC=VSIDE
And/Or
Try adding Microsoft Web Developer Tools extension.
I have both of these and using your same example the intellisense works like a charm.
I tried all the above mentioned remedies and suggestions. None of these worked in my environment. According to Microsoft (Under Microsoft connect's bug id 781048), they have not implemented CSS class intellisense for MVC/Razor files but are working on including this in a future release.
I have a 10 minute webcast example of extending VS2012 intellisense that adds one solution that will add intellisense to your VS2012 environment: a Visual Studio Intellisense Extension
The webcast uses MEF to extend Visual Studio to add an intellisense completion source that scans the currently loaded project for CSS class names to add as an intellisense completion set. Here is the css completion source class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
using EnvDTE;
using System.Text.RegularExpressions;
using System.Configuration;
using System.Collections.Specialized;
namespace CssClassIntellisense
{
internal class cssClassList
{
public string cssFileName { get; set; } //Intellisense Statement Completion Tab Name
public HashSet<string> cssClasses { get; set; }
}
internal class CssClassCompletionSource : ICompletionSource
{
private CssClassCompletionSourceProvider m_sourceProvider;
private ITextBuffer m_textBuffer;
private List<Completion> m_compList;
private Project m_proj;
private string m_pattern = #"(?<=\.)[A-Za-z0-9_-]+(?=\ {|{|,|\ )";
private bool m_isDisposed;
//constructor
public CssClassCompletionSource(CssClassCompletionSourceProvider sourceProvider, ITextBuffer textBuffer, Project proj)
{
m_sourceProvider = sourceProvider;
m_textBuffer = textBuffer;
m_proj = proj;
}
public void AugmentCompletionSession(ICompletionSession session, IList<CompletionSet> completionSets)
{
ITextSnapshot snapshot = session.TextView.TextSnapshot;
SnapshotPoint currentPoint = (SnapshotPoint)session.GetTriggerPoint(snapshot);
if (TargetAttribute.Inside(currentPoint))
{
var hash = new List<cssClassList>();
//read any .css project file to get a distinct list of class names
if (m_proj != null)
foreach (ProjectItem _item in m_proj.ProjectItems)
{
getCssFiles(_item, hash);
}
//Scan Current Editor's text buffer for any inline css class names
cssClassList cssclasslist = ScanTextForCssClassName(
"Inline", snapshot.GetText());
//If file had any css class names add to hash of files with css class names
if (cssclasslist != null)
hash.Add(cssclasslist);
var _tokenSpanAtPosition = FindTokenSpanAtPosition(session.GetTriggerPoint(m_textBuffer), session);
foreach (cssClassList _cssClassList in hash)
{
m_compList = new List<Completion>();
foreach (string str in _cssClassList.cssClasses.OrderBy(x => x)) //alphabetic sort
m_compList.Add(new Completion(str, str, str, null, null));
completionSets.Add(new CompletionSet(
_cssClassList.cssFileName, //the non-localized title of the tab
_cssClassList.cssFileName, //the display title of the tab
_tokenSpanAtPosition,
m_compList,
null));
}
}
}
private ITrackingSpan FindTokenSpanAtPosition(ITrackingPoint point, ICompletionSession session)
{
SnapshotPoint currentPoint = (session.TextView.Caret.Position.BufferPosition) - 1;
ITextStructureNavigator navigator = m_sourceProvider.NavigatorService.GetTextStructureNavigator(m_textBuffer);
TextExtent extent = navigator.GetExtentOfWord(currentPoint);
return currentPoint.Snapshot.CreateTrackingSpan(extent.Span, SpanTrackingMode.EdgeInclusive);
}
private void getCssFiles(ProjectItem proj, List<cssClassList> hash)
{
foreach (ProjectItem _item in proj.ProjectItems)
{
if (_item.Name.EndsWith(".css") &&
!_item.Name.EndsWith(".min.css"))
{
//Scan File's text contents for css class names
cssClassList cssclasslist = ScanTextForCssClassName(
_item.Name.Substring(0, _item.Name.IndexOf(".")),
System.IO.File.ReadAllText(_item.get_FileNames(0))
);
//If file had any css class names add to hash of files with css class names
if (cssclasslist != null)
hash.Add(cssclasslist);
}
//recursively scan any subdirectory project files
if (_item.ProjectItems.Count > 0)
getCssFiles(_item, hash);
}
}
private cssClassList ScanTextForCssClassName(string FileName, string TextToScan)
{
Regex rEx = new Regex(m_pattern);
MatchCollection matches = rEx.Matches(TextToScan);
cssClassList cssclasslist = null;
if (matches.Count > 0)
{
//create css class file object to hold the list css class name that exists in this file
cssclasslist = new cssClassList();
cssclasslist.cssFileName = FileName;
cssclasslist.cssClasses = new HashSet<string>();
}
foreach (Match match in matches)
{
//creat a unique list of css class names
if (!cssclasslist.cssClasses.Contains(match.Value))
cssclasslist.cssClasses.Add(match.Value);
}
return cssclasslist;
}
public void Dispose()
{
if (!m_isDisposed)
{
GC.SuppressFinalize(this);
m_isDisposed = true;
}
}
}
}
As an FYI, you can also address this issue using Resharper. But that is a 3rd party product that needs to be purchased for Visual Studio
Is it just CSS intellisense that's failed or has it completely stopped throughout Visual Studio?
I had a similar issue that effected the whole of my Visual Studio 2012. It was a while back but I remember deleting a folder from my appdata. Take a look at this link, hopefully it will help:
http://www.haneycodes.net/visual-studio-2012-intellisense-not-working-solved/
You are not going to get intellisense for CSS in VS2012 for Razor views. There is a workaround to use intellisense. Just create one test view(.aspx) using ASPX view engine and include your css file there. Now intellisense will work in new aspx view. All you have to do is copy paste the css class from aspx to Razor view(.cshtml or .vbhtml). I hope this helps.

Custom Bootstrapper to show only MSI dialogs

I'm using Wix 3.6 and I would like to implement a bootstrapper for my prerequisites and for certain exe's that I need to call during my install.
I know Burn exists and have played around with it, although I don't like the dialog it keeps up even if you show the MSI dialog set.
I currently have my prerequisites and exe files installing with C++ custom actions but I would like my user to have a better installation process and also follow the Windows Installer Best Practices guidelines.
Does anyone know to to make a bootstrapper that shows the MSI dialogs and have any examples?
At first, if you want to follow installer best practices, I wouldn't recommend installing prerequisites using custom actions.
Speaking about your question, here is my implementation of custom bootstrapper in C#:
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SetupBootstrapper
{
class Program
{
[STAThread]
static void Main(string[] args)
{
var currentDir = AppDomain.CurrentDomain.BaseDirectory;
var parameters = string.Empty;
if (args.Length > 0)
{
var sb = new StringBuilder();
foreach (var arg in args)
{
if (arg != "/i" && arg != "/x" && arg != "/u")
{
sb.Append(" ");
sb.Append(arg);
}
}
parameters = sb.ToString();
}
bool isUninstall = args.Contains("/x") || args.Contains("/u");
string msiPath = Path.Combine(currentDir, "MyMsiName.msi");
if(!File.Exists(msiPath))
{
MessageBox.Show(string.Format("File '{0}' doesn't exist", msiPath), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
string installerParameters = (isUninstall ? "/x" : "/i ") + "\"" + msiPath + "\"" + parameters;
var installerProcess = new Process { StartInfo = new ProcessStartInfo("msiexec", installerParameters) { Verb = "runas" } };
installerProcess.Start();
installerProcess.WaitForExit();
}
}
}
To make it ask for elevated permissions I add application manifest file into project with desired access level.
The drawback of implementing bootstrapper in .NET is of course that you can't adequately process situation when .NET is a prerequisite itself and may be absent on target machine.