当计时器过去时,将释放asp.net核心dbcontext

时间:2018-03-02 17:35:13

标签: c# asp.net asp.net-mvc entity-framework dispose

我的asp.net应用程序出了问题。

我的应用程序应该每天在网站上抓一次网站。

我正在尝试使用计时器触发一个方法,而我正在尝试处理的这个方法需要我的dbcontext来保存新数据。

如果我运行我的应用程序并转到请求调用此方法的页面,我的方法可以正常工作,但是当计时器尝试使用它时,我的dbcontext被释放。

我的问题是..如何配置我的asp.net应用程序,以便我可以在后台重用我的dbcontext而不依赖于来自Web浏览器的请求?

以下是一些代码:

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<FundContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("FundContext")));

        services.AddTransient<IFundDataService, FundDataService>();

        services.AddMvc();            
    }

FundContext.cs

    public class FundContext : DbContext, IFundContext
    {
    public FundContext(DbContextOptions<FundContext> options)
        : base(options)
    {

    }

    public DbSet<Fund> Funds { get; set; }
}

FundsModel.cshtml.cs

public class FundsModel : PageModel
{
    private IFundDataService fundDataService;

    public FundsModel(IFundDataService fundDataService)
    {
        this.fundDataService = fundDataService;            
    }

    public void OnGet()
    {

    }

    public List<Fund> TodaysFundList { get { return fundDataService.TodaysFundList; } }

    public List<Fund> YesterdaysFundList { get { return fundDataService.YesterdaysFundList; } }
}

FundDataService.cs

public class FundDataService : Controller, IFundDataService
{
    private FundContext fundContext;
    private List<Fund> todaysFundList;
    private List<Fund> yesterdaysFundList;

    private static Timer timer;

    public FundDataService(FundContext fundContext)
    {
        this.fundContext = fundContext;

        GetFundFromWebAndSavetoDB();
        PopulateFundLists();

        InitializeTimer();
    }

    public List<Fund> TodaysFundList { get { return todaysFundList; } }

    public List<Fund> YesterdaysFundList{ get { return yesterdaysFundList; } }

    private void InitializeTimer()
    {
        DateTime timeNow = DateTime.Now;
        DateTime scheduledTime = new DateTime(timeNow.Year, timeNow.Month, timeNow.Day, 00, 01, 00);

        if(timeNow > scheduledTime)
        {
            scheduledTime = scheduledTime.AddDays(1);
        }

        double tickTime = 10000;/*(double)(scheduledTime - DateTime.Now).TotalMilliseconds;*/
        timer = new Timer(tickTime);
        timer.Elapsed += Timer_Elapsed;
        timer.Start();
    }

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        timer.Stop();

        GetFundFromWebAndSavetoDB();
        PopulateFundLists();

        InitializeTimer();
    }

    private void PopulateFundLists()
    {
        todaysFundList = new List<Fund>();
        yesterdaysFundList = new List<Fund>();

        foreach (var fund in fundContext.Funds)
        {
            if(fund.DateAddedToDB == DateTime.Now.Date)
            {
                todaysFundList.Add(new Fund
                {
                    ID = fund.ID,
                    Name = fund.Name,
                    RateLastDay = fund.RateLastDay,
                    RateThisYear = fund.RateThisYear,
                    LastUpdate = fund.LastUpdate,
                    DateAddedToDB = fund.DateAddedToDB
                });
            }
            if (fund.DateAddedToDB == DateTime.Now.Date.AddDays(-1))
            {
                yesterdaysFundList.Add(new Fund
                {
                    ID = fund.ID,
                    Name = fund.Name,
                    RateLastDay = fund.RateLastDay,
                    RateThisYear = fund.RateThisYear,
                    LastUpdate = fund.LastUpdate,
                    DateAddedToDB = fund.DateAddedToDB
                });
            }               
        }

        todaysFundList.Sort(delegate (Fund a, Fund b)
        {
            return b.RateThisYear.CompareTo(a.RateThisYear);
        });

        yesterdaysFundList.Sort(delegate (Fund a, Fund b)
        {
            return b.RateThisYear.CompareTo(a.RateThisYear);
        });
    }

    private void GetFundFromWebAndSavetoDB()
    {
        var rawData = WebScrapingService.Instance.WebScrapeSiteAndReturnCollection(
            "url"
            , "//tbody/tr");            

        foreach (var fund in rawData)
        {
            decimal rateLastDay;
            bool rateLastDayOK = decimal.TryParse(fund.ChildNodes[5].InnerText, out rateLastDay);

            decimal rateThisYear;
            bool rateThisYearOK = decimal.TryParse(fund.ChildNodes[11].InnerText, out rateThisYear);

            var newFund = new Fund
            {
                Name = fund.ChildNodes[3].InnerText,
                RateLastDay = rateLastDay,
                RateThisYear = rateThisYear,
                LastUpdate = Convert.ToDateTime(fund.ChildNodes[21].InnerText),
                DateAddedToDB = DateTime.Now.Date
            };

            var NumberOfFundsAddedToday = (from x in fundContext.Funds where x.DateAddedToDB == DateTime.Now.Date select x).Count();

            if(NumberOfFundsAddedToday < 5)
            {
                fundContext.Funds.Add(newFund);
                fundContext.SaveChanges();
            }                
        }            
    }
}

1 个答案:

答案 0 :(得分:1)

我认为最好的方法是在每个经过时间的情况下实例化上下文,在DbContextOptions<FundContext>构造函数中注入FundContext而不是FundDataService并使用/ new来更好地控制:< / p>

private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
...

    using(var context = new FundContext(_options)){
        GetFundFromWebAndSavetoDB(context);
        PopulateFundLists(context);  
    }

...
}