Create nodes in a loop in custom class ( Hangfire ) v8.6
Hi folks!
I am trying to figure what goes wrong in my code, or approach.
The short story is that I have a list of texts, and for each text I am checking if a node under a certain parentnode ( id 1077 in this case ) exists. If it doesn't I'll create a node.
This is setup in a Hangfire job and actually kinda works.
If it finds all the nodes it runs without problems, but if it need to create a node, it might run for the first 2, 3 or sometimes maybe 5 creations and then stop. Hangfire wil run again ( 10 retries ) and each time get the next bunch of nodes and maybe eventually having added all the nodes, but that is not ideal.
foreach (string txt in myListOfStrings)
{
IContentService contentService = Current.Services.ContentService;
long p = 1;
var nodeExists = contentService.GetPagedChildren(1077, 0, 10000, out p).Where(x => x.Name.ToString() == txt).Any();
if (!nodeExists)
{
var newNode = contentService.Create(txt, 1077, "color");
contentService.SaveAndPublish(newNode);
}
}
It returns a lot of exception code in hangfire. First line often being :
System.NullReferenceException: Object reference not set to an instance of an object.
I think what handfire run without umbraco context. In this case Current is null Current.Services.ContentService;
Try inject IContentService to hangfire job
I guess that might be the way to do it. I'm just really unsure how it's done. Could you guide me?
I have made this test which works. It gets the node and changes the "Name". So I guess the contentservice is not NULL :) However - cs.SaveAndPublish(someNode) will not work
public class Jobs
{
public void RunJobs()
{
RecurringJob.AddOrUpdate(() => Test(null), "0 0 31 2 0");
}
public void Test(PerformContext hangfire)
{
hangfire.WriteLine("STARTING TEST");
IContentService cs = Umbraco.Core.Composing.Current.Services.ContentService;
var someNode = cs.GetById(1077);
someNode.Name = "TEST RENAME OF NODE";
cs.Save(someNode);
}
public class Jobs
{
private IContentService _contentService;
public Jobs(IContentService contentService)
{
_contentService = contentService;
}
public void RunJobs()
{
RecurringJob.AddOrUpdate(() => Test(null), "0 0 31 2 0");
}
public void Test(PerformContext hangfire)
{
hangfire.WriteLine("STARTING TEST");
var someNode = _contentService.GetById(1077);
someNode.Name = "TEST RENAME OF NODE";
_contentService.Save(someNode);
}
}
This gives me this error
System.MissingMethodException
No parameterless constructor defined for this object.
System.MissingMethodException: No parameterless constructor defined for this object.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at Hangfire.JobActivator.SimpleJobActivatorScope.Resolve(Type type)
at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context)
at Hangfire.Server.BackgroundJobPerformer.<>cDisplayClass9_0.0()
at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func1 continuation)
at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func1 continuation)
at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable`1 filters)
at Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext context)
at Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId)
1 days effords to make it work later. I'm not sure if I'm doing it right. Injection is something I never have done before, and I'm really not sure if I'm on the right track here. Here are my files ( or at least parts of them ) :
public class UmbracoStandardOwinStartup : UmbracoDefaultOwinStartup
{
public override void Configuration(IAppBuilder app)
{
//ensure the default options are configured
base.Configuration(app);
// Configure hangfire
var options = new SqlServerStorageOptions { PrepareSchemaIfNecessary = true };
const string umbracoConnectionName = Umbraco.Core.Constants.System.UmbracoConnectionName;
var connectionString = System.Configuration
.ConfigurationManager
.ConnectionStrings[umbracoConnectionName]
.ConnectionString;
GlobalConfiguration.Configuration
.UseSqlServerStorage(connectionString, options)
.UseConsole();
// Give hangfire a URL and start the server
var dashboardOptions = new DashboardOptions { Authorization = new[] { new UmbracoAuthorizationFilter() } };
app.UseHangfireDashboard("/hangfire", dashboardOptions);
app.UseHangfireServer();
RecurringJob.AddOrUpdate<Jobs>(x => x.Test2(null), "0 0 31 2 0");
}
-
public class SiteService : ISiteService
{
public string CreateNode(string name)
{
var umbf = Umbraco.Web.Composing.Current.Factory.GetInstance<IUmbracoContextFactory>();
using (var contextf = umbf.EnsureUmbracoContext())
{
var umbcontext = contextf.UmbracoContext;
IContentService cs = Umbraco.Core.Composing.Current.Services.ContentService;
var newNode = cs.Create(name, 1077, "color");
newNode.SetValue("colorName", name + " " + name);
var res = cs.SaveAndPublish(newNode).Result.ToString();
return name + " // " + res.ToString();
}
}
}
public interface ISiteService
{
string CreateNode(string name);
}
-
public class Jobs
{
private ISiteService _siteService;
public Jobs()
{
_siteService = new SiteService();
}
public void Test2(PerformContext hangfire)
{
for (int i = 0; i < 20; i++)
{
hangfire.WriteLine(_siteService.CreateNode("Tester " + i));
}
}
}
Running the Test2 job 3 times gave these results
run : All good - 20 nodes created. Succes!
run : 12 nodes created and then this error :
System.ArgumentException: An item with the same key has already been added.
run : 14 nodes created and then this error :
System.NullReferenceException: Object reference not set to an instance of an object.
So - sometimes it works and sometimes it doesn't. Same as before.
If I do like this in the Jobs class
public class Jobs
{
private ISiteService _siteService;
public Jobs(ISiteService siteService)
{
_siteService = siteService;
}
... I just get this error immediately
System.MissingMethodException: No parameterless constructor defined for this object.
Create nodes in a loop in custom class ( Hangfire ) v8.6
Hi folks!
I am trying to figure what goes wrong in my code, or approach.
The short story is that I have a list of texts, and for each text I am checking if a node under a certain parentnode ( id 1077 in this case ) exists. If it doesn't I'll create a node.
This is setup in a Hangfire job and actually kinda works.
If it finds all the nodes it runs without problems, but if it need to create a node, it might run for the first 2, 3 or sometimes maybe 5 creations and then stop. Hangfire wil run again ( 10 retries ) and each time get the next bunch of nodes and maybe eventually having added all the nodes, but that is not ideal.
It returns a lot of exception code in hangfire. First line often being : System.NullReferenceException: Object reference not set to an instance of an object.
I think what handfire run without umbraco context. In this case Current is null Current.Services.ContentService; Try inject IContentService to hangfire job
You can inject IContentService
https://docs.hangfire.io/en/latest/background-methods/passing-dependencies.html
Thanks for your replies Marcio and Yakov
I guess that might be the way to do it. I'm just really unsure how it's done. Could you guide me?
I have made this test which works. It gets the node and changes the "Name". So I guess the contentservice is not NULL :) However - cs.SaveAndPublish(someNode) will not work
I Job constructor you should add IContentService contentService parameter and init local variable _contentService
inside Test you should use _contentService
Is it done like this ?
This gives me this error
System.MissingMethodException No parameterless constructor defined for this object. System.MissingMethodException: No parameterless constructor defined for this object. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at System.Activator.CreateInstance(Type type) at Hangfire.JobActivator.SimpleJobActivatorScope.Resolve(Type type) at Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext context) at Hangfire.Server.BackgroundJobPerformer.<>cDisplayClass9_0.0() at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func
1 continuation) at Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter filter, PerformingContext preContext, Func
1 continuation) at Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext context, IEnumerable`1 filters) at Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext context) at Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context, IStorageConnection connection, String jobId)Looks like you job in not passed via DI, you can see here good example how to define it
https://our.umbraco.com/forum/umbraco-8/96445-hangfire-dependency-injection
1 days effords to make it work later. I'm not sure if I'm doing it right. Injection is something I never have done before, and I'm really not sure if I'm on the right track here. Here are my files ( or at least parts of them ) :
-
-
Running the Test2 job 3 times gave these results
run : All good - 20 nodes created. Succes!
run : 12 nodes created and then this error : System.ArgumentException: An item with the same key has already been added.
run : 14 nodes created and then this error : System.NullReferenceException: Object reference not set to an instance of an object.
So - sometimes it works and sometimes it doesn't. Same as before.
If I do like this in the Jobs class
... I just get this error immediately
System.MissingMethodException: No parameterless constructor defined for this object.
Came across this post on faking httpcontext, and making a httpRequest to some site, seems to be making all my problems go away - even without using DI
https://our.umbraco.com/forum/extending-umbraco-and-using-the-api/76889-background-process-value-cannot-be-nullparameter-name-httpcontext
Not the prettiest solution but it works.
Maybe there is a better way? Maybe with DI?
is working on a reply...