Appearance
Migration Guide: Old God Package → New Packages
Section: 16 — Packages
Last Updated: 2026-05-30
Scope: Namespace mapping, step-by-step migration, common patterns
Background
The original ERP codebase used a single monolithic NuGet package (nicknamed the "God Package") that contained everything: domain primitives, persistence, messaging, web middleware, and more. This created:
- Tight coupling — changing one thing forced rebuilding everything
- Slow CI — every service rebuild required a full God Package rebuild
- Difficult versioning — all-or-nothing upgrades
- Growing transitive dependencies in every service
The God Package was split into the current 16-package architecture. This guide covers migrating services that still reference old namespaces.
Namespace Mapping Table
Shared.Core → Microtec.Domain
| Old Namespace | New Namespace | Notes |
|---|---|---|
Shared.Core.Domain.Entities | Microtec.Domain.Entities | |
Shared.Core.Domain.BaseEntity | Microtec.Domain.BaseEntity | |
Shared.Core.Domain.AggregateRoot | Microtec.Domain.AggregateRoot | |
Shared.Core.Domain.AuditableEntity | Microtec.Domain.AuditableEntity | |
Shared.Core.Domain.TenantEntity | Microtec.Domain.TenantEntity | |
Shared.Core.Interfaces.ITenantProvider | Microtec.Domain.ITenantProvider | |
Shared.Core.Interfaces.IClockService | Microtec.Domain.IClockService | |
Shared.Core.Services.IScopedService | Microtec.Domain.IScopedService | |
Shared.Core.Services.ITransientService | Microtec.Domain.ITransientService | |
Shared.Core.Exceptions.DomainException | Microtec.Domain.DomainException | |
Shared.Core.Exceptions.NotFoundException | Microtec.Domain.NotFoundException | |
Shared.Core.Results.Result<T> | Microtec.Domain.Result<T> | Same interface |
Shared.Core.ValueObjects.* | Microtec.Domain.ValueObjects.* |
Shared.Core → Microtec.Contracts
| Old Namespace | New Namespace | Notes |
|---|---|---|
Shared.Core.CQRS.ICommand | Microtec.Contracts.ICommand | |
Shared.Core.CQRS.IQuery<T> | Microtec.Contracts.IQuery<T> | |
Shared.Core.CQRS.ICommandHandler<T> | Microtec.Contracts.ICommandHandler<T> | |
Shared.Core.DTOs.PagedResult<T> | Microtec.Contracts.PagedResult<T> | |
Shared.Core.DTOs.APIResponse<T> | Microtec.Contracts.APIResponse<T> | |
Shared.Core.Events.IIntegrationEvent | Microtec.Contracts.IIntegrationEvent | |
Shared.Core.DTOs.DropdownDto | Microtec.Contracts.DropdownDto | |
Shared.Core.DTOs.PagedRequest | Microtec.Contracts.PagedRequest |
Shared.Infrastructure → Microtec.Persistence
| Old Namespace | New Namespace | Notes |
|---|---|---|
Shared.Infrastructure.Data.RepositoryBase<T> | Microtec.Persistence.RepositoryBase<T> | |
Shared.Infrastructure.Data.IRepository<T> | Microtec.Persistence.IRepository<T> | |
Shared.Infrastructure.Data.IUnitOfWork<T> | Microtec.Persistence.IUnitOfWork<T> | Same interface |
Shared.Infrastructure.Data.IAdminUnitOfWork | Microtec.Persistence.IAdminUnitOfWork | |
Shared.Infrastructure.Interceptors.AuditInterceptor | Microtec.Persistence.AuditInterceptor | |
Shared.Infrastructure.Extensions.* | Microtec.Persistence.Extensions.* |
Shared.Infrastructure → Microtec.Messaging
| Old Namespace | New Namespace | Notes |
|---|---|---|
Shared.Infrastructure.Messaging.IEventPublisher | Microtec.Messaging.IEventPublisher | |
Shared.Infrastructure.Messaging.EventPublisher | Microtec.Messaging.EventPublisher | |
Shared.Infrastructure.Cache.IDistributedCacheService | Microtec.Messaging.IDistributedCacheService | |
Shared.Infrastructure.Bus.* | Microtec.Messaging.* | MassTransit wrappers |
Shared.Web → Microtec.Web.Core
| Old Namespace | New Namespace | Notes |
|---|---|---|
Shared.Web.Middleware.TenantMiddleware | Microtec.Web.Core.TenantMiddleware | |
Shared.Web.Middleware.ErrorHandlingMiddleware | Microtec.Web.Core.ErrorHandlingMiddleware | |
Shared.Web.Auth.* | Microtec.Web.Core.Auth.* | |
Shared.Web.Services.ICurrentUserService | Microtec.Web.Core.ICurrentUserService | |
Shared.Web.Behaviors.* | Microtec.Web.Core.Behaviors.* | |
Shared.Web.Extensions.AddSharedWebServices() | Microtec.Web.Core.AddMicrotecAuthentication() | Different method name |
Shared.Web → Microtec.Web.Hosting
| Old Namespace | New Namespace | Notes |
|---|---|---|
Shared.Web.Hosting.AddSharedHosting() | Microtec.Web.Hosting.AddMicrotecHosting() | |
Shared.Web.Telemetry.* | Microtec.Web.Hosting.* | |
Shared.Web.Logging.* | Microtec.Web.Hosting.* | Serilog config moved here |
Step-by-Step Migration for a Service
Step 1: Update .csproj References
Remove old God Package references, add new packages:
xml
<!-- BEFORE (old) -->
<PackageReference Include="Microtec.Shared.Core" Version="1.x.x" />
<PackageReference Include="Microtec.Shared.Infrastructure" Version="1.x.x" />
<PackageReference Include="Microtec.Shared.Web" Version="1.x.x" />
<!-- AFTER (new) -->
<PackageReference Include="Microtec.Web.Hosting" Version="2.3.1" />
<PackageReference Include="Microtec.Persistence" Version="2.3.1" />
<PackageReference Include="Microtec.Messaging" Version="2.3.1" />NOTE
Microtec.Web.Hosting pulls in Web.Core transitively. Microtec.Domain and Microtec.Contracts come transitively through Persistence and Messaging. You typically only need to reference Tier 3 packages directly.
Step 2: Update Program.cs
csharp
// BEFORE (old)
builder.Services.AddSharedWebServices(builder.Configuration);
builder.Services.AddSharedHosting(builder.Configuration);
builder.Services.AddSharedPersistence<MyDbContext>(builder.Configuration);
// AFTER (new)
builder.AddMicrotecHosting(o => o.ServiceName = "my-service");
builder.Services
.AddMicrotecAuthentication(builder.Configuration)
.AddMicrotecAuthorization()
.AddMicrotecPersistence<MyDbContext>(builder.Configuration)
.AddMicrotecMessaging(builder.Configuration, consumers =>
{
consumers.AddConsumer<MyEventHandler>();
});Step 3: Update Using Statements
Use the IDE's "Find & Replace" with the mapping table above, or run:
bash
# Example: Replace Shared.Core.Domain with Microtec.Domain
find . -name "*.cs" -exec sed -i '' \
's/using Shared\.Core\.Domain/using Microtec.Domain/g' {} +
find . -name "*.cs" -exec sed -i '' \
's/using Shared\.Core\.CQRS/using Microtec.Contracts/g' {} +
find . -name "*.cs" -exec sed -i '' \
's/using Shared\.Infrastructure\.Data/using Microtec.Persistence/g' {} +
find . -name "*.cs" -exec sed -i '' \
's/using Shared\.Web/using Microtec.Web.Core/g' {} +Step 4: Update DbContext
csharp
// BEFORE
public class MyDbContext : SharedDbContextBase
{
public MyDbContext(DbContextOptions<MyDbContext> options,
ITenantProvider tenantProvider)
: base(options, tenantProvider) { }
}
// AFTER
public class MyDbContext : DbContext
{
private readonly ITenantProvider _tenantProvider;
public MyDbContext(DbContextOptions<MyDbContext> options,
ITenantProvider tenantProvider)
: base(options)
{
_tenantProvider = tenantProvider;
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
modelBuilder.ConfigureDecimalPrecision(18, 4);
modelBuilder.ApplyGlobalQueryFilters(_tenantProvider);
}
}Step 5: Verify Build
bash
cd Platforms
dotnet restore
dotnet build Microtec.Platforms.sln --no-incremental 2>&1 | grep -E "error|warning"Step 6: Run Tests
bash
dotnet test --filter "FullyQualifiedName~{ServiceName}" --logger trxCommon Migration Issues
Issue: AddSharedWebServices not found
Cause: Old extension method removed in Microtec.Web.Core.
Fix: Replace with the new method chain:
csharp
// Old
services.AddSharedWebServices(config);
// New
services.AddMicrotecAuthentication(config)
.AddMicrotecAuthorization()
.AddMicrotecLocalization();Issue: AuditableEntity has no TenantId
Cause: TenantId was moved to TenantEntity (separate class) in the new packages. Not all entities need multi-tenancy.
Fix: Change base class from AuditableEntity to TenantEntity if the entity is tenant-scoped.
Issue: ConfigureDecimalPrecision not found in OnModelCreating
Cause: Extension method lives in Microtec.Persistence.Extensions.
Fix: Add using Microtec.Persistence.Extensions;
Issue: ICurrentUserService missing after migration
Cause: It moved from Shared.Web.Services to Microtec.Web.Core.
Fix: Update using statement. The interface contract is identical.
Issue: Tenant query filter stops working
Cause: ApplyGlobalQueryFilters() must be called after ApplyConfigurationsFromAssembly().
Fix:
csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly); // First
modelBuilder.ConfigureDecimalPrecision(18, 4);
modelBuilder.ApplyGlobalQueryFilters(_tenantProvider); // Last
}Verification Checklist
After migration:
- [ ]
dotnet buildsucceeds with no errors - [ ]
dotnet testpasses all existing tests - [ ] Swagger loads at
/swaggerin dev - [ ] Health check responds at
/health - [ ] Tenant isolation verified (query returns only current tenant's data)
- [ ] Audit fields populated (CreatedBy, UpdatedBy not null after create/update)
- [ ] No references to old
Shared.*namespaces remain
bash
# Verify no old namespaces remain
grep -r "using Shared\." src/ --include="*.cs" | grep -v ".cs.bak"
# Should return empty