How can I perform 'find and replace' on references? - c#

Our solution has several (10+) C# projects. Each has a reference to the CAB extension library, with the reference pointing to the DLLs in the library's release folders. Each project has between four and seven such references.
We'd like to make some changes to the library; but to debug the changes, we'll need to build a debug version of the library and refer to that. I'd like to add the library's projects to our solution and change each of the DLL references to a project reference.
Is it possible to perform a 'find and replace' on the existing references, or will I have to do it by hand?

There isn't such a feature in the VS IDE.
However, as a .csproj file is just an XML document it is possible to do such a global search and replace in a scripted fashion e.g. by changing one file to observe the before and after states then running sed over the remainder.
For a one-off, going to the extent of writing a script to load the XML and making the substitutions by DOM manipulation is probably overkill.

Take a look at Jared's answer to this SO thread. That approach will likely work for you.

If you download CI Factory, it just so happens that there is a nant function in there called FixUpThirdPartyRefs which you could use or tweak to help you do this. So you could just setup nant and use that function.
It is part of the power tools with CI Factory: http://www.cifactory.org/joomla/index.php?option=com_content&task=view&id=29&Itemid=41

Why don't you just replace DLLs in library's release folder with debug version temporary ? I assume that you have local development environment.
EDIT:
You could:
1. develop all time with debug version of library
2. make updating references in *.csproj more flexible
3. make file system location of library files more flexible
On point 3: If the path to your library dlls contains "release" and if debug and release library folder structure is the same than change from release could be made by just renaming folder "release" to "release.original" and "debug" to "release".
I would probably choose option 1 and all time develop with debug assemblies. Release build would use just for final testing and deploy to customer. Debug and release dlls are not that different.

Related

.Net core 6: How to have output directory without assemblies

I am porting company products in .Net core 6 from .Net 4.8.
In the solution, there is an output directory containing:
Assemblies, Configuration, Log, Resources directories and only .exe, .pdb and .exe.config of the launcher project.
Dlls are in Assemblies directory and I absolutely need to replicate the same structure.
In launcher project .csproj file we have set:
<OutputPath>$(SolutionDir)\$(Configuration)</OutputPath>
In others:
<OutputPath>$(SolutionDir)\$(Configuration)\Assemblies</OutputPath>
During compilation, VS Studio Professional 2022 continues to copy .dlls/.pdbs of the ProjectReference included projects and recursively it copies all the .dlls more and less.
In order to avoid this behavior, I have tried a lot of methods, such as using all these properties (also in different setting combinations: none, all, compile...) but the issue still happens:
<CopyLocalLockFileAssemblies>
<CopyLocal>
<CopyLocalSatelliteAssemblies>
<IncludeAssets>
<ExcludeAssets>
<PrivateAssets>
<AppendTargetFrameworkToOutputPath>
At the moment, I am building in windows but in the future there will also be some linux machines that have to build solutions, so I need a method that should work in all environments.
Is it possible to do it?
Loading of assemblies is not a problem, I have modified AssemblyLoadContext.Default.Resolving and if I manually delete dlls from the output directory, the application works but I need something more "elegant" than a delete script after building (Post-build event).
When you mention "a delete script after building", was that implying one called using a Post-build event? I realize this is probably not exactly what you had in mind, as it will in effect be a script that is called after each time a project is built.
Still, it's not exactly the same as running a script manually, so if you are having trouble finding better options, this may be an alternative?
Open Properties for your project, and look for this:
(You may also want to have a look at the documentation for build evens)

create .exe from c# windows application

I have a created a visual studio 2010 project that creates a windows form - it references numerous other dll's.
How can I wrap this up in to a single .exe file?
ILMerge is what you are looking for with the /t:exe option.
A sample call would look like this:
ilmerge.exe exefile.exe [dlls-to-internalize.dll ..] /out:exefile-out.exe /t:exe
A sample usage of using ILMerge to pack up multiple dlls into one and internalizing them can be found here: dotlesscss buildfile
More info on using ILMerge can be found on the ILMerge Website.
You can also get it through NuGet via Chocolatey
It allows you to pack multiple .NET assemblies into one file by rewriting the references.
You can also internalize your dependencies in case you are supplying a library to someone and don't want to cause dependency conflicts with libraries you are internally using.
As posted ILMerge is one option, another is "SmartAssembly" from RedGate etc.
What all these DO NOT do is internalizing native DLLs - that's a limitation in the Windows API... so any dependency which is a native DLL has to be shipped along with the EXE.
1. Select Configuration Manager and check parameter such as debug/release or x86/new.
2.Select Release instead of debug from drop down menu near debug button(Visual studio framework).
3. Click on build and then build yourApplicationName.
4. Goto Your program folder->bin->release->yourApplicationName.exe.
5. yourApplicationName.exe is ready to use.
Thanks
Go to Your Application->bin->dubug->yourapplicationname.exe
It is automatically generated but exe from release folder is more faster than the debug due to less information of debug.

