Propagation of .config settings - c#

We have a fairly hefty VS2008 solution that comprises of many library projects that are referenced by one or more other projects. Some of these libraries define things like WCF bindings and connection strings, but when these are referenced by other projects, it seems to become a necessity to copy the binding settings from the library projects' .config files into the executable projects. It seems like we're missing something here as this approach has started to violate DRY principals in a major way with duplicate settings littered throughout the solution. Changing a binding has become a major exercise in search & replace.
I have looked at the this project on CodePlex as a possible solution, but I wonder if we're misunderstanding the principals behind app/web.config files.
Is there an easier way?

Not really no.
In sufficiently large projects you end up with settings that need to go in several projects.
One solution I've used previously is to have a custom task run on post-build to modify the configs to set a specific variable (say '$generalSettings') with a bunch on common things, from a local file I call 'local.deploy.properties'. I use NAnt to do this.
These days, I use a custom solution I've written to do it (though it combines the approach above anyway, due to the need to test locally).
Anyway, what I'm getting at is this is a generally unsolved problem.

You have to automate settings propagation in order to keep things working properly. This can be done by adding batch copy command in post-build actions. You can find this settings in the project properties menu.
In order to customize copied settings for a specific project the XSLT transform can be used.

Related

Getting a list of all dependencies from a .NET Standard project's csproj

Ever since I've been using the (relatively) new .NET Standard Library project type in Visual Studio, I've been having some problems getting a complete set of DLL files that are required by my project.
The problem is usually limited to 3rd-party libraries which I reference as NuGet packages. I've noticed that these don't get copied to the output folder of my project when I build it. This didn't use to be the case in classic project types.
While I can appreciate the de-cluttering effect that this change has brought for .NET Standard projects, I'm now faced with a problem. I sometimes absolutely need to be able to get the entire list of all files that my project depends on!
I have several different cases, where I might require this list for one reason or another, but the one I believe is most crucial for me, is when I want to gather these files from the csproj itself, right after it's built. In there, I have a custom MSBuild <Target> which should take all the files from the output dir and zip them together for distribution. The problem is, I'm missing all the files that come from NuGet dependencies, because they're not there!
How can I solve this in a general (i.e. not project-specific) way?
UPDATE
There's this deps.json file that contains basically all I'm after and then some. It's just a matter of extracting the relevant information and find the files in the local NuGet cache. But that would involve writing a specialized app and calling it from my target. Before I start writing one myself... Is there something like this already out there somewhere?
I followed this answer and it sort of works.
The suggested thing was to include the following into my csproj:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
My main concern is that it also outputs some other DLLs from the framework (such as System.Memory.dll and System.Buffers.dll, among others), which I didn't expect. But maybe that's a good thing. They do seem to be dependencies, just not direct ones. I'll see how it plays out.
If it turns out ok, my only wish would be that this directive was more prominently displayed in project settings (as a simple checkbox, maybe?) so I wouldn't have to hunt the web to find it.

How is dirs.proj used?

