DEV Community

Stein Lundbeck
Stein Lundbeck

Posted on

A way to configure an asp.net core site

I found myself coding a lot of the same code when creating and configuring ASP.NET Core sites, so I made this system to gather all the config code in one class and simplify adding and removing features.

I create one class per feature and all classes derive from AppFeatureBase.cs. All classes must set a value indicating what feature they represent.

Sorry, but I can't get to mark the code, so it's a little hard to read.

In Program.cs I add features by creating new features classes.

AppFeatureBase.cs:
`public interface IAppFeatureBase
{
Features Type { get; }
}

public abstract class AppFeatureBase : IAppFeatureBase
{
private readonly Features _type;

protected AppFeatureBase(Features type)
{
    _type = type;
}

public Features Type => _type;
Enter fullscreen mode Exit fullscreen mode

}`

Some types implementing IAppFeatureBase:
public interface IDefaultRoute
{
string Route { get; }
}

public sealed class DefaultRoute : AppFeatureBase, IAppFeatureBase, IDefaultRoute
{
private readonly string _route;

public DefaultRoute(string controller, string action) : base(Features.DefaultRoute)
{
    _route = CoreStatics.GetBaseRoute(controller, action);
}

public string Route => _route;
Enter fullscreen mode Exit fullscreen mode

}

public interface ISSL
{
int Port { get; }
}

