繁体   English   中英

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

[英]How to access the DbContext fom asp.net core service

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

因此,如果我从 Visual Studio (2019) 打开默认的 blazor 应用程序,我会得到类似 Startup 的信息

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());
        }
    }
}

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

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; }
    }
}

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

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

您的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();
    }
}

关于你的服务生命周期,它取决于你的使用情况,但它永远不应该比它的内部服务生命周期更粗略。 因此,您的服务可以是scopedtransient ,但不是singleton因为您的 DbContext 声明为scoped (当然,由于并发问题,您永远不应该将 DbContext 声明为singleton )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM