It depends on the maturity of your shared code. I would say that there are three approaches that you can follow, each with its own pros and cons:
Option 1: Directly link to them from your own team project
Team Project Application 1 --> Development --> ... --> MAIN --> Sources --> Application 1 --> Application1.sln Team Project Application 2 --> Development --> ... --> MAIN --> Sources --> Application 2 --> Application1.sln Team Project CoreProject 1 --> Development --> ... --> MAIN --> Sources --> CoreProject1.csproj
With this approach, you can install CI in your builds so that all applications begin to be created as soon as you register with CoreProject.
You must have Team projects locally mapped to the convention (or compilation will fail)
This is a good approach if you are constantly changing CoreProject and need to ensure that these changes are quickly reflected in all affected applications.
It also implies that you can allow instability in a particular application if a violation in CoreProject inflicts on it.
Option 2: Indirectly link to them via branching
Team Project Application 1 --> Development --> ... --> MAIN --> SharedSources --> CoreProject1_branch --> CoreProject1.csproj --> Sources --> Application 1 ---> Application1.sln Team Project Application 2 --> Development --> ... --> MAIN --> SharedSources --> CoreProject1_branch --> CoreProject1.csproj --> Sources --> Application 2 ---> Application1.sln Team Project CoreProject 1 --> Development --> ... --> MAIN --> Sources --> CoreProject1.csproj
With this approach, every time you check for changes in CoreProject1, you need to organize a merge for each affected application. This creates some effort, but gives you time to stabilize CoreProject on your own playground, and then combine it with your applications.
This approach implies that you also have an assembly definition for each CoreProject.
All in all, this is a good way to continue if you value the stability of CoreProject and cannot afford to βpolluteβ your applications if changes cause problems. This is the approach we have taken.
Option 3: Make a link to the file in each application
Team Project Application 1 --> Development --> ... --> MAIN --> SharedBinaries --> CoreProject1_branch --> CoreProject1.dll --> Sources --> Application 1 ---> Application1.sln Team Project Application 2 --> Development --> ... --> MAIN --> SharedBinaries --> CoreProject1_branch --> CoreProject1.dll --> Sources --> Application 2 ---> Application1.sln Team Project CoreProject 1 --> Development --> ... --> MAIN --> Sources --> CoreProject1.csproj
With this approach, you need to check the binary output of the CoreApplication assembly in each application.
This is only recommended if you are confident that CoreApplication is stable and you do not need to debug it on a regular basis.
Essentially, option 2 and option 3 are similar, separated by the well-known discussion of βproject versus file linkβ. See here for the SO resource, and more can be found in the search results.
If your main projects are constantly changing and / or have low unit test coverage, you should go to option 2 (or 3).
If you are confident in your quality, switching to option 1 is a good choice, as it will significantly increase your overall performance.
Without any knowledge of your products and their quality, simply based on the fairly large numbers that you provide (20 people, 50 solutions, 7 major projects), I would choose option 2/3.
Another important hint: this happens more often than the fact that the shared projectd does not have a means of sharing testing. If this is the case, and the Core Project does not have its own unit tests, there is no special test plan, etc., there is no point in doing anything other than option 1.
An additional great resource on this is work from ALM Rangers.