public sealed class SSL : AppFeatureBase, IAppFeatureBase, ISSL
{
private readonly int _port = 443;

public SSL() : base(Features.SSL)
{
}

public SSL(int port) : base(Features.SSL)
{
    _port = port;
}

public int Port => _port;
Enter fullscreen mode Exit fullscreen mode

}`

AssetsConfig.cs:
`public static class AssetsConfig
{
public static void AddAssets(WebApplicationBuilder builder, params IAppFeatureBase[] features) => AddAssets(builder, null, features);

public static void AddAssets(WebApplicationBuilder builder, Action<MvcOptions>? mvcOptions, params IAppFeatureBase[] features)
{
    if (builder.Configuration.GetSection(AssetsStatics.ConfigSectionName).Exists())
    {
        IAssetsConfig cnf = new Assets.AssetsConfig(builder.Configuration);
        builder.Configuration.Bind(AssetsStatics.ConfigSectionName, cnf);

        _ = builder.Services
            .AddOptions()
            .Configure<IConfiguration>(builder.Configuration)
            .AddSingleton(cnf);
    }
    else
    {
        throw new ConfigSectionNotFoundException();
    }

    _ = builder.Services
        .AddHttpContextAccessor()
        .AddDbContext<AssetsDbContext>(opt => opt.UseSqlServer(AssetsStatics.ConnectionString))
        .AddDbContext<AssetsClientDbContext>(opt => opt.UseSqlServer(AssetsStatics.ClientConnectionString))
        .AddTransient<ISiteHelper, SiteHelper>()
        .AddTransient<IAssetsDbContext, AssetsDbContext>()
        .AddTransient<IAssetsClientDbContext, AssetsClientDbContext>()
        .AddTransient<IDbContextAccessor, DbContextAccessor>()
        .AddTransient<IActionContextAccessor, ActionContextAccessor>()
        .AddTransient<IAssetsConfigAccessor, AssetsConfigAccessor>()
        .AddTransient<IUtilityHelper, UtilityHelper>()
        .AddTransient<IUrlHelperFactory, UrlHelperFactory>()
        .AddTransient<IRepoFactory, RepoFactory>()
        .AddTransient<IExpressionFactory, ExpressionFactory>()
        .AddTransient<ITagHelperRepo, TagHelperRepo>()
        .AddTransient<ISiteHelper, SiteHelper>()
        .Configure<CookiePolicyOptions>(opt =>
        {
            opt.MinimumSameSitePolicy = SameSiteMode.Lax;
        })
        .AddSession(opt =>
        {
            opt.IdleTimeout = TimeSpan.FromMinutes(CoreStatics.SessionTimeout);
        });

    if (features.Exists(Features.Secure))
    {
        _ = builder.Services
            .AddTransient<ISecureAccessor, SecureAccessor>();
    }

    if (features.Exists(Features.FileUpload))
    {
        IFileUpload fu = (FileUpload)features.Single(feat => feat.Type == Features.FileUpload);
        _ = builder.Services
            .AddSingleton(new PhysicalFileProvider(fu.FolderPath));
    }

    if (features.Exists(Features.Logging))
    {
        _ = builder.Services
            .AddTransient<IAssetsLogging, AssetsLogging>();
    }

    if (features.Exists(Features.SSL))
    {
        SSL ssl = (SSL)features.Single(feat => feat.Type == Features.SSL);

        _ = builder.Services
           .AddHttpsRedirection(conf =>
           {
               conf.HttpsPort = ssl.Port;
           });
    }

    if (features.Exists(Features.Service))
    {
        foreach (Service feat in features.Where(feat => feat.Type == Features.Service).Cast<Service>())
        {
            switch (feat.Scope)
            {
                case ServiceScopes.Singleton:
                    builder.Services
                        .AddSingleton(feat.Interface, feat.Implementation);
                    break;

                case ServiceScopes.Scoped:
                    builder.Services
                        .AddScoped(feat.Interface, feat.Implementation);
                    break;

                case ServiceScopes.Transient:
                    builder.Services
                        .AddTransient(feat.Interface, feat.Implementation);
                    break;
            }
        }
    }

    if (features.Exists(Features.Blazor))
    {
        _ = builder.Services
            .AddServerSideBlazor();
    }

    if (features.Exists(Features.Content))
    {
        foreach (ApplicationFeatures.Content cnt in features.Where(ft => ft.Type == Features.Content))
        {
            switch (cnt.Feature)
            {
                case ContentFeature.Local:
                    _ = builder.Services
                        .AddTransient<ILocalizationAccessor, LocalizationAccessor>();
                    break;

                case ContentFeature.Value:
                    _ = builder.Services
                        .AddTransient<IContentAccessor, ContentAccessor>();
                    break;

                case ContentFeature.All:
                    _ = builder.Services
                        .AddTransient<ILocalizationAccessor, LocalizationAccessor>()
                        .AddTransient<IContentAccessor, ContentAccessor>();
                    break;
            }
        }
    }

    _ = builder.Services
        .AddDistributedMemoryCache()
        .AddSession(opt =>
        {
            opt.Cookie.Name = CoreStatics.SessionCookieName;
            opt.Cookie.HttpOnly = false;
        })
        .AddControllersWithViews(mvcOptions);

    if (features.Exists(Features.Minify))
    {
        Minify mn = (Minify)features.Single(ft => ft.Type == Features.Minify);

        switch (mn.Target)
        {
            case MinifyTargets.Production:
                if (builder.Environment.IsProduction())
                {
                    AddToServices();
                }
                break;

            case MinifyTargets.Both:
                AddToServices();
                break;
        }

        void AddToServices()
        {
            _ = builder.Services
                .AddWebMarkupMin(opt =>
                {
                    opt.AllowCompressionInDevelopmentEnvironment = true;
                    opt.AllowMinificationInDevelopmentEnvironment = true;
                })
                .AddHtmlMinification(opt =>
                {
                    opt.MinificationSettings.RemoveRedundantAttributes = true;
                    opt.MinificationSettings.RemoveHttpsProtocolFromAttributes = true;
                    opt.MinificationSettings.RemoveHttpsProtocolFromAttributes = true;
                });
        }
    }

    if (features.Exists(Features.GoogleAuth))
    {
        GoogleConfigSection config = new();
        builder.Configuration.GetSection("Google").Bind(config);

        _ = builder.Services.AddAuthentication().AddGoogle(opt =>
        {
            opt.ClientId = config.ClientId;
            opt.ClientSecret = config.ClientSecret;
        });
    }

    WebApplication app = builder.Build();

    if (features.Exists(Features.Debug))
    {
        Debug db = (Debug)features.Single(feat => feat.Type == Features.Debug);
        db.Environment = app.Environment;

        if (db.Environment.IsDevelopment() || db.IgnoreEnvironment)
        {
            _ = app
                .UseDeveloperExceptionPage();
        }
    }

    if (features.Exists(Features.SSL))
    {
        _ = app
            .UseHttpsRedirection();
    }

    if (features.Exists(Features.GDPR))
    {
        GDPR feat = (GDPR)features.Single(ft => ft.Type == Features.GDPR);

        _ = app.Map("/AssetsAPI/SetGDPR", async context =>
        {
            context.Response.Cookies.Append(CoreStatics.GDPRCookieName, CoreStatics.GDPRCookieName);
        });
    }

    if (features.Exists(Features.Minify))
    {
        Minify mn = (Minify)features.Single(ft => ft.Type == Features.Minify);

        switch (mn.Target)
        {
            case MinifyTargets.Production:
                if (builder.Environment.IsProduction())
                {
                    _ = app.UseWebMarkupMin();
                }
                break;

            case MinifyTargets.Both:
                _ = app.UseWebMarkupMin();
                break;
        }
    }

    _ = app
        .UseStaticFiles()
        .UseRouting()
        .UseSession()
        .UseCookiePolicy(new CookiePolicyOptions
        {
            MinimumSameSitePolicy = SameSiteMode.Lax
        });

    if (features.Exists(Features.Content))
    {
        app
            .UseMiddleware<SetCulture>();
    }

    if (features.Exists(Features.DefaultRoute) && !features.Exists(Features.Blazor))
    {
        DefaultRoute route = (DefaultRoute)features.Single(feat => feat.Type == Features.DefaultRoute);

        _ = app.UseEndpoints(end =>
        {
            _ = end.MapControllerRoute(name: "default", pattern: route.Route);
        });
    }
    else if (features.Exists(Features.Blazor))
    {
        IBlazor blzr = (Blazor)features.Single(ft => ft.Type == Features.Blazor);

        _ = app.UseEndpoints(endpoints =>
        {
            _ = endpoints.MapControllerRoute(
                name: "default",
                pattern: blzr.Pattern);

            _ = endpoints.MapBlazorHub();
        });
    }
    else
    {
        _ = app.UseEndpoints(opt => opt.MapDefaultControllerRoute());
    }

    app.Run();
}
Enter fullscreen mode Exit fullscreen mode

}`

And this is how it looks in Program.cs:
`WebApplicationBuilder bld = WebApplication.CreateBuilder(args);

AssetsConfig.AddAssets(bld,
new GDPR("LE", "Index"),
new DefaultRoute("LE", "Index"),
new Service(typeof(IDataRepo), typeof(DataRepo)),
new Service(typeof(IPictureListRepo), typeof(PictureListRepo)),
new Service(typeof(ILESiteHelper), typeof(LESiteHelper)),
new Minify(MinifyTargets.Production));`

I have a framework called Assets which all my sites derives from, so this way I can easily add new features to Assets and add them to sites without having to think about adding all services in correct order.

Hope you like it :)

Top comments (0)

Cloudinary image

Optimize, customize, deliver, manage and analyze your images.

Remove background in all your web images at the same time, use outpainting to expand images with matching content, remove objects via open-set object detection and fill, recolor, crop, resize... Discover these and hundreds more ways to manage your web images and videos on a scale.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay