8/29/23: I will apply the suggestions mentioned in the comments below.
- Added Using Statement where I omitted it.
- Removing the While loop and using another page or project to trigger the call in a manner simulating the page being hit repeatedly.
- I will look at migrating to a Code First approach, but I have always built the DB first as that is what I am used to doing.
That said...
Please help me understand why this case keeps getting closed as I have a very real problem that is extremely difficult to solve. When I post the details as I understand them my case keeps getting closed.
I have no debug information. That is the crux of the issue. Normal debugging information in the form of exceptions or log entries are not being generated. If they were, I would use them to find the cause, but the are not.
So what do I need to do to get this issue open and available for ideas?
I am doing the best I can yet it keeps getting closed. Please help me get it solved, as this is killing our development plans.
Code is now at end of the post.
My question is:
How do I debug an issue that does not produce any debugging information, does not throw exceptions and simply produces a 'service unavailable' message when it fails?
No information is logged no matter what I do. I have a couple of other posts on this where I was told to build a Minimal Reproduction Project, that is what this post is about. I have that, but do not see how to attach it to the post. It will reproduce this issue and will crash without any logging data or exceptions thrown.
Background:
I have been fighting with Blazor and EF for months now trying to get it to work reliably and no matter what I do it crashes after repeated page accesses.
I have a DB and a minimal repro that will crash after the page is refreshed roughly 250 - 300 times. This is greatly reduced if the DB has more data and more complexity, in my actual app it will fail after less than 50 hits, sometimes around 20.
I have eliminated all known issues like misuses of dependency injection, I have simplified the DB down to a single table with 2 fields and one row, I have scoured the internet and taken all manner of feedback to no avail. It still crashes without any debugging information.
I am desperate for a solution. I am many months behind schedule as a result of this, and I have invested a great deal of time in learning Blazor/EF so there will be a lot of 'sunk cost' if I have to bail and find some other framework.
Please advise.
Program.cs:
using BlazorDbTest.Data;
using BlazorDbTest.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("development");
builder.Services.AddDbContextFactory<BttestContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<AccountUtilitiesService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.MapControllers();
app.Run();
Controller:
using BlazorDbTest.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace BlazorDbTest.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class GetAccountEmailController : ControllerBase
{
private readonly AccountUtilitiesService _accountUtilitiesService;
private static int counter = 0;
public GetAccountEmailController(AccountUtilitiesService accountUtilitiesService)
{
_accountUtilitiesService = accountUtilitiesService;
}
[HttpGet]
public IActionResult GetEmail(string AccountID)
{
bool stillworking = true;
string email = string.Empty;
while(stillworking) //<<<--- this is here to avoide having to click the Refresh button 250 or so times. It will crash with or without this loop.
{
counter++;
stillworking = false;
try
{
email = _accountUtilitiesService.GetAccountEmail(AccountID)+ "\nCount: " + counter;
stillworking = true;
}
catch (Exception e)
{
email += e.Message;
}
}
if(!stillworking)
{
email = "Failed after " + counter + " Hits";
}
return Ok(email);
}
}
}
Service:
using BlazorDbTest.Data;
using Microsoft.EntityFrameworkCore;
namespace BlazorDbTest.Services
{
public class AccountUtilitiesService : IDisposable
{
private readonly IDbContextFactory<BttestContext> _dbContextFactory;
public AccountUtilitiesService(IDbContextFactory<BttestContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
}
public string? GetAccountEmail(string accountId)
{
string? email = "Account not found";
if (!string.IsNullOrEmpty(accountId))
{
int? accountID = int.Parse(accountId);
using BttestContext bttestContext = _dbContextFactory.CreateDbContext();
email = bttestContext.Accounts.FirstOrDefault(a=>a.AccountId == accountID)?.Email;
}
return email;
}
public void Dispose()
{
// TODO release managed resources here
}
}
}
DB Context:
using System;
using System.Collections.Generic;
using BlazorDbTest.Models;
using Microsoft.EntityFrameworkCore;
namespace BlazorDbTest.Data;
public partial class BttestContext : DbContext
{
public BttestContext()
{
}
public BttestContext(DbContextOptions<BttestContext> options)
: base(options)
{
}
public virtual DbSet<Account> Accounts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
{
var builder = WebApplication.CreateBuilder();
var connectionString = builder.Configuration.GetConnectionString("development");
optionsBuilder.UseSqlServer(connectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("db_owner");
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
Account.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace BlazorDbTest.Models;
[Keyless]
[Table("Accounts", Schema = "dbo")]
public partial class Account
{
[Column("Account_ID")]
public int? AccountId { get; set; }
[Column("Email")]
public string Email { get; set; }
}
Connection String:
"server=tcp:Geckoserver;Data Source=GECKOSERVER\\SQLBT;Initial Catalog=BTTest; Integrated Security=False; Persist Security Info=True;User ID=BT_Mgr;Password=;Encrypt=False;TrustServerCertificate=True; MultipleActiveResultSets=True" //Integrated Security=True;