Redirect user from startup.cs asp.net core

10,658

My suggestion is to use a Middleware solution that can handle just what you are looking for.

What is middleware

Middleware is software that is assembled into an application pipeline to handle requests and responses.

Each component:

Chooses whether to pass the request to the next component in the pipeline. Can perform work before and after the next component in the pipeline is invoked.

Here is a simple implemetation of how the middleware would work.

Now as we can assume that only at startup of the application we need to check if the database is installed and not every request to the application we can add the middleware only if it is needed. Therefore on restarts the middleware is only included if the database is not installed. So we will only register the Middleware extension when the database is not installed at startup.

The follow code assumes you have reviewed the linked MSDN page above.

Here is a simple example of the middleware (I called it DatabaseInstalledMiddleware)

public class DatabaseInstalledMiddleware
{
    public DatabaseInstalledMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    readonly RequestDelegate _next;

    public async Task Invoke(HttpContext context, IConfiguration configuration)
    {
        if (!IsDatabaseInstalled(configuration))
        {
            var url = "/databasechecker";
            //check if the current url contains the path of the installation url
            if (context.Request.Path.Value.IndexOf(url, StringComparison.CurrentCultureIgnoreCase) == -1)
            {
                //redirect to another location if not ready
                context.Response.Redirect(url);
                return;
            }
        }
        //or call the next middleware in the request pipeline
        await _next(context);
    }

    public static bool IsDatabaseInstalled(IConfiguration configuration)
    {
        var key = configuration["SQLConnectionSettings:SqlServerIp"];
        return !string.IsNullOrEmpty(key);
    }
}

The code is pretty basic, however we see that Invoke method accepts the current HttpContext and injects the IConfiguration instance. Next we run a simple method to check if the database is installed IsDataBaseInstalled.

If this method returns false we check to see if the user is currently requesting the databasechecker url. You can change this pattern or add urls as required if there are multiple install urls. If they are not requesting an install URL then we redirect them to the /databasechecker url. Otherwise the Middleware executes as expected with the line await _next(context).

Now to use this in your request pipleline simply add the middleware before the MVC middleware such as.

This is in the startup.cs file. (Below is the basic startup file)

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();
    if (!DatabaseInstalledMiddleware.IsDatabaseInstalled(Configuration))
        app.UseMiddleware<DatabaseInstalledMiddleware>();
    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}
Share:
10,658
Raj
Author by

Raj

Updated on June 05, 2022

Comments

  • Raj
    Raj almost 2 years

    I have a requirement where I want to check if database is connected(I have the class for that). if this class's method returns false then I want to redirect to database page/view where setup will take place. I have Asp.Net core identity. I want to check this condition before EF core tries to connect to DB. I tried to use the following but returns "too many redirects in browser". Note: Every method in home controller has [Authorize] except DatabaseCheck. Once the user is redirect here I would take values and update Appsettings.json, and application would run normally. Thanks for insights.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(Configuration);          
    
            services.AddDbContext<MyContext>(options =>
            options.UseSqlServer(SqlSettingsProvider.GetSqlConnection()));
    
            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<MyContext>()
                .AddDefaultTokenProviders();
            services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
            services.AddMvc()
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.Formatting = Formatting.Indented;
                }).AddJsonOptions(options =>
                {
                    options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    
                });
    
    
        }
          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
    
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
    
    
    
            if (!DatabaseInstalledMiddleware.IsDatabaseInstalled(Configuration))
                app.UseMiddleware<DatabaseInstalledMiddleware>();
    
    
    
            app.UseStatusCodePagesWithReExecute("/StatusCodes/{0}");
            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller=Home}/{action=Index}/{id?}");
                    routes.MapRoute(
                        name: "defaultApi",
                        template: "api/v2/{controller}/{id?}");
                });     
    
    
    
    
        }
    

    enter image description here

  • Raj
    Raj over 6 years
    Thanks Nico, it returns error : SqlException: Login failed for user ''." . Looks like EF core kicks in before anything else. I am using EF core and Identity. Any suggestion, I have updated my methods above.
  • Nico
    Nico over 6 years
    @Raj its hard to determine where the error is coming from, however the error is likely due to EF trying to execute a query on the database. The stack trace would be handy to see where in the code the error occurs. It may be something very simple as trying to show the logged in users name or some sort of database stored setting.
  • Raj
    Raj over 6 years
    That's the logic I wanted in place if connect string is set then EF should not kick in , I guess it will because of configureService DP.
  • Nico
    Nico over 6 years
    @Raj if you can post your stack trace of the error we can probably figure out exactly why and where its happening.
  • Raj
    Raj over 6 years
    Thanks Nico. I uploaded the error image above. EF core is reaching/seeking out for database before regardless of the middleware. Can I redirect from program.cs ?