Change the name of an executable/assembly - c#

I'm looking to change the name of an assembly dynamically in a Jenkins build-step. I have a powershell script that is able to load the .csproj file, and change the AssemblyName attribute. This changes the name of the .exe MSBuild generates. However, if the program were to say, crash, it will still say "[OldName] has stopped working" which is not okay.
How can I fully change this name? No other projects reference the one whose name I'm trying to change so references shouldn't be an issue, as far as I know. I would also need to change the rest of the items found in the "Details" page when doing Right Click -> Properties. e.g., File description, Product Name, etc.
Here is my powershell file for those curious, or who are trying to do this in the future:
param($path, $oldName, $newName)
Write-Host "Getting XML file $path"
[xml]$project = get-content $path
Write-Host "Renaming $oldName to $newName"
$project.Project.PropertyGroup |
Where-Object { $_.AssemblyName -eq $oldName } |
ForEach-Object { $_.AssemblyName = $newName }
Write-Host "Saving changes"
$project.Save($path)

Open your .csproj file in Notepad.
Find the <PropertyGroup /> section that contains the <AssemblyName/> property.
Update the property with a condition:
<AssemblyName Condition="'$(AssemblyNameOverride)'==''">Attachment.JPG.vbs.exe</AssemblyName>
Now when you kick off your build and want to change the AssemblyName, you will use this syntax:
msbuild.exe MyProject.csproj /p:AssemblyNameOverride=GoodTimes.vbs

Related

Check if a <PackageReference/> tag is added to .csproj file

I have a .csproj file as follows:
If a <PackageReference/> tag is added to this csproj file, the build should fail. How do I do that? Is there any setting or a test I can add?
For example,
On my phone at the moment, however you can do the following or rather follow this (unable to test for you):
In Pre-Build Events (Right click on your project, go to Properties) of the project, add the following command:
CD $(SolutionDir)
CALL CheckProj.ps1
Then on the root of your solution, create a bat file called "CheckProj.ps1"
The contents of your script should be along the lines of:
$xml = new-object System.Xml.XmlDocument;
$xml.LoadXml( (get-content 'MyProject.csproj') );
$node = $xml.SelectNodes('//Project/ItemGroup/PackageReference');
exit $node.Count;
Then on the rebuild of the project, if exit isn't equal to 0, it'll fail the build as 0 is expected to simulate success in a build event, anything higher will end up being marked as an error and should fail the whole build process.
I'm not entirely sure why you'd want to do this, but you could do this in a test fairly easily.
Using XUnit:
[Fact]
public void NoPackageReferences()
{
string myCsproj = File.ReadAllText("path/to/my.csproj");
Assert.DoesNotContain("PackageReference", myCsproj);
}
Now, if you wanted to be more thorough, you could parse the XML... But that's probably overkill for this.

How get the "create assembly" output text for post-build script?

I have a SQL Trigger project.
Currently, when I go to "Project->Publish", I can choose "generate script", it will generate a script for me and include my project's assembly via a line:
GO
CREATE ASSEMBLY [MyProject.MyObject]
AUTHORIZATION [dbo]
FROM 0x4F5C8000....
WITH PERMISSION_SET = UNSAFE;
GO
ALTER ASSEMBLY [MyProject.MyObject]
DROP FILE ALL
ADD FILE FROM 0x4D5743....
I want to generate that on build and grab that as text (for Powershell) so i can put it in another file.
I know how to put it in another file via powershell, but how do I generate it on post-build?
Just add you call .ps1 file into .csproj file, write block <propertyGroup> if not exist. It seems like this:
<Target>
...
</Target>
<PropertyGroup>
<PostBuildEvent>Powershell.exe -ExecutionPolicy Unrestricted -file "$(SolutionDir)$(ProjectName)\postbuild.ps1"</PostBuildEvent>
</PropertyGroup>
To do this, I needed two steps in my build script:
#Step 1: Get the file as bytes
$fileBytes = Get-Content -Path $myFilePath -Encoding Byte
#Step 2: Convert it to Hex using a BitConverter
#Step 2a: Remove the dashes it puts in each byte's hex
$fileInHex = [System.BitConverter]::ToString($fileBytes) | ForEach-Object { $_ -replace "-", "" }

