Developer forum

Forum » Development » Get root group for user in IndexBuilderExtender

Get root group for user in IndexBuilderExtender

Roald Haahr Jensen
Reply

Hi,

I am trying to use the function User.GetUserByID in an IndexBuilderExtender. However, I the following exception:

System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=Dynamicweb.Security
  StackTrace:
   at Dynamicweb.Security.UserManagement.Common.CustomFields.CustomField.GetCustomFields()
   at Dynamicweb.Security.UserManagement.Common.CustomFields.CustomField.GetCustomFields(String tableName)
   at Dynamicweb.Security.UserManagement.Common.CustomFields.CustomFieldValue.GetCustomFieldValuesFromContainer(String tableName, Object container)
   at Dynamicweb.Security.UserManagement.User.Fill(IDataReader reader)
   at Dynamicweb.Security.UserManagement.User.GetUser(CommandBuilder commandBuilder)
   at Dynamicweb.Security.UserManagement.User.GetUserByID(Int32 userID, Boolean includeAngelType)
   at Website.UserIndexExtender.ExtendDocument(IndexDocument indexDocument) in C:\Projects\Solutions\Website\Website\UserIndexExtender.cs:line 21
   at Dynamicweb.Security.UserManagement.Indexing.UserIndexBuilder.WriteDoc(IndexDocument doc, Int64 currentAutoId)
   at Dynamicweb.Security.UserManagement.Indexing.UserIndexBuilder.ProcessUsers()
   at Dynamicweb.Security.UserManagement.Indexing.UserIndexBuilder.Build(IIndexWriter writer, Tracker tracker)

And I know that the user, with the ID provided, exists.

What I am specifically trying to achieve is to add a column to the index containing information about the root group of a certain user. If a user is located in group B and group B is created as a subgroup of group A, I want the ID of group A as the value of the new field. For my problem, it does not matter that a user can be attached to multiple groups. I just take the first in the list of groups.

Is there another way to achieve this?

Best regards,
Roald, Novicell


Replies

 
Vladimir Shushunov Dynamicweb Employee
Vladimir Shushunov
Reply

Hi Roald,

Yes, I see the bug - we will fix it to next 9.6 release (tfs #66365 Remove Context dependency in Custom Fields)

A workaround: create LimitedUser (which doesn't load CustomFields):

var commandBuilder = CommandBuilder.Create("SELECT * FROM [AccessUser] WHERE [AccessUserID] = {0}", id);
var user = GetUser(commandBuilder);

Btw, if it is extender for UserIndexBuilder, you could use field "Groups"  

Best regards,
Vladimir

 
Roald Haahr Jensen
Reply

Hi Vladimir,

Thank you for the workaround. I found another way to solve my initial problem in a another way not involving the user. However, I had to use the workaround to add the users' External ID to the documents. Is there any reason that this piece of information is omitted by the standard UserIndexBuilder?

I successfully added the External ID to the index, which we are using as a placeholder for the sort value in the source Active Directory, but when I try to sort by that value with a Query Publisher, I get the following error:

System.IndexOutOfRangeException: Indekset lå uden for matrixens grænser.
   ved Lucene.Net.Search.AnonymousClassIntParser1.ParseInt(String val) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCache.cs:linje 304
   ved Lucene.Net.Search.FieldCacheImpl.IntCache.CreateValue(IndexReader reader, Entry entryKey) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCacheImpl.cs:linje 485
   ved Lucene.Net.Search.FieldCacheImpl.Cache.Get(IndexReader reader, Entry key) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCacheImpl.cs:linje 238
   ved Lucene.Net.Search.FieldCacheImpl.GetInts(IndexReader reader, String field, IntParser parser) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCacheImpl.cs:linje 452
   ved Lucene.Net.Search.FieldCacheImpl.IntCache.CreateValue(IndexReader reader, Entry entryKey) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCacheImpl.cs:linje 474
   ved Lucene.Net.Search.FieldCacheImpl.Cache.Get(IndexReader reader, Entry key) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCacheImpl.cs:linje 238
   ved Lucene.Net.Search.FieldCacheImpl.GetInts(IndexReader reader, String field, IntParser parser) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldCacheImpl.cs:linje 452
   ved Lucene.Net.Search.FieldComparator.IntComparator.SetNextReader(IndexReader reader, Int32 docBase) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\FieldComparator.cs:linje 490
   ved Lucene.Net.Search.IndexSearcher.Search(Weight weight, Filter filter, Collector collector) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\IndexSearcher.cs:linje 238
   ved Lucene.Net.Search.IndexSearcher.Search(Weight weight, Filter filter, Int32 nDocs, Sort sort, Boolean fillFields) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\IndexSearcher.cs:linje 212
   ved Lucene.Net.Search.IndexSearcher.Search(Weight weight, Filter filter, Int32 nDocs, Sort sort) i d:\Lucene.Net\FullRepo\trunk\src\core\Search\IndexSearcher.cs:linje 194
   ved Dynamicweb.Indexing.Lucene.LuceneIndexProvider.SearchInternal(IQuery query, QuerySettings settings)
   ved Dynamicweb.Indexing.Querying.QueryService.Query(IQuery query, QuerySettings settings)
   ved Dynamicweb.QueryPublisher.Frontend.GetContent()
   ved Dynamicweb.Frontend.Content.GetModuleOutput(Paragraph paragraph, PageView pageview)

In the IndexBuilderExtender I add it by:

if(indexDocument.ContainsKey("AccessUserId"))
{
   var userCommandBuilder = CommandBuilder.Create("SELECT * FROM [AccessUser] WHERE [AccessUserId] = {0}", indexDocument["AccessUserId"]);
   var user = LimitedUser.GetUser(userCommandBuilder);
   if (int.TryParse(user.ExternalID, out int externalId))
   {
      indexDocument.AddTermValue("AccessUserExternalId", externalId);
   }
}

AddTermValue is this method:

public static void AddTermValue(this IndexDocument document, string fieldName, object fieldValue)
{
    if (!document.ContainsKey(fieldName))
    {
        document.Add(fieldName, fieldValue);
    }
    else
    {
        document[fieldName] = fieldValue;
    }
}

AccessUserExternalId is set to System.Int32 and it is both stored and indexed.

What might the problem be?

I have made a wordaround sorting by the value in the template already, but still I would like to know how to solve it the right way.

 

Best regards,
Roald, Novicell

 
Vladimir Shushunov Dynamicweb Employee
Vladimir Shushunov
Reply

Hi Roald,

It is probably a bug that we skip ExternalId field. I will register a task to fix it.

I think that the exception happened because AccessUserExternalId should be set to a string  type (in DB it is nvarchar(250).

 

Best regards,
Vladimir

 
Nicolai Pedersen
Reply

Hi Roald

You can change your exceptions to english - would help a lot:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/c2665d7a-e84e-41a4-a1c7-8a4d054f8446/switch-to-english-exception-messages?forum=vsx

Also be aware that you query the database once for each record in the user table - which can be expensive and cause performance issues. If you have many users or run the index update frequently, this approach can be an issue. Also you query all fields instead of just the one you need, causing a lot of data to be pulled from the database that is never used...

BR Nicolai

 

You must be logged in to post in the forum