Issue
I am hosting a site on IIS (Windows Server 2022), and trying to implement a simple register-login system via simple ASP.Net Core Web API, but while I can manipulate database internally, I cannot do it externally, nor via the curl test commands.
In the event logs there is an error "Reason: Could not find a login matching the name provided.", but the login is correct, when I try to run cmd sqlcmd -S <my domain> -d UsersDatabase -U <userlogin> -P <password> -Q "SELECT * FROM users;"
- it works perfectly, so credentials seem to be working.
I tried to log extensively but no logs are even created, the code does not runs it seems? Do I miss something stupid, did I deploy the app itself wrong, missed additional allowance for external requests or something?
Here is my current class of the API:
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using BCrypt.Net;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Serilog.Core;
namespace APIInjector
{
public class User
{
public int Id { get; set; }
public string? Login { get; set; }
public string? Nickname { get; set; }
public string? PasswordHash { get; set; }
public string? Email { get; set; }
public bool EmailConfirmed { get; set; }
}
public class UserInputModel
{
public string? Login { get; set; }
public string? Password { get; set; }
}
public class UsersDbContext : DbContext
{
public UsersDbContext(DbContextOptions<UsersDbContext> options) : base(options)
{
}
public DbSet<User>? Users { get; set; }
}
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
private readonly UsersDbContext _dbContext;
private readonly ILogger<UsersController> _logger;
public UsersController(UsersDbContext dbContext, ILogger<UsersController> logger)
{
_dbContext = dbContext;
_logger = logger;
}
[HttpPost("register")]
public async Task<IActionResult> Register(UserInputModel userInput)
{
_logger.LogInformation("Register action was called");
if (await _dbContext.Users!.AnyAsync(x => x.Login == userInput.Login))
{
return BadRequest("User already exists");
}
var user = new User
{
Login = userInput.Login,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(userInput.Password),
};
_dbContext.Users!.Add(user);
await _dbContext.SaveChangesAsync();
return Ok(new { Message = "User registered successfully" });
}
[HttpPost("login")]
public IActionResult Login(UserInputModel userInput)
{
_logger.LogInformation("Login action was called");
var existingUser = _dbContext.Users!.FirstOrDefault(u => u.Login == userInput.Login);
if (existingUser == null || !BCrypt.Net.BCrypt.Verify(userInput.Password, existingUser.PasswordHash))
{
return Unauthorized(new { Message = "Invalid login credentials" });
}
return Ok(new { Message = "Login successful" });
}
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UsersDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Server=<domain>;Database=UsersDatabase;User Id=<username>;Password=<password>"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Program.cs:
using APIInjector;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using System;
public class Program
{
public static void Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.File("E:\\logs\\myapp.txt")
.CreateLogger();
try
{
var host = CreateHostBuilder(args).Build();
host.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Host terminated unexpectedly");
Console.WriteLine("Press any key to close the application...");
Console.ReadKey();
}
finally
{
Log.CloseAndFlush();
}
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Tried to log, as can be seen, but it just shows that program starts and listens.
curl -X POST -H "Content-Type: application/json" -d '{"Login":"testuser","Password":"testpassword"}' https://<domain>/APIInjector/api/users/register
returns just error 500 without any details, with that login error in the event logs server-side
Solution
Hosting Bundle Installer - that what was missing. After restart API started to react and tell the errors properly. The error with login turned out to be a completely separate issue, coming from the database scaling service - it was not properly set up by me. The API itself was just not running, but after installing the HBI requests to the domain brought it to life.
Answer found in the thread ASP.NET Core site not running on IIS, works fine from commandline, that was not marked as solved for some reason.
Answered By - Void Seeker Answer Checked By - David Goodson (WPSolving Volunteer)