如何访问 DbContext fom asp.net 核心服务



我有点陷入 ASP.NET 核心和实体框架及其所有(其他(组件的使用。 我正在开发一个简单的网络应用程序,您可以在其中输入一些数据并让它计算一些统计数据(基本上是 strava ultra-light(。

因此,如果我从Visual Studio(2019(打开默认的blazer应用程序,我会得到类似的东西作为启动

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using BlazorApp1.Areas.Identity;
using BlazorApp1.Data;
namespace BlazorApp1
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
services.AddSingleton<WeatherForecastService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
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.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}

像这样的东西作为服务

using System;
using System.Linq;
using System.Threading.Tasks;
namespace BlazorApp1.Data
{
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
}

所以我为我的数据添加了一个模型

using Microsoft.AspNetCore.Identity;
using BlazorApp1.Database.Types;
using System.ComponentModel.DataAnnotations;
namespace BlazorApp1.Database.Entity
{
public class Activity
{
public string ActivityData { get; set; }
public ActivityType ActivityType { get; set; }
public float Distance { get; set; }
[Key]
public int Id { get; private set; }
public IdentityUser User { get; set; }
}
}

并将其添加到 ApplicationDbContext 中

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace BlazorApp1.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Activity> Activities { get; set; }
}
}

所以现在我想创建自己的服务,类似于天气预报服务,这就是我卡住的地方。

using log4net;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using BlazorApp1.Data.Model;
using BlazorApp1.Database;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace BlazorApp1.Data
{
public class LeaderBoardService
{
private readonly static ILog _logger = LogManager.GetLogger(typeof(LeaderBoardService));

public Task<List<LeaderBoardItem>> GetOverallLeaderboard()
{
//I want to access the database context from here.
return Task.FromResult(result);
}
}
}

另外,我需要将此服务添加到 Startup.ConfigureServices(( 中。 到目前为止,我发现我可以使用services.AddScoped<LeaderBoardService>()services.AddSingleton<LeaderBoardService>()services.AddTransient<LeaderBoardService>()来完成此操作,似乎services.AddScoped<LeaderBoardService>()是最好的使用。

可能只有我有这个问题,但文档似乎缺少一些关于如何完成这个看似简单的任务的提示。

到目前为止,我查看了以下网站:

  1. https://learn.microsoft.com/en-us/aspnet/core/data/ef-rp/intro?view=aspnetcore-3.1&tabs=visual-studio
    • 但此示例中未使用任何服务。
  2. https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#using-dbcontext-with-dependency-injection
    • 尽管解决方案似乎只是将上下文作为参数添加到服务的构造函数中,但我似乎找不到如何在任何调用期间添加此参数。
  3. https://stackoverflow.com/a/48698290
    • 我不是 100% 确定这是否是我正在寻找的,但如果事实证明是,我想对如何实现这一点有一些提示。
  4. 类中 asp.net 核心访问数据库上下文
    • 这里使用了一些中间件,我想这不是我想要的。
  5. https://stackoverflow.com/a/44484724/2986756
    • 这是一个使 DbContext 瞬态的选项,也不是我想要的。
  6. https://stackoverflow.com/a/37511175
    • 此处,数据库放置在单例中。虽然我可以使用它,但我认为我不应该这样做。

您的LeaderBoardService应该这样实现:

public class LeaderBoardService
{
private readonly ApplicationDbContext dbContext;
private readonly ILogger logger;
public LeaderBoardService(ApplicationDbContext dbContext, ILogger<LeaderBoardService> logger)
{
this.dbContext = dbContext;
this.logger = logger;
}
public async Task<List<LeaderBoardItem>> GetOverallLeaderboard()
{
return await dbContext.LeaderBoardItems.ToListAsync();
}
}

关于您的服务生命周期,这取决于您的使用情况,但它绝不应该比其内部服务生命周期更具体。因此,您的服务可以是scoped的,也可以是transient的,但不能singleton,因为您的 DbContext 声明为scoped(当然,由于并发问题,您永远不应该将 DbContext 声明为singleton(。

最新更新