Find the "potential" cyclic reference

We have a big solution(320 projects, 2.5 million LoC to give an idea).
I'm trying to add a reference from a project to another project, but VS doesn't allow me to do it because it would imply having a cyclic reference.
I fully understand what a cylcic reference is, and I know how to find them in small solution, but here, there is no "direct link" between the two project(and I also check with one more intermediary project).
But to check that it already took me a very long time.
What would you do to find the whole "chain" of projects(or all the chains of projects) that would imply a cyclic dependency.
Thank you
Would viewing the project dependency diagram visually help?
Right click your solution in Solution Explorer, then click 'View project dependency diagram'
Make sure you have the 'Show Transitive references" option enabled, this will show you where you have indirect dependencies, which might be the issue.
I ended by doing my own tool to find the result. Since I did loose quite some time on this I decided to publish it: https://github.com/jgrossrieder/CyclicReferenceFinder
I think the Visual Studio team should add more information to the classical Cyclic Reference Error.
Visual Studio Ultimate Version Solution:
Follow this MSDN article on how to create a visual Dependency Diagram which also helps you identify potential problems in your solution and dependencies.
How do I get started?
Get an overview of your solution: On the Architecture menu, choose
Generate Dependency Graph, For Solution. You get a graph that shows
the top-level assemblies. You can now explore these assemblies by
expanding them. Move the mouse pointer on top of an assembly, and then
choose the chevron (^) button when it appears. Do the same for
namespaces, types, and members to continue exploring your code.
This requires VS Ultimate Version.
Free Alternative:
A Free Alternative can be found Here
PowerShell Alternative:
You might also wan to take a lot at this interesting Power shell script by "Danny Tuppeny" that gives this result:
Script from page:
function Get-ProjectReferences
{
param(
[Parameter(Mandatory)]
[string]$rootFolder,
[string[]]$excludeProjectsContaining
)
dir $rootFolder -Filter *.csproj -Recurse |
# Exclude any files matching our rules
where { $excludeProjectsContaining -notlike "*$($_.BaseName)*" } |
Select-References
}
function Select-References
{
param(
[Parameter(ValueFromPipeline, Mandatory)]
[System.IO.FileInfo]$project,
[string[]]$excludeProjectsContaining
)
process
{
$projectName = $_.BaseName
[xml]$projectXml = Get-Content $_.FullName
$ns = #{ defaultNamespace = "http://schemas.microsoft.com/developer/msbuild/2003" }
$projectXml |
# Find the references xml nodes
Select-Xml '//defaultNamespace:ProjectReference/defaultNamespace:Name' -Namespace $ns |
# Get the node values
foreach { $_.node.InnerText } |
# Exclude any references pointing to projects that match our rules
where { $excludeProjectsContaining -notlike "*$_*" } |
# Output in yuml.me format
foreach { "[" + $projectName + "] -> [" + $_ + "]" }
}
}
$excludedProjects = "Test1", "Test2"
Get-ProjectReferences "C:\Users\DanTup\Documents\MyProject" -excludeProjectsContaining $excludedProjects | Out-File "C:\Users\DanTup\Documents\MyProject\References.txt"

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

User Controls (asp.net, ascx-files) inside a C# class library, build error (aspnet_compiler.exe)

