Reputation: 336
I am developing a Blazor WebAssembly app. I am targeting .NET 5.0, publishing to a folder via VS 2019. My web server is IIS 8 on Windows Server 2012 R2. If it matters, the app will only be accessible within our corporate intranet.
The current status of the app is that it has the default counter and weather forecasting, although I have changed the weather forecasting to query an SQL database. This weather forecast querying is done via HTTP requests as shown in this Youtube tutorial (with some relevant code included below). I have added a second set of data for querying, also performed via HTTP requests.
My problem is that I can fetch the data (and do CRUD on it) just fine when I launch the app from within VS 2019 and the SQL server is hosted on that same development workstation. However, when I publish out to IIS, I run into problems.
Specifically, if the SQL Server is on my development workstation, I get the exception "Response status code does not indicate success: 404 (Not Found)." Looking to the Network part of the Console, I see a 404 on http://[my IIS server's network-accessible name]:5001/api/weatherforecast. That particular page loads just fine when launching from VS 2019 on my development machine.
One of my thoughts is that it might be an issue with the authentication for SQL Server Express. When pointed at my local workstation, it was using Windows Authentication, via the following connection string:
"Default": "Data Source = [my development workstation's name]; Initial Catalog = blazorTest; Integrated Security = True; MultipleActiveResultSets = True"
To test this, I set up SQL Server Express 2012 on the virtual server (with mixed mode authentication), and changed the connection string to:
"Data Source=[virtual server's name]; Initial Catalog=blazorTest; User Id=sa; Password=[super-secure password]"
Now, I get a different error when attempting to access the weather forecasts, specifically:
"Failed to load resource: the server responded with a status of 400 ()"
Oddly, this appears to be an uncaught exception and not a Console.Writeline(ex.Message) like I was seeing before. The uncaught exception references /api/weatherforecast.
Here is the code for the weather forecast API (CART is the name of the application):
using CART.Server.Data_Access_Layer;
using CART.Shared;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace CART.Server.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private readonly WeatherDbContext _context;
public WeatherForecastController(ILogger<WeatherForecastController> logger, WeatherDbContext context)
{
_logger = logger;
_context = context;
}
[HttpGet]
public async Task<IActionResult> Get()
{
try
{
List<WeatherForecast> forecasts = await _context.Forecasts.ToListAsync();
return Ok(forecasts);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return BadRequest();
}
[HttpGet]
[Route("{id}")]
public async Task<IActionResult> GetById(int id)
{
try
{
WeatherForecast forecast = await _context.Forecasts.Where(f => f.Id == id).FirstOrDefaultAsync();
return Ok(forecast);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return BadRequest();
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] WeatherForecast forecast)
{
try
{
_context.Forecasts.Add(forecast);
await _context.SaveChangesAsync();
return Ok(forecast);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return BadRequest();
}
[HttpPut]
[Route("{id}")]
public async Task<IActionResult> Update(int id, WeatherForecast updatedForecast)
{
try
{
_context.Forecasts.Update(updatedForecast);
await _context.SaveChangesAsync();
return Ok(updatedForecast);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return BadRequest();
}
[HttpDelete]
[Route("{id}")]
public async Task<IActionResult> Delete(int id)
{
try
{
WeatherForecast forecast = await _context.Forecasts.Where(f => f.Id == id).FirstOrDefaultAsync();
_context.Forecasts.Remove(forecast);
await _context.SaveChangesAsync();
return Ok(forecast);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return BadRequest();
}
}
}
So, it appears to me that none of the tries are throwing exceptions (as I'd see a Console.WriteLine(ex.message) in such a case), but yet the return within the try is not being reached. Instead the return BadRequest is being reached, and that's causing its own exception in other code. But how can that be? I suspect I'm misunderstanding something here.
And just as importantly, what do I need to change / investigate in order to get this working?
ETA: It turns out the SQL Server on the virtual server was not configured to allow remote connections. Following this link's answers I was able to get the basic SQL fetching of data to work again within Visual Studio where it talked with a remote SQL Server. However, when I publish to the virtual server I continue to get "Response status code does not indicate success: 404 (Not Found)
. Further, the URL of http://[virtual server name]:5001/api/weatherforecast gets a 404.
Upvotes: 0
Views: 888
Reputation: 336
It turns out the SQL Server on the virtual server was not configured to allow remote connections. Following this link's answers I was able to get the basic SQL fetching of data to work again.
However, I ran into another problem with the fact that api/weatherforecast would not get routed under IIS 8.5 or Apache 2.4 (the two web servers running on different ports on the virtual server). That page would get successfully routed under IIS Express 10 or Kestrel (the two web servers what could be launched within Visual Studio).
So, I decided to use Kestrel as the web server on the virtual server.
I added the UseKestrel and UseUrls lines to Program.cs in the Server project:
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.UseKestrel();
webBuilder.UseUrls("http://localhost:5000", "http://[virtual server's network name]:5000");
webBuilder.UseStartup<Startup>();
});
}
Then I copied the entire solution over into C:\inetpub on the virtual server. (I suspect I could have used any directory for it, though.) I then installed .NET 5.0 SDK on the virtual server, opened a command prompt on the virtual server, and ran dotnet run
while in C:\inetpub\Server (aka the folder where the Server part of my Blazor solution resided).
At that point I was finally able to access my app from the virtual server and have it retrieve SQL data from an SQL server on the virtual server!
Upvotes: 0