Nant: How to structure svn:externals for building class libraries that reference 3rd party dll's

I'm using subversion and nant (and visual studio IDE)
I've been following the suggested project structure at http://blog.jpboodhoo.com/NAntStarterSeries.aspx which advocates self contained subversion directories where a developer can do a checkout and immediately build a project in a single step.
My repo structure is like:
/Repo
/MainProject
/trunk
/doc <-- documentation
/lib <-- binary-only DLLs
/src <-- source code for MainProject
/tools <-- holds tools like nant, nunit, etc
...
/ClassLibrary1
/trunk
/doc
/lib
/src
/tools
...
/ClassLibrary2
/trunk
/doc
/lib
/src
/tools
What's not clear is how to structure a project that has class libraries which in turn reference third party library dll's themselves.
Currently, I have a main project with a working directory like
Example:
/MainProject
/build
/lib
/src
/MainProject
/ClassLibrary1 <-- svn external to svn://server/repo/ClassLibrary1/trunk/src
/ClassLibrary2 <-- svn external to svn://server/repo/ClassLibrary2/trunk/src
/tools
...
When building MainProject, I compile the class libraries and output the dll's to the build folder. However, the class libraries themselves have 3rd party binary-only DLL's that they reference.
My questions is in order to build the MainProject I have to somehow get the 3rd party DLL's from the class libraries into the build output. How do I do that?
Thoughts:
1. Should I store copies of these 3rd party dlls in the MainProject's lib folder?
2. Or should my svn:external reference be to the trunk of the class library project rather than the src so that I can access the class library's lib folder?
3. Should I use the subversion 1.6 feature of svn:externals to individual files?
Personally I bring in the trunk of the referenced libraries.
(Actually, I bring in the root of a tag, but that's beside the point).
If you keep a separate copy of the required dll's, then you're not really allowing the referenced library to determine what it needs for itself because all that logic is duplicated in the project. The same thing happens if you use multiple externals references or file externals to bring in the code and the dll's.
My principle here is that - the library knows what it needs, a single external reference to the library can get that library and everything it needs.
That way if you change the library's references, you can be confident that any and all projects will just pick that up. (if the IDE doesn't support this, that's the IDE's problem, not subverion's). You can also be confident as a project that if you change the version of the library you're pointing to, you'll automatically get the right references as well, and don't need to go debugging build failures to work out what's gone wrong.
Should I store copies of these 3rd party dlls in the MainProject's lib folder? I prefer to store any external libraries in a binaries directory under trunk but next to source...or call it references, dependencies, etc. This then allows any developer to get latest and all that is needed will come down. It doesn't need to be part of the project per se. It just needs to be accessible when the build is performed.
Or should my svn:external reference be to the trunk of the class library project rather than the src so that I can access the class library's lib folder? I don't prefer this approach as it makes the process of getting a new developer up and running more convoluted. I think an assembly can go into its own repository when it has a level of importance on to itself. But I would never reference its output. It should have a build process wrapped around it that promotes a mechanism to "deploy" the output to the above references or dependencies directory. However automating the deployment like that might be fraught with issues. It would be better if the assembly had its own process around it. And when a new version of the assembly were released it would be manually embraced by a developer on the project that needed it. They could then test it, accept it, and place it into their build process. Obviously if that assembly changes on a daily basis some automation may be required.
Should I use the subversion 1.6 feature of svn:externals to individual files? No. I prefer to keep a project/solution as a self contained entity. Having tenticals spread out all of the place makes dependencies more painful. Keep silos as hard as possible...bring new things in as manual as possible...or as manual as the frequency that things change will allow.
I had a similar need and found a short-and-sweet answer in TortoiseSVN's documentation :
http://tortoisesvn.net/docs/nightly/TortoiseSVN_en/tsvn-howto-common-projects.html

Optimizing Visual Studio solution build - where to put DLL files?

I found out that build time of C# solution with many projects gets much faster if you don't have "copy local" enabled everywhere. I did some tests and it seems that (for our solution at least) we could increase build time by factor 2-3 just by removing "Copy local". This probably means we have to store libraries in some common directory.
Any suggestion/best practices how to acheive this? Note that I would like to keep references to projects, not to DLLs.
We retarget the output directory of projects to be ../../Debug (or ../../Release)
Our libs are placed in these directories as well.
We set the reference paths in each project to be the Debug or Release directory accordingly (this setting is persisted in the user files since it is an absolute rather than relative reference)
We keep project references as project references, All dll references have copy local false and specific version false unless they are system level dlls we know will be in the GAC on all deployed machines.
This works a treat and manual builds in the IDE mimic scripted builds from the command line (using MSBuild)
Test projects not for deployment do not direct their output to the centralized Debug|Release directory, they just use the standard default location (and do use copy local to avoid issues with locking)
The library versions may be changed by the automated build process replacing the dlls in the Debug and Release directories.
I recommend building to ..\..\Build if your application is spread across solutions. (If you only have one solution, you may consider ..\Build.) Visual studio will, by default, pick up reference files in it's output folder. When building without VS using MSBuild, though, you must add the build folder as a reference path as shown in the example below:
<Target Name="BuildApp">
<MSBuild
Projects="#(ProjectReference)"
Targets="Rebuild"
Properties="ReferencePath=..\..\Build;$(LibraryFolder)" >
</MSBuild>
<OnError ExecuteTargets="BuildFailed" />
</Target>
The example also takes me to my second argument. I do not think you should use your build folder as library folder, since this may lead to individual projects erroneously overwriting library assemblies e.g. by using Copy Local. You should have strict control over your library versions, so I suggest you keep this separated. (Developers would need to add this path in VS as a reference path.)
You may also choose to separate ..\..\Build into ..\..\Release and ..\..\Debug as suggested by ShuggyCoUk.
I like the top level Bin Lib folder setup that is common in Unix based systems, by the way moving to this type of system will also make your release engineer's life a lot easier as well. Installer Creation is much simplified by only having to pull everyhting out of one folder. Dll's would then go in bin..

ILMerge Best Practices

Do you use ILMerge? Do you use ILMerge to merge multiple assemblies to ease deployment of dll's? Have you found problems with deployment/versioning in production after ILMerging assemblies together?
I'm looking for some advice in regards to using ILMerge to reduce deployment friction, if that is even possible.
I use ILMerge for almost all of my different applications. I have it integrated right into the release build process so what I end up with is one exe per application with no extra dll's.
You can't ILMerge any C++ assemblies that have native code.
You also can't ILMerge any assemblies that contain XAML for WPF (at least I haven't had any success with that). It complains at runtime that the resources cannot be located.
I did write a wrapper executable for ILMerge where I pass in the startup exe name for the project I want to merge, and an output exe name, and then it reflects the dependent assemblies and calls ILMerge with the appropriate command line parameters. It is much easier now when I add new assemblies to the project, I don't have to remember to update the build script.
Introduction
This post shows how to replace all .exe + .dll files with a single combined .exe. It also keeps the debugging .pdb file intact.
For Console Apps
Here is the basic Post Build String for Visual Studio 2010 SP1, using .NET 4.0. I am building a console .exe with all of the sub-.dll files included in it.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
Basic hints
The output is a file "AssemblyName.all.exe" which combines all sub-dlls into one .exe.
Notice the ILMerge\ directory. You need to either copy the ILMerge utility into your solution directory (so you can distribute the source without having to worry about documenting the install of ILMerge), or change the this path to point to where ILMerge.exe resides.
Advanced hints
If you have problems with it not working, turn on Output, and select Show output from: Build. Check the exact command that Visual Studio actually generated, and check for errors.
Sample Build Script
This script replaces all .exe + .dll files with a single combined .exe. It also keeps the debugging .pdb file intact.
To use, paste this into your Post Build step, under the Build Events tab in a C# project, and make sure you adjust the path in the first line to point to ILMerge.exe:
rem Create a single .exe that combines the root .exe and all subassemblies.
"$(SolutionDir)ILMerge\ILMerge.exe" /out:"$(TargetDir)$(TargetName).all.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" /target:exe /targetplatform:v4,C:\Windows\Microsoft.NET\Framework64\v4.0.30319 /wildcards
rem Remove all subassemblies.
del *.dll
rem Remove all .pdb files (except the new, combined pdb we just created).
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).all.pdb.temp"
del *.pdb
ren "$(TargetDir)$(TargetName).all.pdb.temp" "$(TargetName).all.pdb"
rem Delete the original, non-combined .exe.
del "$(TargetDir)$(TargetName).exe"
rem Rename the combined .exe and .pdb to the original project name we started with.
ren "$(TargetDir)$(TargetName).all.pdb" "$(TargetName).pdb"
ren "$(TargetDir)$(TargetName).all.exe" "$(TargetName).exe"
exit 0
We use ILMerge on the Microsoft application blocks - instead of 12 seperate DLL files, we have a single file that we can upload to our client areas, plus the file system structure is alot neater.
After merging the files, I had to edit the visual studio project list, remove the 12 seperate assmeblies and add the single file as a reference, otherwise it would complain that it couldnt find the specific assembly. Im not too sure how this would work on post deployment though, could be worth giving it a try.
I know this is an old question, but we not only use ILMerge to reduce the number of dependencies but also to internalise the "internal" dependencies (eg automapper, restsharp, etc) that are used by the utility. This means they are completely abstracted away, and the project using the merged utility doesn't need to know about them. This again reduces the required references in the project, and allows it to use / update its own version of the same external library if required.
We use ILMerge on quite a few projects. The Web Service Software Factory, for example produces something like 8 assemblies as its output. We merge all of those DLLs into a single DLL so that the service host will only have to reference one DLL.
It makes life somewhat easier, but it's not a big deal either.
We had the same problem with combining WPF dependencies .... ILMerge doesn't appear to deal with these. Costura.Fody worked perfectly for us however and took about 5 minutes to get going... a very good experience.
Just install with Nuget (selecting the correct default project in the Package Manager Console). It introduces itself into the target project and the default settings worked immediately for us.
It merges the all DLLs marked "Copy Local" = true and produces a merged .EXE (alongside the standard output), which is nicely compressed in size (much less than the total output size).
The license is MIT as so you can modify/distribute as required.
https://github.com/Fody/Costura/
Note that for windows GUI programs (eg WinForms) you'll want to use the /target:winexe switch. The /target:exe switch creates a merged console application.
I'm just starting out using ILMerge as part of my CI build to combine a lot of finely grained WCF contracts into a single library. It works very well, however the new merged lib can't easily co-exist with its component libraries, or other libs that depend on those component libraries.
If, in a new project, you reference both your ILMerged lib and also a legacy library that depends on one of the inputs you gave to ILMerge, you'll find that you can't pass any type from the ILMerged lib to any method in the legacy library without doing some sort of type mapping (e.g. automapper or manual mapping). This is because once everything's compiled, the types are effectively qualified with an assembly name.
The names will also collide but you can fix that using extern alias.
My advice would be to avoid including in your merged assembly any publicly available lib that your merged assembly exposes (e.g. via a return type, method/constructor parameter, field, property, generic...) unless you know for sure that the user of your merged assembly does not and will never depend on the free-standing version of the same library.
We ran into problems when merging DLLs that have resources in the same namespace. In the merging process one of the resource namespaces was renamed and thus the resources couldn't be located. Maybe we're just doing something wrong there, still investigating the issue.
We just started using ILMerge in our solutions that are redistributed and used in our other projects and so far so good. Everything seems to work okay. We even obfuscated the packaged assembly directly.
We are considering doing the same with the MS Enterprise Library assemblies.
The only real issue I see with it is versioning of individual assemblies from the package.
I recently had issue where I had ilmerged assembly in the assembly i had some classes these were being called via reflection in Umbraco opensource CMS.
The information to make the call via reflection was taken from db table that had assembly name and namespace of class that implemented and interface. The issue was that the reflection call would fail when dll was il merged however if dll was separate it all worked fine. I think issue may be similar to the one longeasy is having?
It seems to me like the #1 ILMerge Best Practice is Don't Use ILMerge. Instead, use SmartAssembly. One reason for this is that the #2 ILMerge Best Practice is to always run PEVerify after you do an ILMerge, because ILMerge does not guarantee it will correctly merge assemblies into a valid executable.
Other ILMerge disadvantages:
when merging, it strips XML Comments (if I cared about this, I would use an obfuscation tool)
it doesn't correctly handle creating a corresponding .pdb file
Another tool worth paying attention to is Mono.Cecil and the Mono.Linker [2] tool.
[2]: http:// www.mono-project.com/Linker

Categories