using Examine;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Search;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Controllers
{
public class AFMembersIndexComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Components().Append<AFMembersIndexComponent>();
composition.RegisterUnique<AFMembersIndexComponent, AFMembersIndexCreator>();
}
}
}
MY CUSTOM COMPONENT
using Examine;
using Umbraco.Core;
using Umbraco.Core.Composing;
using static Umbraco.Core.Constants;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Controllers
{
public class AFMembersIndexComponent : IComponent
{
private readonly IExamineManager _examineManager;
private readonly AFMembersIndexCreator _afMembersIndexCreator;
public AFMembersIndexComponent(IExamineManager examineManager, AFMembersIndexCreator afMembersIndexCreator)
{
_examineManager = examineManager;
_afMembersIndexCreator = afMembersIndexCreator;
}
public void Initialize()
{
// get the AFMembersIndex
if (!_examineManager.TryGetIndex("AFMembersIndex", out IIndex AFMembersIndex))
return;
// add a custom field type
AFMembersIndex.FieldDefinitionCollection.TryAdd(new FieldDefinition("memberName", FieldDefinitionTypes.FullText));
AFMembersIndex.FieldDefinitionCollection.TryAdd(new FieldDefinition("memberSurname", FieldDefinitionTypes.Double));
// modify an existing field type (not recommended)
//index.FieldDefinitionCollection.AddOrUpdate(new FieldDefinition("parentID", FieldDefinitionTypes.FullText));
_examineManager.AddIndex(AFMembersIndex);
}
public void Terminate() { }
}
}
MY CUSTOM CREATOR
using System.Collections.Generic;
using System.Linq;
using Examine;
using Lucene.Net.Analysis;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Search;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Controllers
{
public class AFMembersIndexCreator : LuceneIndexCreator, IUmbracoIndexesCreator
{
private readonly IProfilingLogger _profilingLogger;
private readonly ILocalizationService _localizationService;
private readonly IPublicAccessService _publicAccessService;
// Since Umbraco 8 has dependency injection out of the box, we can use it to inject
// the different services that we need.
public AFMembersIndexCreator(IProfilingLogger profilingLogger,
ILocalizationService localizationService,
IPublicAccessService publicAccessService,
IMemberService memberService,
IUmbracoIndexConfig umbracoIndexConfig)
{
_profilingLogger = profilingLogger;
_localizationService = localizationService;
_publicAccessService = publicAccessService;
}
// Noticed that we return a collection of indexes? Technically you
// can create multiple indexes in an indexCreator :) You can have a look at
// UmbracoIndexesCreator.cs in the CMS core and see how the CMS does that.
public override IEnumerable<IIndex> Create()
{
// create my AFMemberIndex definitions
IIndex AFMemberIndex = CreateAFMemberIndex();
return new[] { AFMemberIndex };
}
private IIndex CreateAFMemberIndex()
{
UmbracoMemberIndex AFMembersIndex = new UmbracoMemberIndex("AFMembersIndex",
new UmbracoFieldDefinitionCollection(),
CreateFileSystemLuceneDirectory("AFMembersIndex"),
new WhitespaceAnalyzer(),
_profilingLogger,
new MemberValueSetValidator());
return AFMembersIndex;
}
}
}
When I try to start Umbraco I receive following error after process my composer (the component and the creator aren't called):
Can anyone help me?
It would also be okay to override the default MemberIndex to include the custom fields
With Umbraco 7 it was very simple to create a new Cusom Index and I never had problems...with Umbraco 8 I can't!!! :-s
{"@t":"2021-03-02T16:28:05.5911281Z","@mt":"{FailMessage} ({Duration}ms) [Timing {TimingId}]","@l":"Error","@x":"Umbraco.Core.Exceptions.BootFailedException: Boot failed. ---> System.ArgumentOutOfRangeException: The implementing type AF.Examine.Index.Tools.For.UmbracoV8.Controllers.AFMembersIndexCreator is not assignable from AF.Examine.Index.Tools.For.UmbracoV8.Controllers.AFMembersIndexComponent.\r\nNome parametro: implementingType\r\n in LightInject.ServiceContainer.EnsureConstructable(Type serviceType, Type implementingType)\r\n in LightInject.ServiceContainer.RegisterService(Type serviceType, Type implementingType, ILifetime lifetime, String serviceName)\r\n in Umbraco.Core.Composing.LightInject.LightInjectContainer.Register(Type serviceType, Type implementingType, Lifetime lifetime)\r\n in Umbraco.Core.Composing.Composition.<>c__DisplayClass37_0.<RegisterUnique>b__0(IRegister register)\r\n in Umbraco.Core.Composing.Composition.CreateFactory()\r\n in Umbraco.Core.Runtime.CoreRuntime.Boot(IRegister register, DisposableTimer timer)\r\n --- Fine della traccia dello stack dell'eccezione interna ---","FailMessage":"Boot failed.","Duration":199099,"TimingId":"e10d37d","SourceContext":"Umbraco.Core.Runtime.CoreRuntime","ProcessId":7936,"ProcessName":"iisexpress","ThreadId":1,"AppDomainId":2,"AppDomainAppId":"LMW3SVC3ROOT","MachineName":"VP-FABRI","Log4NetLevel":"ERROR","HttpRequestNumber":1,"HttpRequestId":"96c94f7c-01f1-4347-831e-fa789feb913a"}
Just a word of advice: To get help in an international forum, you really cant post stacktraces that are written in Italian. I can see you have a null reference somewhere, but not easy to understand that screenshot.
Hi Rodolphe,
I'm sorry but I configured VS2019, IIS and IIS Express in english language but I really don't know why the stack messages are still in Italian language.
This is a quick overview of all the bits I've got when I create a custom index:
Component
internal class MyCustomIndexComponent : IComponent
{
private readonly IExamineManager _examineManager;
private readonly MyCustomIndexCreator _myCustomIndexCreator;
public MyCustomIndexComponent (IExamineManager examineManager, MyCustomIndexCreator myCustomIndexCreator)
{
_examineManager = examineManager;
_myCustomIndexCreator = myCustomIndexCreator;
}
public void Initialize()
{
foreach (var index in _myCustomIndexCreator .Create())
_examineManager.AddIndex(index);
}
public void Terminate()
{
}
}
Creator
public class MyCustomIndexCreator : LuceneIndexCreator
{
public override IEnumerable<IIndex> Create()
{
var index = new LuceneIndex("MyIndexName",
CreateFileSystemLuceneDirectory("MyIndexName"),
new FieldDefinitionCollection(
new FieldDefinition("Id", FieldDefinitionTypes.FullText),
new FieldDefinition("Code", FieldDefinitionTypes.FullTextSortable),
new FieldDefinition("Name", FieldDefinitionTypes.FullText),
new FieldDefinition("Family", FieldDefinitionTypes.FullTextSortable),
new FieldDefinition("SortOrder", FieldDefinitionTypes.Integer),
new FieldDefinition("Details", FieldDefinitionTypes.FullText)
),
new StandardAnalyzer(Version.LUCENE_30));
return new[] { index };
}
}
I've also got a Populator and ValueSetBuilder for actually putting data into the index.
Looking at your code, it doesn't look like you are registering your creator properly.
Yeah...I had to modify the creator and the composer as you told me but also I had to create the Populator and the ValueSetBuilder as well.
So...I want to share the code to help anyone who needs it ;-)
Thank you again.
A.
Composer
using AF.Examine.Index.Tools.For.UmbracoV8.Components;
using AF.Examine.Index.Tools.For.UmbracoV8.Creators;
using AF.Examine.Index.Tools.For.UmbracoV8.Populators;
using AF.Examine.Index.Tools.For.UmbracoV8.ValueSetBuilders;
using Umbraco.Core;
using Umbraco.Core.Composing;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Composers
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class AFMembersIndexComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.RegisterUnique<AFMembersIndexValueSetBuilder>();
composition.Register<AFMembersIndexPopulator>(Lifetime.Singleton);
composition.RegisterUnique<AFMembersIndexCreator>();
composition.Components().Append<AFMembersIndexComponent>();
}
}
}
Component
using AF.Examine.Index.Tools.For.UmbracoV8.Creators;
using Examine;
using Umbraco.Core.Composing;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Components
{
public class AFMembersIndexComponent : IComponent
{
private readonly IExamineManager _examineManager;
private readonly AFMembersIndexCreator _afMembersIndexCreator;
public AFMembersIndexComponent(IExamineManager examineManager, AFMembersIndexCreator afMembersIndexCreator)
{
_examineManager = examineManager;
_afMembersIndexCreator = afMembersIndexCreator;
}
public void Initialize()
{
// Try get the AFMembersIndex
if (!_examineManager.TryGetIndex("AFMembersIndex", out IIndex AFMembersIndex))
{
// add AFMembersIndex to examineManager
foreach (var index in _afMembersIndexCreator.Create())
_examineManager.AddIndex(index);
}
}
public void Terminate() { }
}
}
Creator
using Examine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Util;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Search;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Creators
{
public class AFMembersIndexCreator : LuceneIndexCreator, IUmbracoIndexesCreator
{
private readonly IProfilingLogger _profilingLogger;
private readonly ILocalizationService _localizationService;
private readonly IPublicAccessService _publicAccessService;
// Since Umbraco 8 has dependency injection out of the box, we can use it to inject
// the different services that we need.
public AFMembersIndexCreator(IProfilingLogger profilingLogger,
ILocalizationService localizationService,
IPublicAccessService publicAccessService,
IMemberService memberService,
IUmbracoIndexConfig umbracoIndexConfig)
{
_profilingLogger = profilingLogger;
_localizationService = localizationService;
_publicAccessService = publicAccessService;
}
// Noticed that we return a collection of indexes? Technically you
// can create multiple indexes in an indexCreator :) You can have a look at
// UmbracoIndexesCreator.cs in the CMS core and see how the CMS does that.
public override IEnumerable<IIndex> Create()
{
// create my AFMemberIndex definitions
return new[] { CreateAFMemberIndex() };
}
private IIndex CreateAFMemberIndex()
{
var AFMembersIndex = new LuceneIndex("AFMembersIndex",
CreateFileSystemLuceneDirectory("AFMembersIndex"),
new FieldDefinitionCollection(
new FieldDefinition("memberId", FieldDefinitionTypes.FullText),
new FieldDefinition("memberNodeName", FieldDefinitionTypes.FullText),
new FieldDefinition("memberLoginName", FieldDefinitionTypes.FullText),
new FieldDefinition("memberEmail", FieldDefinitionTypes.FullText),
new FieldDefinition("memberName", FieldDefinitionTypes.FullText),
new FieldDefinition("memberSurname", FieldDefinitionTypes.FullText),
new FieldDefinition("memberIntTel", FieldDefinitionTypes.FullText),
new FieldDefinition("memberFax", FieldDefinitionTypes.FullText),
new FieldDefinition("memberCel", FieldDefinitionTypes.FullText),
),
new StandardAnalyzer(Version.LUCENE_30));
return AFMembersIndex;
}
}
}
Populator
using AF.Examine.Index.Tools.For.UmbracoV8.Models;
using AF.Examine.Index.Tools.For.UmbracoV8.ValueSetBuilders;
using Examine;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Examine;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Populators
{
public class AFMembersIndexPopulator : IndexPopulator<IUmbracoMemberIndex>
{
private readonly AFMembersIndexValueSetBuilder _afMembersIndexValueSetBuilder;
private readonly IMemberService _memberService;
public AFMembersIndexPopulator(AFMembersIndexValueSetBuilder AFValueSetBuilder, IMemberService memberService)
{
_memberService = memberService;
_afMembersIndexValueSetBuilder = AFValueSetBuilder;
RegisterIndex("AFMembersIndex");
}
protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
{
if (indexes.Count == 0) return;
const int pageSize = 1000;
var pageIndex = 0;
IMember[] members;
//no node types specified, do all members
do
{
members = _memberService.GetAll(pageIndex, pageSize, out _).ToArray();
if (members.Length > 0)
{
// ReSharper disable once PossibleMultipleEnumeration
foreach (var index in indexes)
index.IndexItems(_afMembersIndexValueSetBuilder.GetValueSets((IMember[])members));
}
pageIndex++;
} while (members.Length == pageSize);
}
}
}
ValueSetBuilder
using AF.Examine.Index.Tools.For.UmbracoV8.Models;
using Examine;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Examine;
namespace AF.Examine.Index.Tools.For.UmbracoV8.ValueSetBuilders
{
public class AFMembersIndexValueSetBuilder : IValueSetBuilder<IMember>
{
public IEnumerable<ValueSet> GetValueSets(params IMember[] UmbracoMembers)
{
AFMembersModel AFMembers;
foreach (var Member in UmbracoMembers)
{
AFMembers = new AFMembersModel(Member);
Dictionary<string, object> indexValues = new Dictionary<string, object>
{
["memberId"] = AFMembers.id,
["memberNodeName"] = AFMembers.nodeName,
["memberNodeTypeAlias"] = AFMembers.nodeTypeAlias,
["memberLoginName"] = AFMembers.loginName,
["memberEmail"] = AFMembers.email,
["memberName"] = AFMembers.memberName,
["memberSurname"] = AFMembers.memberSurname,
["memberIntTel"] = AFMembers.memberIntTel,
["memberFax"] = AFMembers.memberFax,
["memberCel"] = AFMembers.memberCel
};
ValueSet valueSet = new ValueSet(AFMembers.memberId.ToString(), "afMember", indexValues);
yield return valueSet;
}
}
}
}
I had to modify my Custom Index Creator as follows.
Now I have my custom index always updated.
Adriano
using Examine;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Util;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Examine;
using Umbraco.Web.Search;
namespace AF.Examine.Index.Tools.For.UmbracoV8.Creators
{
public class AFMembersIndexCreator : UmbracoIndexesCreator
{
private readonly IProfilingLogger _profilingLogger;
private readonly ILocalizationService _languageService;
private readonly IPublicAccessService _publicAccessService;
private readonly IMemberService _memberService;
private readonly IUmbracoIndexConfig _iUmbracoIndexConfig;
// Since Umbraco 8 has dependency injection out of the box, we can use it to inject
// the different services that we need.
public AFMembersIndexCreator(IProfilingLogger profilingLogger,
ILocalizationService languageService,
IPublicAccessService publicAccessService,
IMemberService memberService,
IUmbracoIndexConfig umbracoIndexConfig) : base(profilingLogger, languageService, publicAccessService, memberService, umbracoIndexConfig)
{
_profilingLogger = profilingLogger;
_languageService = languageService;
_publicAccessService = publicAccessService;
_memberService = memberService;
_iUmbracoIndexConfig = umbracoIndexConfig;
}
// Noticed that we return a collection of indexes? Technically you
// can create multiple indexes in an indexCreator :) You can have a look at
// UmbracoIndexesCreator.cs in the CMS core and see how the CMS does that.
public override IEnumerable<IIndex> Create()
{
// create my AFMembersIndex definitions
return new[] { CreateAFMembersIndex() };
}
private IIndex CreateAFMembersIndex()
{
var AFMembersIndex = new UmbracoMemberIndex(
"AFMembersIndex",
new FieldDefinitionCollection(
new FieldDefinition("memberId", FieldDefinitionTypes.FullText),
new FieldDefinition("memberNodeName", FieldDefinitionTypes.FullText),
new FieldDefinition("memberLoginName", FieldDefinitionTypes.FullText),
new FieldDefinition("memberEmail", FieldDefinitionTypes.FullText),
new FieldDefinition("memberName", FieldDefinitionTypes.FullText),
new FieldDefinition("memberSurname", FieldDefinitionTypes.FullText),
new FieldDefinition("memberIntTel", FieldDefinitionTypes.FullText),
new FieldDefinition("memberFax", FieldDefinitionTypes.FullText),
new FieldDefinition("memberCel", FieldDefinitionTypes.FullText)
),
CreateFileSystemLuceneDirectory("AFMembersIndex"),
new StandardAnalyzer(Version.LUCENE_30),
ProfilingLogger,
UmbracoIndexConfig.GetMemberValueSetValidator());
return AFMembersIndex;
}
}
}
How can I create a custom Members Index (or override the defaut) in Umbraco v8
Hi to all, I'm trying to create a custom Members Index that includes custom fields.
I write this code starting from the official guide: Umbraco Indexing Reference
MY CUSTOM COMPOSER
MY CUSTOM COMPONENT
MY CUSTOM CREATOR
When I try to start Umbraco I receive following error after process my composer (the component and the creator aren't called):
Can anyone help me? It would also be okay to override the default MemberIndex to include the custom fields
With Umbraco 7 it was very simple to create a new Cusom Index and I never had problems...with Umbraco 8 I can't!!! :-s
Thank you A.
In the UmbracoTracelog I found this info:
Just a word of advice: To get help in an international forum, you really cant post stacktraces that are written in Italian. I can see you have a null reference somewhere, but not easy to understand that screenshot.
Hi Rodolphe, I'm sorry but I configured VS2019, IIS and IIS Express in english language but I really don't know why the stack messages are still in Italian language.
Any help about it?
ok...I updated the stacktrace image with the english one.
I forced globalization to en-US in web.config
Hi Adriano,
Can you share your composer and component code please? It might be "order" you are doing things causing a null reference exception :-)
Cheers
Nik
Hi, you can find them in main post (or I don't understand the question) :-)
I posted:
Tell me if you need anything else
A.
Hi Adriano,
Try swapping these two lines around:
Basically, I think LightInject is trying to create your AFMembersIndexComponent before your AFMembersIndexGenerator is registered.
Also this line is not right,
Change it to:
With those two changes, see how you get on :)
Nik
Hi Nik, If I only swap the RegisterUnique and the components.Append lines I receive the same error as above (see the main post stacktrace)
If I follow all your indications, finally Umbraco starts but I don't see my custom Index
A.
I think you might be "missing" some bits.
This is a quick overview of all the bits I've got when I create a custom index:
Component
Creator
I've also got a
Populator
andValueSetBuilder
for actually putting data into the index.Looking at your code, it doesn't look like you are registering your creator properly.
Does this help?
Cheers
Nik
Hi Nik, thank you very much...you saved me :-)
Yeah...I had to modify the creator and the composer as you told me but also I had to create the
Populator
and theValueSetBuilder
as well.So...I want to share the code to help anyone who needs it ;-)
Thank you again.
A.
Composer
Component
Creator
Populator
ValueSetBuilder
Members Model
Congrats on getting it working Adriano #H5YR
Hi Nik,
almost everything function properly but there is a problem after new member creation.
When I try to create new AFMember, the index not rebuild after save action (I tried both in backoffice and programmatically)
Where can I put a directive to force rebuild my custom index after new AFMember creation/update?
Thanks
Adriano
SOLVED
I had to modify my Custom Index Creator as follows.
Now I have my custom index always updated.
Adriano
is working on a reply...