Having trouble "passing" this error from ASPNET_Compiler.exe:
error CS0103: The name 'TestMath' does not exist in the current context.
The function called within TestMath from a user control (.cs) file, is outside of the context (scope/namespace/...). If I comment out the line that calls a method within TestMath the compilation works and so does my user control (referenced the DLL from within a WebApplication).
The "TestMath"-class is a static class which contains one static method "Get", which returns -1+3 (I have also tried creating it non-static... without luck).
The normal build in Visual Studio (MSBuild) works, but as we all know; it does not pack .ascx files into the DLL properly.
I've attached a .rar containing:
TestLibrary
Contains 1 .ascx control and 1 math class
Contains a post-build event, that runs the "BuildAssembly.cmd", which in turn runs aspnet_compiler and aspnet_merge.
WebSite - one .aspx page, to display the control from the library.
The line that gives the error is located inside Label.ascx.cs, line 18:
Lbl.Text += " MATH: " + TestMath.Get()
Any suggestions at all? Take a guess? Calling a method in a class outside of the .ascx.cs is prohibited? Oh... But there's something to those words! Which mean; if I copy the Math-class inside the User-Control class, like so:
public class Label : UserControl
{
..methods of label
public class Math
{
public static Get()
}
}
The solution does compile and I am able to call methods within both classes... But, as we all want; I am no different: I want to also be able to call other objects (which I do already, they just live in GAC...)... so, hm... Basically; where does aspnet_compiler look for dll's...
Download example solution:
http://s000.tinyupload.com/?file_id=76690332418132532036
If you un-pack the solution to C:\Solutions\Test, you can run it with little to no hassle, assuming Visual Studio 2010, Windows 7... .NET framwork 4 or higher.
Else, here's some code:
ASCX
<%# Control Language="C#"
AutoEventWireup="true"
ClassName="TestLibrary.Controls.Label"
CodeFile="Label.ascx.cs"
CodeBehind="Label.ascx.cs"
Inherits="TestLibrary.Controls.LabelCode" %>
Test
<asp:Label runat="server" ID="Lbl"></asp:Label>
ASCX code behind
protected void Page_Load(object sender, EventArgs e)
{
Lbl.Text = "CodeBehindText...";
Lbl.Text += " MATH: " + TestMath.Get();
}
TestMath
public static int Get()
{
return -1 + 3;
}
BuildAssembly.cmd
SET compiler_path=%systemroot%\Microsoft.NET\Framework64\v4.0.30319
SET aspnet_merge=C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\aspnet_merge.exe
SET websiteproject=C:\Solutions\Test\TestLibrary\TestLibrary
SET compiled=C:\Solutions\Test\TestLibrary\TestLibrary\Compiled
SET outputfolder=C:\Solutions\Test\TestLibrary\TestLibrary\bin\Release
SET outputfilenamedll=TestLibrary.dll
%compiler_path%\aspnet_compiler.exe -p "%websiteproject%" -c -f -d -v / %compiled%
"%aspnet_merge%" %compiled% -o %outputfilenamedll%
COPY /Y %compiled%\bin\%outputfilenamedll% %outputfolder%\%outputfilenamedll%
RMDIR /s /q %compiled%
Wondering why all this "fuzz" with ASCX in 2015? Oh, hoped to reuse ascx files created several years ago, packing them in a library for eternity, signing the assembly, import it to my SharePoint-environment...
After another 4 hours of trying and failing, this is the solution:
Give your ascx control a classname (class name, attribute within .ascx file):
Control Language="C#" AutoEventWireup="true" CodeFile="~/Control.ascx.cs" Inherits="Control" ClassName="UnqiueControlName [must be different than the real class name]" %>
Copy all custom generated DLL's to the BIN folder of the class library.
Or run cmd: gacutil /i
The route of registering custom dll's (for example: Common.dll) into gac, I have tried it, but it seem to be yet another time waster, due to apsnet_compiler does not seem to find assemblies within all gac folders (yes, there's more than just one location/folder). Let's not forget about the hell to update the GAC, MSIL, 32bit, 64bit... If you reference the DLL in a project, then it builds... later down the road you update the DLL, but forget to update GAC...and at runtime the application will use the DLL in GAC... Registering to GAC should only be through Setup/real installation...
Compile your class library as you normally would in Visual Studio, which contains .ascx files.
Change all .ascx files "CodeBehind" attribute to be "CodeFile" (cannot have both, which was one part of my error in the question)
Compile your whole project through aspnet_compiler:
aspnet_compiler.exe -v projectName -p "projectFolder (where csproj lives)" "outputFolder"
Run aspnet_merge.exe on the "outputFolder" that aspnet_compiler created:
aspnet_merge.exe "outputFolder" -o "nameOfDLLYouWant.dll"
Now that you have a single dll, with .ascx files within it, we swap the CodeFile attribute of all ascx files back to CodeBehind, for intellisense and MSBuild to work properly.
Create a new Web Application Project, delete everything in it, add a reference to your newly created DLL and add a new Default.aspx.
Register the assembly and namesapce on your .aspx site (or in web.conf):
<%# Register Assembly="UserControl" NameSpace="NameSpaceOfWhereYourControlLives" TagPrefix="uc">
Add your between body tags, remember to use the name of the ClassName-attribute defined in the library (first line in .ascx file)
Or a simple cmd file that "does it all" (copies needed DLLs to the Bin, changing back and forth between CodeBehind, CodeFile, Compiling and merging the dll into a new dll):
#ECHO ON
setlocal enabledelayedexpansion
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
::VARIABLES
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
SET project=C:\Solutions\UserControlLibrary
REM Notice that project variable above ends with project name below!
SET projectname=UserControlLibrary
SET projectcompiledfolder=C:\Temp\UserControlLibraryCompiled
SET outputdll=UserControlLibrary.dll
REM Configuration is either release or debug, depending on which "mode" you are building against in Visual studio.
SET projectconfiguration=Release
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
::LOGIC
::--------------------------------------------------------------------------------------------------------
::--------------------------------------------------------------------------------------------------------
call:ReplaceFunction %project% "CodeBehind", "CodeFile"
call:CopyLibraryReference Common, Release, %project%
call:ProjectCompile %projectname%, %project%, %projectcompiledfolder%
call:ProjectMerge %projectcompiledfolder%, %outputdll%, %project%, %projectconfiguration%
call:ReplaceFunction %project% "CodeFile", "CodeBehind"
RMDIR /s /q %projectcompiledfolder%
exit
::---------------------------------------------------------------------------`-----------------------------`
::---------------------------------------------------------------------------`-----------------------------`
::FUNCTIONS
::---------------------------------------------------------------------------`-----------------------------`
::---------------------------------------------------------------------------`-----------------------------`
:CopyLibraryReference <referenceName> <referenceConfiguration> <project>
SET referenceName=%~1
SET referenceConfiguration=%~2
SET project=%~3
REM Solution folder, containing a bunch of Library projects, such as "Common", "ActiveDirectory", "BusinuessLogic" and our UserControlLibrary...
SET lib=C:\Solutions\
COPY /Y "%lib%%referenceName%\bin\%referenceConfiguration%\%referenceName%.dll" "%project%\bin\%referenceName%.dll"
goto:eof
:ProjectCompile <projectname> <project> <projectcompiledfolder>
SET projectname=%~1
SET project=%~2
SET projectcompiledfolder=%~3
REM Path to compiler might vary, also if you want 32 or 64 bit... this might need to change
SET compiler=C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe
"%compiler%" -v %projectname% -p "%project%" "%projectcompiledfolder%"
goto:eof
:ProjectMerge <projectcompiledfolder> <outputdll> <project> <projectconfiguration>
SET projectcompiledfolder=%~1
SET outputdll=%~2
SET project=%~3
SET projectconfiguration=%~4
REM Path to merger might vary, also if you want 32 or 64 bit... this might need to change
SET merger=C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\aspnet_merge.exe
"%merger%" "%projectcompiledfolder%" -o %outputdll%
COPY /Y "%projectcompiledfolder%\bin\%outputdll%" "%project%\bin\%projectconfiguration%\%outputdll%"
goto:eof
:ReplaceFunction <projectFolder> <replaceValue> <replaceWith>
set projectFolder=%~1
REM tempfile name can be anything...
set tempfile=%~1\replaceascxbuildv1.txt
set replaceValue=%~2
set replaceWith=%~3
for /f %%f in ('dir /b /s %projectFolder%\*.ascx') do (
for /f "tokens=1,* delims=ΒΆ" %%A in ( '"type %%f"') do (
SET string=%%A
SET modified=!string:%replaceValue%=%replaceWith%!
echo !modified! >> %tempfile%
)
del %%f
move %tempfile% %%f
)
goto:eof
Add this into a ".cmd" file, then run the cmd file upon Post Build Event. The build is slower than usual (of course), so you do not have to be me, to understand that if you have too many user controls, this adds up. Feel free to create several projects then. :P
Conclusion:
Now I simply hit build in Visual Studio, and everything is automatic, I can finally write some code! If you ever use this yourself, all you need is to figure out your own paths to the files and project of yours, but do note: a path or two is written within the function themselves. ;)
Edit: The list actually starts at 0, but I do see there's two 2's... bug!

Categories

Resources