9. June 2016 20:20
In the MSBuild deployment script for our discoverize portals we use a number of useful functions from the .NET framework, e.g.: $([System.IO.File]::Exists($file)) $([System.IO.Path]::GetFileName($(Destination))) $([System.IO.Directory]::GetDirectories("$(Folder)")) $([System.DateTime]::Now.ToString($(TimestampFormat))) These methods are called Property Functions and have been made available for use in MSBuild scripts since version 4. Here's the full list of .NET framework types whose static methods or properties you can use almost anywhere in you MSBuild scripts: System.Byte System.Char System.Convert System.DateTime System.Decimal System.Double System.Enum System.Guid System.Int16 System.Int32 System.Int64 System.IO.Path System.Math System.UInt16 System.UInt32 System.UInt64 System.SByte System.Single System.String System.StringComparer System.TimeSpan System.Text.RegularExpressions.Regex Microsoft.Build.Utilities.ToolLocationHelper There are a few rather useful methods from some more types that you can also use: System.Environment::CommandLine System.Environment::ExpandEnvironmentVariables System.Environment::GetEnvironmentVariable System.Environment::GetEnvironmentVariables System.Environment::GetFolderPath System.Environment::GetLogicalDrives System.IO.Directory::GetDirectories System.IO.Directory::GetFiles System.IO.Directory::GetLastAccessTime System.IO.Directory::GetLastWriteTime System.IO.Directory::GetParent System.IO.File::Exists System.IO.File::GetCreationTime System.IO.File::GetAttributes System.IO.File::GetLastAccessTime System.IO.File::GetLastWriteTime System.IO.File::ReadAllText The general pattern to call a property method is: $([Class]::Method(Parameters)). Beyond the above mentioned methods, MSBuild offers some more helpful ones that are invoked on the MSBuild pseudo class: [MSBuild]::DoesTaskHostExist(string runtime, string arch) [MSBuild]::GetDirectoryNameOfFileAbove(string p, string f) [MSBuild]::GetRegistryValue(...) [MSBuild]::GetRegistryValueFromView(...) [MSBuild]::MakeRelative(string path1, string path2) [MSBuild]::ValueOrDefault(string value, string default) [MSBuild]::Escape(string unescaped) [MSBuild]::Unescape(string escaped) [MSBuild]::Add(double a, double b) [MSBuild]::Add(long a, long b) [MSBuild]::Subtract(double a, double b) [MSBuild]::Subtract(long a, long b) [MSBuild]::Multiply(double a, double b) [MSBuild]::Multiply(long a, long b) [MSBuild]::Divide(double a, double b) [MSBuild]::Divide(long a, long b) [MSBuild]::Modulo(double a, double b) [MSBuild]::Modulo(long a, long b) [MSBuild]::BitwiseOr(int first, int second) [MSBuild]::BitwiseAnd(int first, int second) [MSBuild]::BitwiseXor(int first, int second) [MSBuild]::BitwiseNot(int first) The smart thing about those arithmetic methods is that MSBuild converts string values to a matching number type on the fly, so there's no need for any explicit type conversion. And that would be the whole spectrum of property functions in MSBuild. For further reading, please turn to the official documentation on the MSDN. Happy coding! photo credit: Paddington Reservior Gardens Roof via photopin (license)
11. May 2016 12:24
How do I modify an entry in the appSettings node during deployment? We use a custom MSBuild script to deploy our discoverize portals and wanted to set a portal dependent key, namely NewRelic.AppName. So how did we do it? We use the XmlUpdate task from the MSBuild Community Tasks project. Here's the code: <!-- Import all MSBuild Community Tasks --> <Import Project="$(LibFolder)\msbuild\MSBuild.Community.Tasks.Targets" /> <!-- Define the property value we want to use below --> <PropertyGroup> <NewRelicAppName>$([System.IO.Path]::GetFileName($(Destination))), Discoverize Portals</NewRelicAppName> </PropertyGroup> <!-- Update NewRelic.AppName key in appSettings of web.config --> <XmlUpdate XmlFileName="$(Destination)\web.config" XPath="/configuration/appSettings/add[@key='NewRelic.AppName']/@value" Value="$(NewRelicAppName)" /> I'm no XPath guru, so I was glad to find this thread that contained the XPath expression needed to select a certain appSettings entry by key and update its value. If you seek to delete an element from an XML file, this stackoverflow answer taught me that there is also a Delete attribute on the XmlUpdate task :-) Happy deploying!
28. January 2014 21:24
This is embarrassing. For the n-th time during the past couple of years I've felt an unease waiting for our projects (read: solutions) to compile. I kept seeing this: This is MSBuild using 1 (!), yes, one!, of the 8 CPU cores I've sitting in my machine to get my work done. What about the other 7? Why don't you use them, MSBuild? With that single core, currently my simple local build of our project discoverize takes around 36 seconds: Tell MSBuild to use all cpu cores Well, it's as easy as adding /m or /maxcpucount to your msbuild command line build to boost your build times: Down to 8 seconds with 3 additional characters: [space]/m. That's easily a 4.5 times improvement! Your mileage may vary Of course, every project is different, so your speed increase might be higher or a lot lower than what I've seen. But it's an easy measure to get at least some improvement in build times with very little effort. Don't trust Visual Studio on that one, though – the solution builds slowly there, still. For reference, let me tell you, that the /maxcpucount switch can actually take a parameter value like so: /maxcpucount:4. So if you lots of other stuff going on in the background or I don't know for what reason, really, you can limit the number of cpus used by MSBuild. Props to the Orchard team for a highly parallelizable build One of the specifics of the Orchard source code that's the base for discoverize is the very loose coupling between the 70+ projects in the solution. This allows MSBuild to distribute the compilation work to a high number of threads because there are almost no dependencies between the projects that MSBuild would have to respect. Great work! Happy building!
6. September 2011 22:18
Recently, we encountered a quite surprising behavior of MSBuild – the continuous integration build of our new collaborative Todo Management app (we hope to go into beta soon!) would produce a broken version whereas the local build with VS2010 was all smooth and well. Our admin and tester already posted about this problem over at his blog: MSBuild does not build like Visual Studio 2010. The exception message finally led me down the right path: Server Error in '/' Application. No constructors on type 'Teamaton.TodoCore.Repositories.TodoRepositoryJson' can be found with 'Public binding flags'. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: Autofac.Core.DependencyResolutionException: No constructors on type 'Teamaton.TodoCore.Repositories.TodoRepositoryJson' can be found with 'Public binding flags'. The TodoRepositoryJson is a type we used at the very beginning of our development to quickly get started using a JSON document as data store. Later we switched to SQLite, so now we have another implementation: TodoRepositoryDb. Both implement the same interface ITodoRepository. Turns out, the Autofac type registering code was the culprit: 1: var builder = new ContainerBuilder();
2: builder.RegisterAssemblyTypes(typeof (Todo).Assembly)
3: .Where(t => t.Name.Contains("Repository"))
What worked with Visual Studio, didn’t work with MSBuild: obviously – well, now it is – both ITodoRepository implementations were registered with Autofac, and while Autofac’s assembly scanning delivered them in the order we assumed from the DLL built with VS – first, TodoRepositoryJson, and second, TodoRepositoryDb, thus overriding the first registration – MSBuild seems to build a DLL which returns the inverse order! Very strange.
Honestly, I’m not familiar with the anatomy of DLLs and surprised by this result. But it’s the only explanation I’ve found so far.
Well, the solution to the problem is, of course, to care more about what we register with Autofac and in which order.