I'm afraid I may be asking a really dumb question, but I can't seem to find anything that makes this clear. I usually work on smaller applications but am now working on a larger one with several assemblies in a baseline framework and several assemblies for a product line domain (with more to come). I would like to manage the build by configuring MSBuild. I've done a lot of online research (specifically with several MSDN articles I found) and now feel knowledgeable enough to be dangerous.
I understand that in csharp the *.csproj file can be unloaded and modified with properties, items, and targets to control the build process. I also understand that I can import my own targets file to help separate and organize. In this link though (https://msdn.microsoft.com/en-us/magazine/dd483291.aspx) a multilevel project build is organized with node-level dirs.proj files. This is confusing to me and has raised several questions I can't seem to find an answer to:
What is the difference in a *.proj and *.csproj file?
Can a *.proj be setup in VS to load on Build with F6 or does using this require use of the command prompt only? (i.e. "msbuild dirs.proj /t:Build").
Does dirs.proj load automatically? If so, my study-by is not working correctly, yet it does with command prompt.
Or am I overlooking something all the way around with "dirs.proj" Maybe it's just a substitue name for one of the project *.csproj files? If that was the case though there wouldn't have been a need for the root node's dirs.proj which from what I can tell doesn't have an actual project associated to it.
Anyways, I've seen dirs.proj mentioned in several forums regarding issues, but no where can I find how it's loaded or used in VS (outside of manual command prompt building which seems unreasonable if this is used to organize the build but the build won't really take a huge amount of time). I'm hoping someone can help me achieve that a-ha moment with this.
Thanks in advance.
Dirs.proj is an MSBuild convention typically used when dealing with very large source trees (> than 20 projects). I've worked with Microsoft engineers at a previous company and the dirs.proj convention appears to be one that Microsoft developed and uses internally to manage very large source trees.
A very good implementation reference for this is the Python Tools for Visual Studio project on CodePlex GitHub.
The link you shared by Sayed Ibrahim Sashimi is a very good explanation of the reasoning behind the msbuild paradigm, but it doesn't do a very good job of showing a practical example of how it works. The Python Tools project is an outstanding reference for this.
The idea behind using this paradigm is simple. I'd wager a guess that most .NET software engineers work on somewhat limited-scale projects that don't deal with more than 5-10 projects at a time, and they manage these projects in Visual Studio via Solution (.sln) files. They may even instruct their build system to run builds on the .sln. This works fine until you start thinking about scaling your product into or combining it with something larger, such as a platform with many, many projects. Solution files are not MSBuild files and as such they are not extensible like MSBuild is and they suffer massive performance penalties when dealing with large numbers of projects.
From an MSBuild perspective, dirs.proj stands in for Visual Studio .sln files. The difference, however, is that dirs.proj don't just include .csproj (and the like) as .sln do, rather, they can include source subtrees (e.g. other nested dirs.proj). So, building the root dirs.proj can result in the entire source tree being built, or building a nested dirs.proj will result in that subtree being built.
Therefore, the paradigm encourages you to look at your source as a series of interdependent nodes organized into features or product areas. That way, engineers can work on different source subtrees in very large projects without having to deal with the entire source tree, as you would have to with a VS solution.
Using this paradigm also carries certain benefits that don't come with .sln files. For example, if one project references a project from another, separate subtree, msbuild will build that reference first, automatically. Additionally, your source nodes can carry their own build settings, allowing them to be built dynamically using different build settings based on build scenario. For example, under one scenario a SharePoint source subtree needs WSP packaging, a C# subtree needs to be built without .pdb, a DB subtree needs to generate dacpacs, and the entire source tree needs to sign their assemblies using myCorp.snk and set build output to the $(buildRoot)\Output directory.
dirs.proj aren't opened via visual studio - they're built on the command line using msbuild. The only pain point is that the files have to be hand-curated.
So, long answer short take a look at the Python Tools project and see how they're using dirs.proj. Note how the entire source tree has common settings managed by Common.Build.settings, and how msbuild properties in this .settings file are used in the various .csproj files.

What is the best way to publish multiple versions of the same ClickOnce application?

I have a c# ClickOnce application that I need to be able to publish multiple times for OEM purposes.
The way I understand it now is that publish settings are located in the .csproj file.
However, this is inconvenient in the case where I want to publish multiple versions.
for example, Company A needs totally different icons, start menu location, product name etc. from Company B, but the assemblies need not be renamed.
Here are a couple approaches/questions that I can think of to solve this issue...
1.Is there a way to create a separate publish settings file to use during build time?
2.Can I edit specific publish settings (like Start Menu location, etc) at build time with MSBuild.exe? I think this would be ideal...
e.g.
MSBuild.exe project.sln /target:Publish /property:edit-project-publish-settings-here
3.Maybe create a 2nd .csproj file? (Would prefer not to do this...)
Please share your thoughts as to the best approach, or any other clever ways to make this happen. Thanks!
I wish I could give you some brilliant solution, but personally I would probably go with option 3.
I mean, its pretty simple, the changes should be pretty static and it will be difficult(ish) to totally screw it up and deploy the wrong changes to the wrong company.
If you copy the .csproj in your project folder, it will reference all of the same source files and you can just change the executable name. Create another VS solution and you can reference the copied .csproj and get rid of your first one so that you can publish two separate versions.
This isn't ideal for ClickOnce however.
If you use a Singleton object that specifies the "mode" (Company A, B, C, etc.) you can easily store that in the app.config (or another xml file). Then just re-publish your ClickOnce Application but copy the correct version of your configuration file in so it gets shipped with the build. This way, you don't need any additional csprojects Just include all of your icons and set them at run-time on App Start based on your Singleton object.
I found that you are able to edit certain properties using MSBuild.exe like this
MSBuild Solution.sln /target:publish /property:ProductName=ProductA\;Publisher=CompanyA\;ApplicationIcon=companyA.ico
I found another useful post on modifying.csproj files programatically with .NET code. (This would only be needed if you're modifying things that are deeper than just the project properties specified in the ClickOnce documentation below)
The MSBuild documentation here was also useful -- especially under Publishing Properties

Whats a good approach for white labeling dll

Whats a good approach for white labeling dll and exe with visual studio?
In essence we want to be able to have the name of the dll and exe change based on the client that we are packaging the solution for, e.g.:
Instead of myCompany.exe and myCompany.db.dll, I would like yourComany.exe and yourComany.db.dll or acme.exe and acme.db.dll, etc
Edit:
Currently we are using a straight visual studio build process with a wix project to create an msi.
If the only justification for rebuilding it is to change the name, can you just use something generic in the first place? Imagine having to patch 50 identical DLLs, and build/deploying each one separately because they all must be named different things. Even if it's only for a few clients, I would hate to have to maintain that. Versioning could be a hassle too.
If you must do it, I would probably go with a build task (which can perform fairly advanced operations). You mention that you are "packaged the solution"; the viability of a build task would depend on how it is being packaged.
In response to your comment about naming the EXEs with client-specific names... My obvious suggestion there would be to have those applications contain as little code as possible.
The simplest build integration I can think of would be to create a post-build task which ran upon successful compilation in release mode. The task could then read a config file which defined the unique names, and copy the successfully built EXEs to an output directory.
Some of the operations can be accomplished just from the task config file: http://msdn.microsoft.com/en-us/library/ms171466.
Alternatively, you might want to create a little application to do all the work for you, and just pass config switches to it.
For example, here is a little post-build command that I execute to minify my JavaScript/CSS upon successful build of a web application. The concept is similar:
build
execute an app (like msbuild.exe, or your custom build app)
pass data to the executable (like paths, switches, etc.)
executable writes the files out
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe
"$(ProjectDir)Properties\build\minify.xml"
/p:SourceLocation="$(ProjectDir)client"
/p:CssOutputFile="$(ProjectDir)client\final\final-full.css"
/p:JavaScriptOutputDirectory="$(ProjectDir)client\final"
You could use ILMerge in whatever post-build process you want on all your outputted assemblies (dll and exe), to create one-off customer-branded builds.
ilmerge /out:CustomerName.exe internalName.dll internalName.exe
I don't know that there is a good way to do this without actually building the project as XYZ company. You could try something like this which will give you the desired result BUT it will change the physical name of the assembly as well which may cause dependency problems.

Which visual studio solution type is right for me?

I currently have a program that i wrote that is divided up into 3 separate solutions.
Front end (all display related stuff)
Parsers (multiple (39) projects that each create a dll to parse specific data)
Globals (multiple (5) projects that each create a dll that is used by projects in the parsers solution, and by the front end).
Requirements -
Both the Front end and Parsers require the globals dlls to exist at compile time, and used at run time.
The Parsers dlls are loaded at run time using assembly.LoadReference.
Development is: C:\projects\myProg
deployed location is: C:\myProg
My problem is that I have been going back and forth with issues dealing with project dependencies, where to point to for my globals dlls. Do I point to the deployed location or the developement location, and if so, release or debug?
So I started looking up the different solution types, and I'm wondering if I should set up a partitioned solution, or a multi-solution for my particular situation.
Add all the projects to a single solution.
Change any references between projects into "project references" rather than direct references to dll files. This will fix a lot of dependency issues.
If you have any "library" files that are not changed often, then you can optionally move them into a separate solution. The output of this should be "prebuilt" release dlls that you can then reference from a standard location in your main solution (the best way to do this is to add a post build step that copies the output to your development "library binaries" folder. That way, the build process is not changed, you simply add an extra step to get the files where you need them, and you remain in full control of the build process). This works well, but is a pain if you need to change these prebuilt dlls often, so it's best only used for fairly static parts of your codebase.
Finally, consider merging many of your projects into a single project/assembly. The killer on build times is not the amount of code, it's the number of assemblies - on my PC every project adds a pretty constant 3 seconds to the build time, so by merging small projects I've saved quite a bit of build time.
Since those 3 are all part of the same system, it will probably be easier to have a single Solution with each Project added to it.
NOTE: You do not need to move anything from their current locations.
Just create a new empty solution and do a right-click Add > Existing Project... for each project you want to be a included, they will remain where they are on disk, but will be opened together.
The current ("old") solutions will be available as well, just as they are.
Also keep in mind that if you are editing the same project in two instances of VS at the same time, it will bug you about reloading the source code when a change is made and saved.
Most importantly, having the projects in the same solution will allow you to add references between them, rather than the DLL files.
why are they scattered into separate projects, Combine the Parses and globals into a single assembly. keep the UI assembly separate and as simple/small as possible.
Let's say you have a good reason for having so many projects (example: different amount of parsers available for different licenses of a product).
Managing dependencies in visual studio is made easy:
Right click your solution node
Select "Project Build Order..."
Make sure that every project does not need a project beneath it in that dialog.
About "where to deploy": visual studio does it well by default. If you're in debug, it will output to the debug folder of your solution, likewise for release.
HTH.

Categories

Resources