My SAAS company has two C#.NET products, call them Application Alpha and Application Beta. Both of them reference some libraries that we can call Core.
At the moment, the codebase is monolithic, stored in a single SVN repository with a single .NET solution, and we're trying to make it more modular/componentized. We've split off into separate repositories for the two applications and the core library, but we're now running into the following problem:
Alpha and Beta must reference Core, but we're trying to avoid having a direct code reference because then we're practically back to square one: you would need to check out and co-locate all repositories. So how should we go about referencing assemblies between these components?
Each component could have a directory containing DLLs from the other components that need to be referenced, stored in SVN, but this would mean extra effort any time Core is updated to push out the new DLLs to Alpha and Beta.
Or we could store the DLLs in a central SVN'd location (and/or in the GAC), but that would mean extra effort any time Core is updated for everyone else to pull the new DLLs.
Is there a third option that we're overlooking?
I have something similar in which I have 5 applications utilizing a series of web controls I built. The controls are compiled into a series of DLLs for modularization and the applications that utilize them live on separate servers.
What I do is utilize VS2008's build utility to execute a batch file that copys the compiled (updated) DLLs to the production servers when a Release Build executes.
You do this by going to the project that builds into the DLL (or DLLs) and right click on that project and goto Properties. Then you goto the BUILD EVENTS tab. There you see Pre-Compile command line and Post-Compile command line textboxes.
Therefore your release builds can be fully automated and you never have to worry about DLL hell-like differences between versions of your production DLLs.
Hope this helps,
JP
you could have your rebuild script for Alpha and betat create artifacts (namely build core) and place the result of the core build at a specific location referencing that location.
You could use SVN:externals. It was designed for this type of scenario.
If you want to avoid that, these are probably your better options. I'd avoid putting the files in the GAC, though, unless your core project is very stable, and not changing very often. Having the DLLs local provides much more flexibility.
Each component could have a directory containing DLLs from the other components that need to be referenced, stored in SVN, but this would mean extra effort any time Core is updated to push out the new DLLs to Alpha and Beta.
This could be handled fairly easily with a good build system. This approach has some disadvantages (ie: exectuable depdenencies in the build system), but has some advantages, including allowing each dependent project to have different versions as needed, etc.
Related
After searching quite a bit, I seem to be unable to find an answer to my problem. Usually, I find that means it is a non existent or incorrect approach, but I think it worth it to have an answer floating around on the internet nonetheless.
Essentially, we have 4 applications referencing 5 different "source" projects. So the scenario is, when we add a 5th application (for example), we will need to create project references to the other 5 different projects, as the application requires their output.
Its not a difficult task because the amount of projects is small, but it got us thinking. What if you could create a single project, maybe called Libs or something, reference all 5 projects in that project, and then the applications must only reference Libs. The idea seems cool, but I don't know if it will work because when you create a project reference, it points to Libs single output libs.dll.
So to actually ask a question, is this possible, and if so, how can it be done? Currently, having Libs reference the other "source" projects, and then having the applications reference the Lib project does not work, as it says there are missing assemblies.
And just to go over how this was created. The 5 source projects reside in a couple different solutions, so the only tedious part of this approach is "add existing project" at the initial start of the application's solution.
The way we manage this kind of thing in my organisation is to make a NuGet package for each of these shared "source" projects (e.g. in our case we have an error logging library, an XML utils library, a bespoke HTTP client, and others). These are published to our private NuGet feed URL (hosted on Azure DevOps, but you can just use a standard Windows fileshare if necessary) for our developers to use in their applications.
This has some clear advantages over your approach:
1) Dependencies - this seems most relevant to your question. If the project you built the NuGet package from itself depends on any other NuGet packages (either publicly available ones, or others from our private feed) then when someone installs that package in their project it will automatically install all the other packages it depends on.
So in your case you could create a shell "libs" package which doesn't deliver any content itself, but has dependencies on all your other packages, causing them to be installed automatically. In our case we have several cases of dependency (e.g. a "base" error logging package which is relied on by error handling modules which are tailored to different app types, e.g. MVC, Web API, Windows Services), and it works very well.
2) Updates and maintenance. In your scenario if you make a breaking change to one of your "source" projects, then, because you have a direct project reference declared in Visual Studio, any project which references the source one will have to make related changes to cope with the updates to the source project, before you can re-compile it and do whatever feature changes you're trying to achieve. This could be a pain, and be an untimely problem, especially in the case of major updates. However if instead you install a NuGet package containing that functionality, the developer of the application can choose if and when to install an updated version of the package.
There are other minor benefits as well which I won't go into, but there are some very good reasons why almost all major programming languages now provide similar "package" and "feed" functionality as a way of managing dependency on external projects and libraries. Your approach is, I feel, outdated and naive, resulting in the issue you've described and the potential for other irritations as well.
I have about 10-15 projects with separate solutions that reference 3rd party DLL's in a microsoft .NET shop. One of the problems that we want to address is consistency of the versions of the DLL's used across projects (E.G. Netwonsoft 8.0.3 in all projects as opposed to separate versions depending when the project was created).
I have seen this done in two separate ways in my previous positions and was wondering if there are any other options to solve this problem.
I have used a corporate NuGet for all third party DLL's referenced within a solution for any project within the company. The DLL's would be updated and then made available to the developers in the projects to pull down and upgrade (if needed) within the solutions on their own.
Another company had an assemblies folder in source that housed all "approved" third party DLL's and all references lived within this directory.
I did see this question but it only offered one of the two solutions above: Where should you store 3rd party assemblies?
Are there other options aside from the ones listed above?
Whenever possible use NuGet. Primary reason being that Git doesn't very much handle large binaries well and using LFS for this doesn't make much sense, since there is a valid alternative. TFVC has fewer issues with large binaries, but I'd keep future migration to Git in mind if you're on TFVC.
Keep in mind that not just NuGet, but likely also npm and other package sources are of interest in this case.
If you want to enforce a certain version being used, create a custom task that you hook into the CI pipeline. That way you can easily give off warnings or setup some kind of policy. The custom task could take the packages.config file, scan the referenced packages and then query the TFS/VSTS package management feed to see if it's using the latest version (or the is using the latest minor version)... (or is using at least x versions back)... or fetches the approved versions from a json file or xml file from somewhere and validates against that...
In your source control, Commit and Push to Master with the desired dependency DLLs when the repository is first populated. Since all users, even on other branches, will then be pulling from the repository, you're ensuring they receive all the DLLs they need. This only becomes a problem if you're referring to DLLs in the GAC, which is resolved either by GACUtil or just making sure everyone is using the same Windows version.
POSSIBLY POINTLESS BACKSTORY
In an effort to get out of NuGet hell (formerly dependency hell) my team has decided to switch to considerably larger solutions focused on our major divisions in the company. In the past we would have a core DLL that contained the most common code for a particular system and multiple solutions that pulled that DLL in through NuGet. This resulted in a lot of packages, and even more solutions, which ultimately meant a highly fractured collection of code for each division.
Our new approach is to move towards using a large comprehensive core library that gets exposed through a Web API. We also plan to serve up the core DLL through a NuGet package for situations where Web API performance is not suitable.
A basic solution will have 3 projects: Core, API, and Wrapper. The Wrapper project provides methods for accessing the API through simple methods rather than re-writing all the Web API calls in our apps that will use it. More complex solutions will have additional projects such as Windows services and console apps to run as scheduled tasks.
The 3 basic projects will all share the same version number because they're tightly coupled. The problem arises when including other projects that should not use the same version number in their builds.
THE REAL QUESTION
I have a solution with 4 projects: A, B, C, and D, A-C are always updated together and share the same version number. D is a service project that has its own logic in it that can change independently of the other projects, and therefore should have its own version numbering. However, to avoid confusion, D should be deployed with the correctly versioned DLLs from A-C. (Meaning that if D is on 2.0.0, and A-C are 1.0.0, the DLLs from A-C in the install directory should show 1.0.0 in their details.)
With that in mind, is there a way in TeamCity to build and control the version numbering so that the projects that need to be unique can be, and still reference the correct dependencies?
Notes:
I know that the easiest solution is to simply move the special projects to their own solutions and reference the core DLL, but that's part of what we're trying to get away from.
We want to be able to have proper build numbers on our finished files, as well as have tags in Git from successful builds.
As far as I can tell, the AssemblyInfo Patcher feature in TeamCity can only overwrite the whole version. If it could simply overwrite the build number then I could control version numbers right in my source code.
Well you are right AssemblyInfo Patcher won't help in this case, as it updates all assemblyinfo files or global assembly info file. There is no straight forward way I am afraid but I think you could try something like below:
Rather than building the solution, build individual projects using .csproj files, i.e. break compilation into 4 steps one for each project (A-D).
Use AssemblyInfo patcher for A-C projects so they can simply use Teamcity version %build.number%.
Add a pre-build event to D csproj to update its assemblyinfo information. You'll need to define a variable in teamcity for first 3 bits of its version say DVersion(1.0.0), the last part of it can come from %build.counter% variable. Pass this version (%DVersion%.%build.counter%) as a parameter to D csproj file build step.
Finally update teamcity build number by writing logs to something like ##teamcity[buildNumber '%build.number%-%DVersion%']
Is it good practice to bundle all required managed dlls as embedded resources to a .NET library project in order to ship just one dll?
Background:
I have created an API as a .NET dll (in C#), and it's working all fine. But the library has quite some dependencies on other managed libraries (around 15 dlls) so I need to distribute those as well.
When the users of my API have created an application they again have to make sure to distribute all those dlls along with the application. To me it would seem better if they had just one dll to consider.
The main downside I can see to using embedded dlls is that they must be unpacked to a temporary folder before being loaded dynamically, which may or may not have performance and robustness issues.
There are a lot of questions around this. What happens if you're expecting to load a platform-specific dependency (i.e. x86 vs. x64), or that's true about the app consuming your API? Does that mean that you need to include specific x86 vs x64 assemblies in your package as well? It becomes hairy quickly.
You should consider using ClickOnce deployment for these types of scenarios. Then, all of the dependencies would be packaged together.
Realistically, it's a problem for the API consumer to solve, not for the API producer. Your API might be less popular if it has a lot of external dependencies, but you'll have to make decisions there about what's really crucial to your API's success.
I have a requirement to package up and release a .NET control library across multiple platforms and have a question on how to automate this deployment (or make as efficient as possible) through build scripts and VS2010 configurations.
The control library is to be released as a Silverlight version (separate builds for SL 3.0, 4.0, 5.0) and WPF version (separate builds for .NET3.5 / .NET4.0). I also need to specify release and trial versions of the same libraries. Trial versions will be differentiated in code with a preprocessor statement TRIAL. Both the trial and full version will be compiled in RELEASE mode.
I'm wondering how to achieve this in the most efficient way possible. My VS2010 solution currently has one project for WPF (.NET 4.0) and one separate project for SL (SL 4.0).
Do I need to create further csproj projects for the missing versions, e.g. .NET 3.5 and SL 3.0 and 5.0?
I wish to create one MSI for all Silverlight DLLs and one MSI for all WPF dlls. Do I need to create further MSIs for the versions compiled as Trial? What about separate MSIs for each version of the .NET or Silverlight framework?
Is it possible to achieve the above deployment packaging using build.targets or build scripts?
Basically if I create manually MSIs for all the above combinations and do a full rebuild that would work, but it is also a laborious process when releasing updates. I am looking for suggestions on how to achieve this with build scripts, build.targets, MSI configurations or a combination of the above.
Finally when redistributing the control libraries, installation should ideally result in registration in the GAC.
Any comments / suggestions welcome.
Best regards,
If you are releasing for different versions of the framework, then you will need different projects. You probably could get away with switching the target framework at runtime, but there are so many variables, by the time you get them all figured out and tested, you could have easily created the additional projects.
I think it would be well worth your money to invest in an Installation tool such as Installshield that has built-in support for the rest of the functionality that you desire.
I believe that you should be able to accomplish all of your needs in a single installshield project using various switches and end user keys (to trigger trial or real installs), but you may potentially consider separating trial and real depending on your licensing scheme.
Update
You can also solve this issue through a pure VS2010 solution, it's just more complicated.
Based on your goals, you will need to have a total of 5 projects and each solution will have 2 configurations, one for release one for trial (where the preprocessor define is set).
You might be able to get away with a single build solution that contains all 5 projects since you can reference the output from each project separately within the VS setup project.
On release, you will have to run the build twice, once for release and once for trial, but you can easily automate this with MSBuild.
What we did to ease the release process burden was create a small database to hold configuration information about the products (locations of solutions, project files, and assemblies) and a small UI application that builds the apps by first changing the version everywhere necessary and then building the installer solution through the visual studio build process.
One very important note that I just remembered as I was typing the above: at one point (it may have been fixed), it was not possible to build Visual Studio 2010 setup projects through MSBuild, which is why we went with building through devenv.com.
For posterities sake I'm recording the solution I came up with thanks to competent_tech's very informative answer.
Solved using an msdos batch file as follows.
Dumped the idea of #If Trial switch. Instead component is licensed by licx file so trial build is the same as release build. This means just one solution for dev work which build outputs are derived from
Created a batch file to rebuild Silverlight and WPF output projects with MSBuild, switching toolsversion to create multiple versions
Copied DLLs over to Nuget style directory structure, e.g. Build/lib/net40, Build/lib/sl4, Build/lib/sl5 etc...
Obfuscate built libs in place
XCopy example projects over to Build/examples/
Use Powershell to edit example projects to reference new obfuscated output.
For reference, please see the following questions and answers on removing/re-adding references and editing project files with powershell