W codziennej pracy programisty .NET prędzej czy później pojawia się potrzeba współdzielenia kodu między kilkoma projektami. Modele, helpery, logika biznesowa – wszystko to często duplikuje się w wielu aplikacjach. Jednym ze sposobów na poradzenie sobie z tym problemem jest wykorzystanie Shared Project, czyli pliku .shproj. Ale czym właściwie jest ten format, jak działa i kiedy ma sens, a kiedy lepiej go unikać?
W tym artykule wyjaśniam to krok po kroku – praktycznie i bez marketingowej otoczki.
Co to jest Shared Project (.shproj)?
Shared Project to specjalny rodzaj projektu w Visual Studio, który pozwala współdzielić same pliki źródłowe, bez tworzenia dodatkowej biblioteki DLL. Kod znajdujący się w projekcie .shproj nie jest kompilowany samodzielnie. Zamiast tego staje się częścią każdego projektu, który go referuje.
W praktyce oznacza to, że:
- Shared Project nie ma własnego target frameworka,
- nie generuje osobnego assembly,
- jego pliki kompilują się tak, jakby były fizycznie dodane do projektu głównego.
Dzięki temu Shared Project jest bardzo elastyczny i świetnie sprawdza się w sytuacjach, kiedy różne aplikacje korzystają z tej samej logiki, ale każda kompiluje ją w swoim własnym środowisku – np. WPF, WinUI, Xamarin, Android czy Worker Service.
Po co powstały Shared Projects?
Główny problem, który rozwiązują, to potrzeba łączyć logikę wspólną bez konieczności:
- tworzenia bibliotek,
- utrzymywania wersji,
- budowania paczek NuGet,
- walki z referencjami i konfliktami frameworków.
Shared Project był bardzo popularny szczególnie w czasach:
- PCL (Portable Class Library),
- projektów UWP + WPF,
- Xamarin (Android/iOS).
Dziś nadal ma sens – szczególnie w dużych solucjach, gdzie kilka projektów rozwijanych jest jednocześnie.
Jak działa .shproj w praktyce?
Załóżmy, że masz strukturę:
Solution ├─ App.Wpf ├─ App.Worker ├─ App.Common.shproj
A w App.Common.shproj masz klasę:
public static class MathHelper
{
public static int Add(int a, int b) => a + b;
}
Jeśli oba projekty (App.Wpf i App.Worker) referują Shared Project:
- kompilują tę klasę u siebie, tak jakby tam była,
- możesz stosować dyrektywy kompilatora:
#if WINDOWS // Windows-only code #endif
- nie tworzysz DLL – kod wciąga się sam.
To świetnie działa, jeśli wszystkie projekty są w jednej solucji i jednym repozytorium.
Kiedy Shared Project to dobry wybór?
Shared Project jest świetny, gdy:
✔️ Masz kilka projektów w jednej solucji
Np.:
- aplikacja desktopowa,
- aplikacja usługowa (Worker),
- aplikacja testowa,
- narzędzie CLI.
Wszystkie korzystają z tej samej logiki.
✔️ Nie chcesz tworzyć osobnej biblioteki
Brak:
- wersjonowania,
- budowania NuGet,
- problemów z kompatybilnością frameworków.
✔️ Chcesz, aby kod był kompilowany w kontekście projektu docelowego
To pozwala:
- używać różnych API per platforma,
- stosować
#if WINDOWS,#if ANDROID, - jednocześnie utrzymywać jedną bazę kodu.
✔️ Wszystko trzymasz w jednym repo (monorepo)
Git świetnie radzi sobie z Shared Projectem, bo:
- pliki
.cstrafiają normalnie do repo, .shprojto zwykły XML trzymany w repo,- każda referencja to ścieżka względna,
- refaktoryzacja działa we wszystkich projektach naraz.
Kiedy Shared Project zaczyna przeszkadzać?
Shared Project przestaje być dobrym rozwiązaniem, gdy:
❌ ten sam kod chcesz używać w wielu repozytoriach
Jeśli masz:
- Repo 1: Aplikacja
- Repo 2: Worker
- Repo 3: Tools
i wszystkie mają korzystać z jednego shared code → zaczynają się schody:
- musisz używać Git submodule,
- ścieżki względne się psują,
- refaktoryzacja potrafi wywrócić projekty poza repo,
- debugowanie bywa męczące.
❌ potrzebujesz wersjonowania
Shared Project nie ma wersji – wszystko jest zawsze „z głównej gałęzi”.
To problem, gdy:
- jedna aplikacja ma być na wersji 1.0,
- druga wymaga nowszej wersji 1.2.
W Shared Project to niewykonalne. Każda zmiana od razu wpływa na wszystkie projekty.
❌ chcesz publikować bibliotekę dla innych
Wtedy lepsze jest:
- Class Library (.csproj)
- publikacja jako NuGet (np. prywatny feed, GitHub Packages, Azure Artifacts)
To daje stabilne API, wersjonowanie i porządek.
Shared Project vs Class Library – porównanie
| Cecha | Shared Project (.shproj) | Class Library (.csproj) |
|---|---|---|
| Generuje DLL | ❌ Nie | ✔️ Tak |
| Ma własny target framework | ❌ Nie | ✔️ Tak |
| Łatwe wersjonowanie | ❌ Nie | ✔️ Tak |
| Nadaje się do wielu repo | ❌ Raczej nie | ✔️ Tak |
| Elastyczny, prosty w solucji | ✔️ Tak | ❌ Wymaga budowania |
| Kompiluje się „w projekcie” | ✔️ Tak | ❌ Nie |
Co więc wybrać?
Użyj Shared Project, jeśli:
- masz jedną solucję, wiele projektów,
- nie potrzebujesz DLL,
- chcesz szybko rozwijać wspólny kod,
- cały zespół pracuje w jednym repo.
Użyj Class Library + NuGet, jeśli:
- kod ma być stabilny i wersjonowany,
- używasz go w wielu repozytoriach,
- planujesz publikować API,
- budujesz mikroserwisy lub architekturę modułową.
Podsumowanie
Shared Project (.shproj) to świetne rozwiązanie, gdy:
- pracujesz w ramach jednego repozytorium,
- masz kilka aplikacji korzystających ze wspólnej logiki,
- chcesz uprościć organizację kodu,
- zależy Ci na szybkim refaktoringu bez budowania bibliotek.
Jednocześnie nie jest to narzędzie uniwersalne. Jeśli projekt rośnie i wymaga stabilnych wersji – prędzej czy później Shared Project ustąpi miejsca klasycznej bibliotece .NET i pakietom NuGet.

