-
Notifications
You must be signed in to change notification settings - Fork 0
Magic EF Share Protocol
The Magic EF Share Scaffold Protocol is an advanced, automated scaffolding system designed to generate a reusable Shared Library alongside your primary database scaffolded class library. It creates read-only interfaces, DTO models, mapping profiles, and extension files that simplify working with database entities across multiple projects.
This protocol is particularly powerful when used with Blazor, where strict typing and reusable DTO models are highly beneficial. However, it is still a valuable tool in any .NET environment that requires reusable, structured, and automatically maintained entity models.
- Auto-generates Read-Only Models & Interfaces
- Creates DTO Models with Mapping Profiles
- Supports Shared Extensions & Metadata
- Works alongside Magic EF Scaffolding
- Minimal Maintenance, Highly Extensible
- Blazor-Friendly & Reusable in APIs or Frontend Apps
- Automatically Updates When Database Schema Changes
Unlike the main Magic EF Scaffolding Protocol, which has been refined over years of development, the Share Scaffold Protocol is still evolving. While actively used in production by the creator, protocol changes could require refactoring in your codebase.
- π’ The Share Scaffold Protocol is expected to exit experimental status in 2025
- π‘ The Migration Runner remains experimental for now
- π΄ Future protocol changes may require refactoring
Developers using this feature should carefully review scaffolded changes before integrating them into their projects.
Before running the Share Scaffold Protocol, you must first set up a new Shared Library in your solution. Then I suggest you also make your original database scaffolded project reference your new shared project, but not vice versa!
- This should be a C# Class Library Project with the same .NET version as your database scaffolded class library.
- This project should not contain additional dependencies aside from those added by the scaffolding process.
- Naming suggestion:
- If your database project is called
PrimaryDb
, name your shared libraryPrimaryDb.Share
.
- If your database project is called
Example:
Solution/
βββ PrimaryDb/ # Your database scaffolded class library
β βββ PrimaryDb.csproj
βββ PrimaryDb.Share/ # Your shared library project
β βββ PrimaryDb.Share.csproj
In the database scaffolded class library, install AutoMapper:
dotnet add package AutoMapper
If using NetTopologySuite in your database library, install it in the Shared Library as well:
dotnet add package Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
The recommended approach is to use the provided PowerShell script:
π Scaffold_Script_Example.ps1
(located in the Magic EF repository)
-
Open the script and locate:
# Define Share namespace (default set to ":" to indicate disabled state) $shareNamespace = ":"
-
Change
:
to your Shared Library Name (e.g.,"PrimaryDb.Share"
).Example:
$shareNamespace = "PrimaryDb.Share"
-
Running the script now automatically executes:
MagicEF --initialShareSetupHandler --shareProjectFilePath "$shareProjectFilePath" --dbProjectFilePath ".\$projectFileName" MagicEF --shareScaffoldProtocolHandler --shareNamespace "$shareNamespace" --other-required-flags
-
DO NOT add the Share Scaffold Protocol to your CI/CD pipelines.
- This should only be manually run during development.
- Always review generated files before committing.
If your database models include Geometry types:
- Add
using NetTopologySuite.Geometries;
to:-
ReadOnly Models (
{ModelName}ReadOnly.cs
) -
ReadOnly Interfaces (
I{ModelName}ReadOnly.cs
)
-
ReadOnly Models (
- These
using
statements are preserved on future scaffolds.
After running the Share Scaffold Protocol, the following folders and files are created automatically:
- DO NOT modify ReadOnly Models manually.
- Use ViewDTO Models for customization.
PrimaryDb.Share/
βββ ReadOnlyInterfaces/
β βββ I{ModelName}ReadOnly.cs
βββ ReadOnlyModels/
β βββ {ModelName}ReadOnly.cs
- These are safe to modify.
- You should work only within these classes.
PrimaryDb.Share/
βββ ViewDtoModels/
β βββ {ModelName}ViewDTO.cs
Example:
[MetadataType(typeof(GeoLocationMetadata))]
public partial class GeoLocationViewDTO : GeoLocationReadOnly, IGeoLocation
{
// make modifications here or write explicit ignore code
[EditorBrowsable(EditorBrowsableState.Never)]
[JsonIgnore]
Geometry IGeoLocationReadOnly.Location { get => ExplicitlyIgnore.Get<Geometry>(); set => ExplicitlyIgnore.Set(value); }
}
if you want my personal ExplicitlyIgnore code I created for my personal use, you can just steal it here:
public static class ExplicitlyIgnore
{
#pragma warning disable CS8603 // Suppresses "Possible null reference return"
/// <summary>
/// Returns the default value for a property meant to be ignored.
/// </summary>
public static T Get<T>() => default;
#pragma warning restore CS8603 // Re-enables the warning after this point
/// <summary>
/// Logs a debug message when attempting to set an ignored property.
/// </summary>
public static void Set<T>(T _)
{
#if DEBUG
try
{
string className = typeof(T).Name;
Console.WriteLine($"DTO disabled serializing: {className}");
}
catch
{
Console.WriteLine($"DTO disabled serializing");
}
#endif
}
}
Metadata and extensions allow shared logic across models.
PrimaryDb.Share/
βββ SharedMetaData/
β βββ {ModelName}SharedMetadata.cs
βββ SharedExtensions/
β βββ {ModelName}SharedExtensions.cs
Example:
public static class GeoLocationSharedExtension
{
public static string GetFormattedLocation(this IGeoLocationReadOnly location)
{
return location?.Location?.ToString() ?? "N/A";
}
}
The Magic EF Share Scaffold Protocol generates AutoMapper Profiles inside the database scaffolded class library.
PrimaryDb/
βββ MappingProfiles/
β βββ {ModelName}ToDtoProfile.cs
β βββ DtoTo{ModelName}Profile.cs
Example:
public class GeoLocationToDtoProfile : Profile
{
public GeoLocationToDtoProfile()
{
// Use interface-first mapping by default for IGeoLocationReadOnly
CreateMap<IGeoLocationReadOnly, IGeoLocationReadOnly>()
.IncludeAllDerived(); // Automates mapping for shared interface properties
// Specific mapping for custom logic can be added here:
//CreateMap<GeoLocationReadOnly, GeoLocationViewDTO>()
// .IncludeBase<IGeoLocationReadOnly, IGeoLocationReadOnly>()
// .ForMember(dest => dest.YourField, opt => opt.MapFrom(src => "Custom Value"));
}
}
public class DtoToGeoLocationProfile : Profile
{
public DtoToGeoLocationProfile()
{
// Use interface-first mapping by default for IGeoLocationReadOnly
CreateMap<IGeoLocationReadOnly, IGeoLocationReadOnly>()
.IncludeAllDerived(); // Automates mapping for shared interface properties
// Specific mapping for DTO -> model logic can be added here:
//CreateMap<GeoLocationViewDTO, GeoLocationReadOnly>()
// .IncludeBase<I{originalName}ReadOnly, I{originalName}ReadOnly>()
// .ForMember(dest => dest.YourField, opt => opt.MapFrom(src => "Something"));
}
}
To disable the Share Scaffold Protocol, revert:
$shareNamespace = ":"
Or remove just the following if you don't want to have the shared extension interface and/or metadata share:
MagicEF --shareScaffoldProtocolHandler --dbMetadataPath --dbExtensionsPath
The Magic EF Share Scaffold Protocol provides:
β
Automated Read-Only Models & Interfaces
β
Safe ViewDTO Models with Extension & Metadata Handling
β
Seamless AutoMapper Integration
β
Enforced Compilation Errors for Type Mismatches
β
Improved Maintainability & Reusability
With these structured automation tools, best practices become effortless. π