Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Sep 19, 2018 @ 06:55
    Bjarne Fyrstenborg
    0

    Access UmbracoContext in Hangfire

    I have a Hangfire background task to export some data from Umbraco daily. It seems Hangfire needs to have a parameter constructor to execute the method/task in this class.

    It works with the following, when using ContextHelper.EnsureUmbracoContext(), but maybe there is a better way to handle this?

    public class ExportService
    {
        private readonly ApplicationContext _applicationContext;
        private readonly UmbracoContext _umbracoContext;
        private readonly ILogger _logger;
    
        //public GeckoExportService() : this(UmbracoContext.Current)
        //{
    
        //}
    
        // Hangfire needs a parameterless constructor
        public ExportService()
        {
            _umbracoContext = ContextHelper.EnsureUmbracoContext();
        }
    
        public ExportService(UmbracoContext umbracoContext)
        {
            _umbracoContext = umbracoContext ?? throw new ArgumentNullException("umbracoContext");
    
            _applicationContext = _umbracoContext.Application;
    
            _logger = _applicationContext.ProfilingLogger.Logger;
        }
    
        public void ExportData()
        {
    
        }
    }
    

    ...

    public static class ContextHelper
    {
        public static UmbracoContext EnsureUmbracoContext()
        {
            if (UmbracoContext.Current != null)
                return UmbracoContext.Current;
    
            var dummyHttpContext = new HttpContextWrapper(new HttpContext(new SimpleWorkerRequest("/", string.Empty, new StringWriter())));
    
            return UmbracoContext.EnsureContext(dummyHttpContext,
                    ApplicationContext.Current,
                    new WebSecurity(dummyHttpContext, ApplicationContext.Current),
                    UmbracoConfig.For.UmbracoSettings(),
                    UrlProviderResolver.Current.Providers,
                    false);
        }
    }
    

    and then in Umbraco then following Hangfire configuration:

    public class UmbracoStandardOwinStartup : UmbracoDefaultOwinStartup
    {
        public override void Configuration(IAppBuilder app)
        {
            // Ensure the default options are configured
            base.Configuration(app);
    
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/")
            });
    
            // Configure the database where Hangfire is going to create its tables
            var options = new SqlServerStorageOptions { PrepareSchemaIfNecessary = true };
            var connectionString = ApplicationContext.Current.DatabaseContext.ConnectionString;
            GlobalConfiguration.Configuration.UseSqlServerStorage(connectionString, options);
    
            // Configure Hangfire dashboard
            var dashboardOptions = new DashboardOptions { Authorization = new[] { new UmbracoAuthorizationFilter() } };
            app.UseHangfireDashboard("/hangfire", dashboardOptions);
    
            // Create a default Hangfire server
            app.UseHangfireServer();
    
            // Schedule jobs
            var scheduler = new ScheduleHangfireJobs();
            scheduler.ExportData();
        }
    
    }
    
    public class ScheduleHangfireJobs
    {
        RecurringJobManager manager = new RecurringJobManager();
    
        [DisableConcurrentExecution(timeoutInSeconds: 60)]
        [AutomaticRetry(Attempts = 3)]
        public void ExportData()
        {
            string timer = "00 23 * * *";
    
            var service = new ExportService(UmbracoContext.Current);
    
            manager.AddOrUpdate("Fetch Data", Job.FromExpression(() => service.ExportData()), timer);
        }
    }
    

    /Bjarne

  • John Bergman 483 posts 1132 karma points
    Sep 19, 2018 @ 07:04
    John Bergman
    0

    Hey Bjarne,

    We do something similar. Instead of determining how to get the umbraco context inside of the hangfire task, I actually wrote it as a "maintenance" page in the CMS, then the background task simply calls the web page to do the work. Made implementation a breeze :-).

  • Ranjit J. Vaity 66 posts 109 karma points
    Dec 08, 2019 @ 14:02
    Ranjit J. Vaity
    0

    Hello John,

    Can you please point to some code snippet or example page that you might have shared?

    Thank you!

    @Bjarne Thank you too for sharing....

    Regards, Ranjit

  • John Bergman 483 posts 1132 karma points
    Dec 09, 2019 @ 00:54
    John Bergman
    1

    Here is the EnsureUmbracoContext we use

        /// <summary>
    /// Ensure there is an umbraco context for cases where we dont have one
    /// 
    /// Based on:  https://gist.github.com/sniffdk/7600822
    /// 
    /// Other references for creating an UmbracoContext / UmbracoHelper
    ///   https://staheri.com/my-blog/2015/march/custom-examine-indexing-using-umbraco-cache/
    ///   https://our.umbraco.com/forum/umbraco-7/using-umbraco-7/57892-IPublishedContent-and-GatheringNodeData
    /// </summary>
    public static void EnsureUmbracoContext()
    {
      if (UmbracoContext.Current == null)
      {
        var dummyHttpContext = new HttpContextWrapper(new HttpContext(new SimpleWorkerRequest("/", string.Empty, new StringWriter())));  //blah.aspx
        UmbracoContext.EnsureContext(
            dummyHttpContext,
            ApplicationContext.Current,
            new WebSecurity(dummyHttpContext, ApplicationContext.Current),
            UmbracoConfig.For.UmbracoSettings(),
            UrlProviderResolver.Current.Providers,
            false);
      }
    }
    

    And the we call it this way

        EnsureUmbracoContext();
        UmbracoHelper umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
        MembershipHelper membershipHelper = new MembershipHelper(UmbracoContext.Current);
    
  • Bjarne Fyrstenborg 1280 posts 3990 karma points MVP 7x c-trib
    Dec 10, 2019 @ 15:10
    Bjarne Fyrstenborg
    1

    Hi John

    If you already have created an instance of UmbracoHelper you don't need to create an instance of MembershipHelper, instead just access it through MembershipHelper property.

    UmbracoHelper umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
    MembershipHelper membershipHelper = umbracoHelper.MembershipHelper;
    

    /Bjarne

  • Ranjit J. Vaity 66 posts 109 karma points
    Dec 10, 2019 @ 20:28
    Ranjit J. Vaity
    0

    Hello John / Bjarne,

    Thank you very much for replies. This works like charm! :)

    I had to say, curiosity remain about Hangfire and Autofac working together.

    Say in my project have I have a derived class from UmbracoDefaultOwinStartup where I register all Recurring Jobs as below:

    RecurringJob.AddOrUpdate<ImportContentHelper>(x => x.ExcuteJob(), Cron.DayInterval(days));
    

    ImportContentHelper.cs as below

    public class ImportContentHelper
    {
        private readonly IContentImportService _contentImportService = null;
        public ImportContentHelper()
        {
            _contentImportService = new ContentImportService();
        }
    
        public void ExcuteJob()
        {
            .....
        }
    }
    

    Also I have Bootstrapper.cs where exists building of IOC container using Autofac and I registering controllers, services and UmbracoContext as well.

    I tried registering ImportContentHelper and IContentImportService/ContentImportService to the container but while ImportContentHelper ctor is called, it fails to inject an instantiated object of the IContentImportService service.

    I somehow do not agree the new keyword while i instantiate the service object. Is there any efficient way to do this or am I missing something?

    Please advise.

    Thanks again,

    Ranjit

Please Sign in or register to post replies

Write your reply to:

Draft