0

I have issues running my asp.net core 3.1 web api on a remote server after publishing it. The API is working well on my PC but when I publish it, all API end points are returning error 404. My swagger documentation page swagger/index.html is also returning the same error.

Below is the Program.cs code

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

My Startup cs file is as follows

public class Startup
{
    private readonly IWebHostEnvironment _env;
    private readonly IConfiguration _configuration;
    //public static IMvcBuilder ConfigureApiBehaviorOptions(this IMvcBuilder builder, Action<ApiBehaviorOptions> setupAction);

    public Startup(IWebHostEnvironment env, IConfiguration configuration)
    {
        _env = env;
        _configuration = configuration;
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        try
        {
            // use sql server db in production and sqlite db in development
            //if (_env.IsProduction())
            //    services.AddDbContext<DataContext, SqlDataContext>();
            //else
            //    services.AddDbContext<DataContext, SqliteDataContext>();

            //services.AddDbContext<DataContext, SqlDataContext>();
            services.AddDbContext<DataContext, SqlDataContext>
            (options => options.UseSqlServer(Configuration.GetConnectionString("SQLServerdb")));

            services.AddCors();
            services.AddControllers();
            services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

            // configure strongly typed settings objects
            var appSettingsSection = _configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // enabling API documentation
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
                {
                    Version = "v1",
                    Title = "x",
                    Description = "x",
                    TermsOfService = null,
                    Contact = new Microsoft.OpenApi.Models.OpenApiContact()
                    {
                        Name = "x",
                        Email = "x",
                        Url = null
                    }
                });

                    // Set the comments path for the Swagger JSON and UI.
                    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });

            // enabling Cookies
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
            }).AddCookie("Cookies", options =>
            {
                options.Cookie.Name = globals.APISessionKey;
                options.Cookie.SameSite = SameSiteMode.None;
                options.Events = new CookieAuthenticationEvents
                {
                    OnRedirectToLogin = redirectContext =>
                    {
                        redirectContext.HttpContext.Response.StatusCode = 401;
                        return Task.CompletedTask;
                    }
                };
            });

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.Events = new JwtBearerEvents()
                {
                    OnTokenValidated = context =>
                    {
                        var userService = context.HttpContext.RequestServices.GetRequiredService<IUserService>();

                        var theContext = context.HttpContext;
                        var userId = int.Parse(context.Principal.Identity.Name);
                        var user = userService.GetById(context.HttpContext, userId);
                        if (user == null)
                        {
                                // return unauthorized if user no longer exists
                                context.Fail("Unauthorized");
                        }
                        return Task.CompletedTask;
                    }
                };
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });


            // custom validation responses CustomBadRequest
            //services.Configure<ApiBehaviorOptions>(a =>
            //{
            //    a.InvalidModelStateResponseFactory = context =>
            //    {
            //        var problemDetails = new CustomBadRequest(context);

            //        return new BadRequestObjectResult(problemDetails)
            //        {
            //           // ContentTypes = { "application / problem + json", "application / problem + xml" } // these requires cross origin resource what what (cors)
            //        };
            //    };
            //});
        }
        catch (Exception ex)
        {
            Console.WriteLine("ConfigureServices _ERROR: " + ex.Message);
        }
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
    {
        try
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            dataContext.Database.Migrate();

            app.UseHttpsRedirection();

            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });

            // Enable middle ware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("../swagger/v1/swagger.json", "My API V1 (RELEASE)");
                    //c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1 (DEBUG)");

                    /*To serve the Swagger UI at the app's root (http://localhost:<port>/), set the RoutePrefix property to an empty string:
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
                    c.RoutePrefix = string.Empty;*/
            });

            //if (env.IsDevelopment())
            //{
            //    app.UseDeveloperExceptionPage();
            //}

            //app.UseHttpsRedirection();

            //app.UseRouting();

            //app.UseAuthorization();

            //app.UseEndpoints(endpoints =>
            //{
            //    endpoints.MapControllers();
            //});
        }
        catch (Exception ex)
        {
            Console.WriteLine("Configure _ERROR: " + ex.Message);
        }
    }
}
}

Is there anything that i am missing. My API is haring the same solution with a blazor server app which is working perfectly well on the same server which the API is failing to work.

I have tried fixing the issue on my own and searching on the internet but haven't found anything that could assist me resolve this issue. Your help is highly appreciated.

Airn5475
  • 2,452
  • 29
  • 51
  • There are many reasons that this could occur. Would you mind adding more details regarding what you have tried? For example: What is your deployment method? Are you deploying to IIS? Did you install the .Net Core hosting bundle? How is the website configured on the server? Are folder permissions set up correctly on the server? If the code works locally then it might be something with the server configuration or even a router. – Soenhay Aug 18 '20 at 15:35
  • If you're deploying to IIS, please have a look at my checklist here: https://stackoverflow.com/a/63466234/14072498 – Roar S. Aug 19 '20 at 02:03
  • Thank you so much for your contribution. I am deploying the API to a folder on my local PC then copy the contents to the server. Yes, i have installed hosting bundles, the old version of the API is actually running without issues on the same server. I don't know if there is anything which installed which is causing this problem. I will look into your checklist and see if i can get some pointers – Dot Naughty Aug 19 '20 at 17:45

1 Answers1

1

There is no problem in the Swagger settings of your project. It seems that you are deploying the DotNet Core Application(Core Web API and Blazor serve app) to the IIS web server.
Generally speaking, if these applications work properly locally but returning HTTP errors in the remote web server. the hosting environment might be configured improperly. For example, the below IIS hosting bundle is required when hosting the DotNet Core application.
enter image description here
Download URL (directly download).
https://dotnet.microsoft.com/download/dotnet-core/thank-you/runtime-aspnetcore-3.1.7-windows-hosting-bundle-installer
Additionally, the publishing location, in other words, the website root directory should be accessed properly by IUSR account or Everyone account. It depends on the account of the application pool identity.
enter image description here
Feel free to let me know if the problem persists.

Abraham Qian
  • 7,117
  • 1
  • 8
  • 22
  • Thank you so much for your comment. Hosting bundles are installed. The blazor app is working properly well on both my local PC as well as on the server. I recreated the .net core 3.1 API project from the server worked properly when i ran it from visual studio on the server (The one that was running from my local PC wasn't). However, the project failed to run on my local machine. It was now returning http error 404 on my local PC. It now feels like the API is running only from the PC it was created from. The API used to run without any issues on both my PC and the server. – Dot Naughty Aug 19 '20 at 17:35
  • Http 404 error might relate to the network issue. From your description, the API application works only from the PC it was created from. I would like to know that how did you test the result that fail to work in the other machine? If you just test it by accessing the service in the browser instead of deploying it in the IIS web server, I suspect it might be network issue. In the other words, The network between these two machines is blocked, thereby we can not access it in the browser from another machine. – Abraham Qian Aug 21 '20 at 09:23