I'm customizing the Examine members index like this:
public class CustomizeMemberIndexComponent : IComponent
{
private readonly IExamineManager _examineManager;
private BaseIndexProvider _indexProvider;
public CustomizeMemberIndexComponent(IExamineManager examineManager)
{
_examineManager = examineManager;
}
public void Initialize()
{
if (!_examineManager.TryGetIndex(Constants.UmbracoIndexes.MembersIndexName, out var index))
return;
var houseNumber = new FieldDefinition("houseNumber", FieldDefinitionTypes.Integer);
index.FieldDefinitionCollection.TryAdd(houseNumber);
}
public void Terminate()
{
}
}
This works perfectly fine when I reindex via the back-office; the houseNumber property is indexed as number.
But whenever the index gets recreated (which occurs on Azure), the houseNumber property is not index as number, but as FullTextType.
I guess it's a timing issue and maybe I have to use the ComposeAfter attribute, but with what argument?
Still no joy :-( Works fine on my machine, does not work fine on Azure and the production environment is having issues because of this :-( So frustrating!
Yeah everything is in place.
Originally the title of the topic was "not being used on boot", but it's not in effect at all right now on prod. So when I rebuild the index manually, the houseNumber field will end up as a string every single time :-(
I'm out of ideas here. FYI here's the current complete class:
using System;
using System.Linq;
using Examine;
using Examine.Providers;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Examine;
namespace Website.Core.Components
{
public class CustomizeMemberIndexComposer : IUserComposer
{
public void Compose(Composition composition)
{
composition.RegisterUnique<IUmbracoIndexConfig, CustomMemberIndexConfig>();
composition.Components().Append<CustomizeMemberIndexComponent>();
}
}
public class CustomizeMemberIndexComponent : IComponent
{
private readonly IExamineManager _examineManager;
private readonly ILogger _logger;
private BaseIndexProvider _indexProvider;
public CustomizeMemberIndexComponent(IExamineManager examineManager, ILogger logger)
{
_examineManager = examineManager;
_logger = logger;
}
public void Initialize()
{
if (!_examineManager.TryGetIndex(Constants.UmbracoIndexes.MembersIndexName, out var index))
{
_logger.Error<CustomizeMemberIndexComponent>($"Index {Constants.UmbracoIndexes.MembersIndexName} not found");
return;
}
var houseNumber = new FieldDefinition("houseNumber", FieldDefinitionTypes.Integer);
index.FieldDefinitionCollection.AddOrUpdate(houseNumber);
_logger.Info<CustomizeMemberIndexComponent>($"Added houseNumber with type Integer to {Constants.UmbracoIndexes.MembersIndexName}");
//we need to cast because BaseIndexProvider contains the TransformingIndexValues event
if (!(index is BaseIndexProvider indexProvider))
throw new InvalidOperationException("Could not cast");
_indexProvider = indexProvider;
_indexProvider.TransformingIndexValues += IndexProviderOnTransformingIndexValues;
}
public void Terminate()
{
if (_indexProvider != null)
{
_indexProvider.TransformingIndexValues -= IndexProviderOnTransformingIndexValues;
}
}
private static void IndexProviderOnTransformingIndexValues(object sender, IndexingItemEventArgs e)
{
if (e.ValueSet.Category != IndexTypes.Member || !e.ValueSet.Values.ContainsKey("zipcode")) return;
var zipcodeField = e.ValueSet.Values.Single(x => x.Key == "zipcode");
e.ValueSet.Set("zipcode", zipcodeField.Value.Single().ToString().Replace(" ", string.Empty));
}
}
public class CustomMemberIndexConfig : UmbracoIndexConfig, IUmbracoIndexConfig
{
public CustomMemberIndexConfig(IPublicAccessService publicAccessService) : base(publicAccessService)
{
}
IValueSetValidator IUmbracoIndexConfig.GetMemberValueSetValidator()
{
var excludeFields = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Keys;
return new MemberValueSetValidator(null, null, null, excludeFields);
}
}
}
I am not that familiar with the member indexing in V8.
Is houseNumber a property on your member ? And does that end up in the index without your custom code ?
So it might be a long shot, but could you try to remove it from the fieldcollection if it exists and add it.
Instead of AddOrUpdate ?
Also setting your composer using the ComposeAfter attribute and look in to the Umbraco source code where it builds the examine member index.
So that you are sure your code runs last. Could be a race condition.
With the debugger attached I see the houseNumber field has not been added yet at the point I'm adding it to the fieldcollection.
Also tried ComposeAfter, didn't help.
So on my local machine it always works correctly, also with a cold boot. On Azure it works 5 to 10% of the time. So it is some kind of timing issue I guess.
Anyway, I worked around it by creating a custom members index with the fields I need. Which is also a whole lot quicker to (re)build than the members index. Like a few seconds vs. 10 to 15 minutes.
Which leads me to believe that Umbraco starts processing cache refresher instructions before the full boot sequence is complete thus locking the ability to change field types prematurely. I'm investigating this and will see what I can find.
Side note - please be sure to also implement IUserComposer when using ComponentComposer since that only implements IComposer by default and typically all end user composers should be IUserComposer and prob also best to attribute with [RuntimeLevel(MinLevel = RuntimeLevel.Run)] since in most cases you don't want yours running during install/upgrade phases.
Nope. IUserComposer and RuntimeLevelAttribute are 2 different mechanisms.
All IUserComposer does is ensure that it's run (along with any components it registers) after Umbraco's core composers. It's just an ordering thing.
Also note, you will get an exception if you use ComposeAfter for a composer that has RuntimeLevelAttribute values that are different to the ones declared on your own composer.
By default, any IUserComposer uses the Minimum Runtime Level of Run & thus does not need to explicitly add the attribute as shown in the example below.
Customize Examine index - not being used on boot
I'm customizing the Examine members index like this:
This works perfectly fine when I reindex via the back-office; the houseNumber property is indexed as number. But whenever the index gets recreated (which occurs on Azure), the houseNumber property is not index as number, but as
FullTextType
.I guess it's a timing issue and maybe I have to use the
ComposeAfter
attribute, but with what argument?Hi Stefan,
What is the runtime level of your composer ?
Dave
Hey Dave!
Sorry for not including it in the snippet:
@Dave any ideas? 🤞🏼
Sorry missed the notification.
Maybe you can add the runtime attribute to your composer and set the minimum level to Run.
I have it setup that way in a project without issues for content indexes : https://our.umbraco.com/Documentation/Implementation/Composing/#runtimelevel
Dave
I've also switched to
IUserComposer
, doing some tests right now. I'll add the runtime attribute just in case as well, thanks.Still no joy :-( Works fine on my machine, does not work fine on Azure and the production environment is having issues because of this :-(
So frustrating!
Hi Stefan,
Do you have all the correct settings configured for hosting on Azure ?
https://our.umbraco.com/documentation/Getting-Started/Setup/Server-Setup/azure-web-apps
Dave
Yeah everything is in place.
Originally the title of the topic was "not being used on boot", but it's not in effect at all right now on prod. So when I rebuild the index manually, the
houseNumber
field will end up as a string every single time :-(I'm out of ideas here. FYI here's the current complete class:
Hi Stefan,
I am not that familiar with the member indexing in V8.
Is houseNumber a property on your member ? And does that end up in the index without your custom code ?
So it might be a long shot, but could you try to remove it from the fieldcollection if it exists and add it.
Instead of AddOrUpdate ?
Also setting your composer using the ComposeAfter attribute and look in to the Umbraco source code where it builds the examine member index. So that you are sure your code runs last. Could be a race condition.
Dave
With the debugger attached I see the houseNumber field has not been added yet at the point I'm adding it to the fieldcollection.
Also tried
ComposeAfter
, didn't help.So on my local machine it always works correctly, also with a cold boot. On Azure it works 5 to 10% of the time. So it is some kind of timing issue I guess.
Anyway, I worked around it by creating a custom members index with the fields I need. Which is also a whole lot quicker to (re)build than the members index. Like a few seconds vs. 10 to 15 minutes.
What version of Umbraco are you on ? I know in the latest version several fixes have been merged regarding the indexing of the members index.
It's v8.8.4. Can you point me in the direction of those fixes? Sounds interesting!
Hi Stefan,
I see fixes related to member index in following releases : https://our.umbraco.com/download/releases/891 https://our.umbraco.com/download/releases/8120
But there are some more examine related fixes in other releases as well.
Dave
I'll do an upgrade soon :-)
This sounds very similar to the issue discussed here:
https://github.com/umbraco/UmbracoDocs/issues/3115#issuecomment-819138962
https://github.com/umbraco/Umbraco-CMS/issues/8893#issuecomment-819461693
Which leads me to believe that Umbraco starts processing cache refresher instructions before the full boot sequence is complete thus locking the ability to change field types prematurely. I'm investigating this and will see what I can find.
Side note - please be sure to also implement IUserComposer when using
ComponentComposer
since that only implements IComposer by default and typically all end user composers should be IUserComposer and prob also best to attribute with[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
since in most cases you don't want yours running during install/upgrade phases.Isn't the
IUserComposer
usingRuntimeLevel.Run
by design already?Nope. IUserComposer and RuntimeLevelAttribute are 2 different mechanisms.
All IUserComposer does is ensure that it's run (along with any components it registers) after Umbraco's core composers. It's just an ordering thing.
Also note, you will get an exception if you use
ComposeAfter
for a composer that hasRuntimeLevelAttribute
values that are different to the ones declared on your own composer.Then the docs are wrong about it: https://our.umbraco.com/documentation/implementation/composing/#runtimelevel
Interesting! Guess they're right, didn't realize the code did this check https://github.com/umbraco/Umbraco-CMS/blob/d428a4543f33bb7094cf7db5f6b6fdc2d1de3063/src/Umbraco.Core/Composing/Composers.cs#L129
is working on a reply...