简体   繁体   中英

asp.net core dbcontext is disposed when timer elapsed

I have a problem with my asp.net application.

My application is supposed to webscrape a site once every day.

I'm trying to fire of a method with a timer and this method I'm trying to process needs my dbcontext to save the new data.

My method works fine if i run my application and go to the page that calls this method on request, but when the timer tries to use it my dbcontext is disposed.

My question is.. How do i configure my asp.net application so i can reuse my dbcontext in the background and not dependent to a request from a web browser?

Here is some code:

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

I think the best aproach is to instantiate the context each ellapsed time, inject the DbContextOptions<FundContext> instead of FundContext in the FundDataService constructor and do a using/new for better control:

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

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

...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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