U4-1187 - TypeFinder FindClassesMarkedWithAttribute returns types that do not have that attribute

Created by Morten Bock 12 Nov 2012, 16:55:16 Updated by Claus Jensen 17 Jan 2017, 08:21:11

Is duplicated by: U4-1601

There is an issue with the TypeFinder class, that will allow types to be returned, that are do not actually have the given attribute.

The problematic code is the following:

static IEnumerable FindClassesMarkedWithAttribute(Assembly assembly, Type attribute) { // DF: Fix Codeplex #30479 - Dynamic assemblies in Umbraco cause XSLTs to break - TypeFinder.cs // Just return if the assembly is dynamic. if (assembly.ManifestModule.GetType().Namespace == "System.Reflection.Emit") return new List();

try
{
    return assembly.GetTypes().Where(type => type.GetCustomAttributes(attribute, true).Length > 0);
}
catch (ReflectionTypeLoadException ex)
{
    if (GlobalSettings.DebugMode)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendFormat("Unable to load one or more of the types in assembly '{0}'. Exceptions were thrown:", assembly.FullName);
        foreach (Exception e in ex.LoaderExceptions)
            sb.AppendFormat("\n{0}: {1}", e.GetType().FullName, e.Message);
        throw new Exception(sb.ToString());
    }
    else
    {
        // return the types that were loaded, ignore those that could not be loaded
        return ex.Types;
    }
}

}

The call to assembly.GetTypes() might throw an exception, if some referenced dll's are not found. That is handled with the catch block.

In the catch block, the exception will be surfaced if the application is in debug mode. Great. If it is not, then it will just return any type that it did find. ANY type. That means that for example the /base module will throw an exeption because the types returned to it are not actually marked as rest extensions, but just happen to live in a dll with references to non existing dll's.

My proposed fix is this:

static IEnumerable FindClassesMarkedWithAttribute(Assembly assembly, Type attribute) { // DF: Fix Codeplex #30479 - Dynamic assemblies in Umbraco cause XSLTs to break - TypeFinder.cs // Just return if the assembly is dynamic. if (assembly.ManifestModule.GetType().Namespace == "System.Reflection.Emit") return new List();

IEnumerable<Type> typesInAssembly;

try
{
	typesInAssembly = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
	if (GlobalSettings.DebugMode)
	{
		var sb = new StringBuilder();
		sb.AppendFormat("Unable to load one or more of the types in assembly '{0}'. Exceptions were thrown:", assembly.FullName);
		foreach (Exception e in ex.LoaderExceptions)
			sb.AppendFormat("\n{0}: {1}", e.GetType().FullName, e.Message);
		throw new Exception(sb.ToString());
	}
	else
	{
		// return the types that were loaded, ignore those that could not be loaded
		typesInAssembly = ex.Types;
	}
}

return typesInAssembly.Where(type =>
	{
		try
		{
			return type != null && type.GetCustomAttributes(attribute, true).Length > 0;
		}
		catch (Exception e)
		{
			if (GlobalSettings.DebugMode)
			{
				string typename = type != null ? type.FullName : "null";
				string message = string.Format("Unable to load attributes for type {0} in assembly {1}. \n{2}", typename, assembly.FullName, e.Message);
				throw new Exception(message);
			}
			else
			{
				return false;
			}
		}
	});

}

This should make sure that only classes that actually have the attribute are returned, and it will only throw in case you have debug mode turned on, as before.

3 Attachments

Download ClassLibrary3.zip

Download ReferenceFail.zip

Download SolvingTheMissingReferenceIssue.zip

Comments

Shannon Deminick 13 Nov 2012, 00:14:33

any chance do you know if this is an issue with 4.10 with the new TypeFinder?


Morten Bock 13 Nov 2012, 09:31:56

I don't know if the issue exists in 4.10. I only upgraded to 4.9.1. We're not quite ready to try out the all new routing for this project yet.

If it is solved in 4.10, that might push us in that direction though.


Sebastiaan Janssen 13 Nov 2012, 12:57:37

@Morten if you have an easy way to reproduce the error I'll give it a go on 4.10.0 and see if it's still a problem.


Morten Bock 13 Nov 2012, 13:13:30

@Sebastian Should be possible to reproduce by these steps:

  • Create two projects ProjA and ProjB
  • Create a class in ProjB that inherits from something in ProjA
  • Put ProjB.dll in your umbraco site, and not ProjA.dll
  • Go to the media section of the site, and see if the folderbrowser will load

The actual dll we are having issues with is Recaptcha.dll, but the missing reference for that is System.Web.Mvc.dll, which I assume is already there in V4.10 of umbraco, so that would not create an error there.


Sebastiaan Janssen 13 Nov 2012, 14:15:03

@Morten seems to work in 4.10.0! See if you can build this (see attached) and only deploy ClassLibrary1.dll, I think I did it correctly as you said.


Morten Bock 13 Nov 2012, 14:46:55

@Sebastiaan It won't open in VS2010, but if it fails in a 4.9.1 install, then you did it right :)

The Class2 probably needs to be public though, for Umbraco to be able to find it?


Morten Bock 13 Nov 2012, 14:52:51

Create my own project. If you add ReferenceFail.dll to the bin folder, then the folderbrowser fails in 4.9.1.


Sebastiaan Janssen 13 Nov 2012, 16:48:10

Hey Morten, this actually does not work at all, so the whole site is now a YSOD, I don't actually understand how it could possibly work though. I would definitely expect this behaviour, if a dll refers to another one and it's not there, it should just crap out.. what else can it do?


Sebastiaan Janssen 13 Nov 2012, 16:48:56

(by the way, my solution does the same thing, I just copied the wrong dll over)


Morten Bock 13 Nov 2012, 17:06:33

@Sebastiaan The scenario where this could happen is valid enough. We have a few project in the company where third party products have some sort of reference to a dll, that we either don't have, or don't want to have.

The Recaptcha nuget package is one example, that does not ship with all the referenced dll's. MiniProfiler is another. They reference other dll's, so they can suuport them "if they are there".

You and I can quickly agree, that it's a bad thing to have a reference in your dll to something that you do not include. It would probably be nice to separate that stuff into another dll, that could then be omitted.

However, I have seen it with quite a few different tools, and it is a valid thing, as long as you don't use the types that interact with the missing dll.

So I would hope that that TypeFinder would not blow up because of it, since we would probably like people to be able to use those tools, even though the tools are "doin' it wrong"?


Stephan 13 Nov 2012, 17:45:58

@Sebastiaan: DLL-1 can reference DLL-2 but as long as you don't reference a type in DLL-1 that requires a type in DLL-2, DLL-2 may not be loaded. So it's valid to have DLL-1 in ~/bin and ''not'' DLL-2. But the TypeFinder has to reference ''every'' types in DLL-1, just to see if they match the query, and so an exception is raised when it reaches the type in DLL-1 that references the type in DLL-2.


Stephan 13 Nov 2012, 18:11:43

I can confirm that currently the test case just kills Umbraco, which is something we fixed in 4.9. The fix was buggy because it returned types that did not have the attribute. In 4.10 we have a regression. Looking into it.


Stephan 13 Nov 2012, 18:33:05

I believe we don't want to die anytime an assembly is missing, because as Morten pointed out there may be some valid cases where an assembly ''will'' be missing. So we should swallow the exception and just return the types that could be loaded. However this has drawbacks because then you can spend hours trying to figure out why a type that you expected is not returned (been there...).

Pre 4.10 we died in debug mode, and swallowed in non-debug mode. But that was far from perfect too, because then in debug mode there was no way to get it to work.

Ideally I'd like to swallow ''but'' to report somewhere in an obvious-enough way. Somehow we should have a "health status" feature in the Developer section that would report assemblies with issues. So people would know where to look. Alternatively we can always write to the log, but usually people forget to look at the log...

What do you think?


Morten Bock 13 Nov 2012, 19:16:43

@Stephan I agree with your reasoning, and I found the "swallow when not debug" a bit weird. I see a couple of stages of this:

1: Discovering the error: Always throw an exception, if the assembly types cannot be loaded. I think that is fair, debug or not. Also log the exception to the umbracoLog, and display errors from the log in the backend somehow, since these exceptions might be happening in ajax requests to /base

2: Fixing the error: In V5 you needed to mark your assembly as containing plugins, for it to be picked up by reflection. Maybe we could turn it around, so you could add an assembly to a "exclude from reflection" list. Most of the times, the assemblies that cause this stuff don't actually contain plugins, but are 3rd party of some sort. So excluding them would help your site not blow up, and would not cause any problems.

Would that work? The throw/don't throw can be discussed, but I think the behavior should be the same no matter if it is debug mode or not?


Shannon Deminick 13 Nov 2012, 20:47:10

IMO there is no real good way to solve this... The thing is, if AssemblyA references AssemblyB but AssemblyB is missing, then as soon as any type is tried to load from AssemblyAn(in the case above, if a Recaptcha was attempted to be loaded) then a YSOD will occur regardless.

So, if we band-aid fix the TypeFinder to not throw a YSOD when this occurs we can run in to other problems which will just be swallowed and you won't know about the problems. For example, lets say AssemblyA includes SurfaceController's (or any plugin type) and AssemblyA still references AssemblyB but AssemblyB is missing. If we then swallow this exception and carry on, this means that all of those plugin types will be missing in the Umbraco runtime that were supposed to be found in AssemblyA. Then someone will say, "there is a bug in Umbraco, it's not showing my plugin types but I know there are there".

The thing with v5 we did for performance but I'm 99% sure that you would still have this problem because as soon as you load an assembly into the CLR either to look for a type or an Assembly attribute, it will attempt to load all referenced assemblies and you will end up with the same YSOD.

I agree that the behavior should be the same in debug or not debug and IMHO i think displaying a YSOD is a good thing because in fact the application is missing an assembly and a YSOD will occur at some point anyways.

Oh and we already have an 'exclude from reflection' type of list though this is internal and is used for performance. I don't really think that opening this up to be public so people can add to this list in order to not get a YSOD is a good thing, i think that real fix is to just add the assembly that is missing.

The only other option i can think of than showing the YSOD is to swallow the exception, ignore any plugin types found in those assemblies and just log the error in the log... though I bet you at some point someone does say: "there is a bug in Umbraco, it's not showing my plugin types but I know there are there".


Morten Bock 13 Nov 2012, 21:28:52

@Shannon There is definitely a case to be made for the "Fail fast" strategy. And if the new TypeFinder throws already at app start, then that is a big improvement over the "fail when /base is called" strategy.

The problem with "just add the missing assembly" is that you might not be able to get that assembly. It could be a reference to an aggressive logging framework, or some other evil spawn. My point is, that there is a valid reason why you might not include a 3rd party components referenced dll's.

So if the choice stands between "Why is my plugin not loaded", and "I can't use umbraco because it throws a big exception", then what should we choose?

You're right, that there is no 100% nice solution for this. Maybe a config option like TrowOnTypeLoadException that defaults to true. Then people who can't get past the exception can flip the switch, and accept that plugins might not load?


Shannon Deminick 13 Nov 2012, 21:34:14

But I'm wondering how its possible to use the library that is referencing the missing library at all? Is that even possible? It was my understanding that as soon as you try to (for example) load a control from AssemblyA and even if that control doesn't use anything from AssemblyB, .Net will chuck an exception anyways because it needs to load in both assemblies to load in anything from AssemblyA... perhaps I'm wrong in that assumption though? if that's the case, then does .Net just chuck an exception if the control in AssemblyA requires something in AssemblyB which is missing?


Morten Bock 13 Nov 2012, 21:38:35

It is possible to use a control from the dll. We are doing it in a few project right now. It is not until you actually try to access a type that uses the missing dll that you get the exception. Sort of like a static constructor is not called until some code tries to use the class.


Stephan 14 Nov 2012, 07:53:52

@Morten: we've been there too, when you ''have'' to use a bogus DLL, even for a short time.

We definitively want a system that

  • reports the faulted DLLs when TypeFinder encounters them, in a very obvious way, and dies
  • allows to disable that report, for specific DLLs, and then only let you use types that "work"

We need the first one because if we swallow by default, we'll get tons of "my plugin does not load" questions. And writing to the log is not enough, we want to die hard.

@Shannon: we don't want to add these assemblies to the "exclude from reflection" list because they actually contain types that we ''want'' to use. Only, we want a separate "swallow reflection exceptions" list where devs can add the DLLs that they know cause issues.

@Morten: so basically I'm repeating what you said already. Anyway. Will think about it today.


Thomas Skyldahl Sørensen 16 Apr 2013, 15:43:33

Would it be possible to check if the assembly has a reference to the assembly containing the Attribute we are looking for? that way it could be faster and we would only scan the assemblies containg code that could have the Attribute we are looking for?


Shannon Deminick 16 Apr 2013, 15:46:25

That is how it originally worked in v5 (before it was actually released) but the community did not like the concept as it was an additional step to create plugins. We had an attribute like:

[assembly: ContainsPlugins] (or something like that).

We can't change it to work like that now as it would be a huge breaking change. It also doesn't solve this issue since if your assembly that contains this attribute is still missing a referenced assembly you will get this error.


Thomas Skyldahl Sørensen 16 Apr 2013, 15:50:23

here is a quick example of what I mean:

AppDomain.CurrentDomain.GetAssemblies().Where(asm => asm.GetReferencedAssemblies().Contains(((Type)attribute).Assembly)

with that you could filter out any assembly not referencing the assembly containing your attribute without any extra work from the people creating plugins

I think that would fix most of the problems, as we would avoid scanning assemblies that dont contain the attribute we are looking for


Shannon Deminick 16 Apr 2013, 15:54:38

The exception comes from the call: Assembly.GetExportedTypes()

So we really can't 'filter' out anything as this call will still throw an exception if you have missing references.


Thomas Skyldahl Sørensen 16 Apr 2013, 16:00:29

for me the biggest problem right now is that we are scanning assemblies that cant contain the attribute and they can fail the lookup. by filtering the assemblies that have the reference to the assembly containing the attribute we are looking for we avoid scanning all the extra assemblies. and we only fail on the ones containing the the reference.

I will try putting a sample together to prove my point :-)


Thomas Skyldahl Sørensen 16 Apr 2013, 17:06:08

Hi Shannon I created a project to test out the issue the most of the code lives in the PluginScanner project and then there are few assemblies to test out different scenarios. from me it looks like most of the errors should be comming when looking up the Attributes, if any type is decorated with Attributes from a missing reference then we have the issue.

But I think you will understand what I was trying to do in the code above when you see the code.

simply put we could add the following after the reflection emit check to avoid scanning types in assemblies that doesn't contain any types we are interested in: // Avoid scanning assembly if it doesn't contain a reference // to the assembly containing the attribute we are looking for var attributeAssemblyName = attribute.Assembly.GetName().Name; if(assembly.GetName().Name != attributeAssemblyName && !assembly.GetReferencedAssemblies().Select(a => a.GetName().Name).Contains(attributeAssemblyName)) return new List();

Updated to avoid skipping the assembly containing the attribute


Robert 17 Apr 2013, 03:22:32

Can we at least provide a nicer error so you can tell which dll is failing to load its dependency without the user getting fusion logs involved?


Thomas Skyldahl Sørensen 17 Apr 2013, 16:25:37

I added some optimization to how the assemblies are scanned in the TypeFinder it can be found in the pull request https://umbraco.codeplex.com/SourceControl/network/forks/NeZz_DK/fixissueU41187/contribution/4505


Shannon Deminick 30 Apr 2013, 05:37:46

@Thomas: I've run some performance tests between the original code and your merged in revised code and the results look great!

The differences are better all around but the biggest difference is in the method FindClassesWithAttribute which chews up a crazy amount of processing... its a good thing we don't use this method often. However, with your changes it doesn't matter so much.

Here's the results, each sub test is x1000 iterations.

New code changes:

Starting test Starting FindClassesOfType Finished FindClassesOfType (took 1060ms) Starting FindClassesOfTypeWithAttribute Finished FindClassesOfTypeWithAttribute (took 615ms) Starting FindClassesWithAttribute Finished FindClassesWithAttribute (took 1468ms) Finished test (took 3151ms)

Original code:

Starting test Starting FindClassesOfType Finished FindClassesOfType (took 2153ms) Starting FindClassesOfTypeWithAttribute Finished FindClassesOfTypeWithAttribute (took 2001ms) Starting FindClassesWithAttribute Finished FindClassesWithAttribute (took 17035ms) Finished test (took 21194ms)

As you can see the performance is MUCH better for FindClassesWithAttribute. Nice work Sir :)

I'm just going to write some other tests to ensure that it is still resolving everything correctly and merge it in to the 4.10.8 branch and upwards.

This won't solve this actually issue but as you said it can minimize the issue.


Thomas Skyldahl Sørensen 30 Apr 2013, 08:56:16

@Shannon Glad I could help :-)


Shannon Deminick 03 May 2013, 05:58:37

DOH! We have a problem with this change :( :( :( and it's not been released in 4.11.8. Even though the tests pass, the method "RemoveAssembliesThatDontReferenceAssemblyOfType" is removing assemblies that do reference a type that we are looking for. Now Examine no longer works at all and will not listen to events. I'm in the process of figuring out how this happens, will report back soon but means we're going to have to have another emergency release.


Shannon Deminick 03 May 2013, 06:04:28

The problem is due to this:

This method gets the assembly that contains the 'raw' type, however this doesn't take into account any types that inherit from that type and thus removes assembly that still need to be scanned.

An example (which is causing the current problem) is that we look for types: IApplicationStartupHandler which is in the interfaces.dll assembly. But we also need to find any types that inherit from ApplicationBase which is found in the businesslogic.dll. UmbracoExamine.dll doesn't reference interfaces.dll so now UmbracoExamine.dll gets removed from being searched.

Not sure the best way to solve this issue without just reverting the TypeFinder back to how it worked before since we'd have to find non-concrete types of the type we're looking for in all assemblies and ensure we don't remove them from the current scan.

@Thomas, depending on what Sebastian says we might just have to revert this and make a release so that everything works properly.


Thomas Skyldahl Sørensen 03 May 2013, 07:17:54

I tested this in my project and Resharper tells me that I need to reference the base library. when I apply the INHERITED attribute.

ASSEMBLIES in my test: RUNNER ( console project for running the test and having my class with the attribute from INHERITED applied ) BASE ( has a base attribute ) INHERITED ( has the attribute that inherits from a attribute in BASE )

could it be caused by internal refactoring and Sebastian is referencing a old version of umbraco that doesn't have a attribute that inherits from something inside Core?


Shannon Deminick 05 May 2013, 03:55:43

@Thomas, it's easy to replicate this issue. In the UmbracoExamine.dll library that is shipped with 4.x it has a class that inherits from ApplicationBase. When we use the TypeFinder to find all instances of IApplicationStartupHandler the class that inherits from ApplicationBase in the UmbracoExamine.dll is not found even though ApplicationBase implements IApplicationStartupHandler. That is because the UmbracoExamine.dll doesn't explicitly reference the interfaces.dll so the method "RemoveAssembliesThatDontReferenceAssemblyOfType" removes UmbracoExamine.dll from the lookup.

This is a fairly major issue as currently in 4.8 Umbraco Examine will not index any newly saved content, media or members. This issue probably affects many other sub classes of ApplicationBase if their assembly doesn't explicitly reference interfaces.dll.


Shannon Deminick 05 May 2013, 05:47:31

@Thomas, I've updated a unit test to show the failure in revision: 7cb2e364b7cc

Umbraco.Tests.TypeFinderTests.Find_Classes_Of_Type

I'm not sure there is a way around this since in order to effectively "RemoveAssembliesThatDontReferenceAssemblyOfType" we'd have to search for all inherited type's in all assemblies which would mean searching all assemblies anyways. I suppose we could theoretically recursively search for inherited types in assemblies that are referencing the current base type. What I mean is (for example):

  • We are searching for implementations of IApplicationStartupHandler
  • We look for all types of IApplicationStartupHandler in assemblies that reference interfaces.dll since that is where IApplicationStartupHandler lives
  • We iterate over each type found and search for implementations of these types in assemblies that reference the current assembly of the type we are looking for
  • We recursively do that until we don't find any more types

This is possible I think but not sure if this will actually save on overall performance or not. In the meantime, we're going to have to fix this issue very quickly since the impact of it is quite large and there's not really any work-around's since this could affect all sorts of plugins. I'll wait to hear back from @Sebastian tomorrow but we might just need to revert back to the original TypeFinder by COB Monday.


Thomas Skyldahl Sørensen 05 May 2013, 16:37:20

@Shannon We could revert to the old version but filter out .NET Framework libraries that would keep some of the speed gains but would get us back to getting exceptions if any library fails to load a single type.

Then for the next version we could try to optimize the way we look for assemblies in another way, by using GetTypes() and handling the TypeLoadException we can resolve the types that are possible and report back in a log or exception if we ran against any errors.

But I think we would need some kind of setting to configure how we want the TypeFinder to react to errors.

Another way would be to use Mono.Cecil then we can actually scan the assemblies for types without loading them into the app domain.


Thomas Skyldahl Sørensen 05 May 2013, 21:00:35

@Shannon, We could change the PluginManagerExtensions.ResolveApplicationStartupHandlers into the following internal static IEnumerable ResolveApplicationStartupHandlers(this PluginManager resolver){

return resolver.ResolveTypes() // we need to support support legacy handlers, that where compiled against older versions of umbraco .Concat(resolver.ResolveTypes()) // we only want each type once even if it implements the IApplicationStartupHandler and inherits from ApplicationBase .DistinctBy(t => t.FullName); }

That would enable the updated manager to support the older way of initializing without recompiling the binaries against the new version.

But I'm not into the whole codebase so I dont know if there are other places that have been refactored to use interfaces instead of base classes in the same way.


Shannon Deminick 06 May 2013, 01:36:21

@Thomas, We cannot simply look for both IApplicationStartupHandler and ApplicationBase because we'll have the same problem with other plugin types and inherited types that exist in different assemblies. Also the very old TypeFinder that we used to use did load up a separate app domain to run its searches but that turns out to be incredibly slow which is why we removed that.

I'll get the recursive searching happening to see if that is still faster than just reverting the code.


Adam Nelson 06 May 2013, 02:08:54

@Shannon - could you please confirm that Examine indexing is broken in 4.11.8 or not? ie. it won't index any newly saved content. I'm trying to upgrade to 4.11.8 now and I'm seeing that behaviour but from what I read above seems to indicate that the change here is NOT in 4.11.8.


Shannon Deminick 06 May 2013, 02:13:42

@Adam, correct in 4.11.8 Examine indexing will not work for newly saved content due to the TypeFinder changes not finding inherited classes that exist in different assemblies. You could work around this by manually constructing the UmbracoExamine.UmbracoEventManager ... but definitely ensure that you remove this work around after we've fixed this issue otherwise examine will double bind to events so it will re-index information 2 times (you won't have duplicates but it will process it twice). Also keep in mind that the TypeFinder but in 4.11.8 could affect other plugins/packages.


Adam Nelson 06 May 2013, 02:19:19

@Shannon - ok thanks for the info. I'm actually seeing the newly created articles make their way into the index (verified with Luke), but my frontend search isn't finding them. I'll keep looking as it sounds like it ''should'' be working for me.


Shannon Deminick 06 May 2013, 02:21:45

Normally the UmbracoExamine.UmbracoEventManager will log an entry on startup: "[UmbracoExamine] Adding examine event handlers for index providers: "

but with this issue you'll notice that it doesn't because it is not found so it doesn't get constructed and therefor doesn't bind to the Umbraco events.


Adam Nelson 06 May 2013, 02:25:59

@Shannon - thanks, confirmed no references to "Examine" at all in the UmbracoTraceLog.txt. So looks like I can stop trying to work out why it's not working for me.


Shannon Deminick 06 May 2013, 02:27:46

try constructing the UmbracoExamine.UmbracoEventManager in your app startup and you should be back in business as a work around.


Shannon Deminick 06 May 2013, 12:28:57

This is all fixed up in revision: 368acfe1d1ab

I've managed to fix up the TypeFinder so that it maintains the new performance changes and it resolves looking for inherited types even ones that exist in different assemblies. I've also added more unit tests for this. If anyone would like to review the code changes in 2b66b6b2ef35 and 368acfe1d1ab, that'd be much appreciated.

You can download a nightly here: http://nightly.umbraco.org/umbraco%204.11.9/UmbracoCms.AllBinaries.4.11.9-build.31.zip

The 6.0.6 nightly is building now and will be available here: http://nightly.umbraco.org/umbraco%206.0.6/


Thomas Skyldahl Sørensen 06 May 2013, 13:13:48

Nice! I will take a look when I get home.


Adam Nelson 06 May 2013, 21:37:33

@Shannon - sorry to come back to this unrelated point but FYI UmbracoExamine ''is'' working for me ''without'' manually constructing UmbracoEventManager. I ended up finding the log entry you mention above in the umbracoLog table (I was checking in UmbracoTraceLog.txt before).

The reason my search wasn't working was just a bug in my code. The reason UmbracoExamine is being registered (when you say above it shouldn't be) is perhaps because I'm listening to the GatheringNodeData event:

public void OnApplicationStarted(UmbracoApplication httpApplication, ApplicationContext applicationContext) { var indexer = ExamineManager.Instance.IndexProviderCollection["ArticleIndexer"]; indexer.GatheringNodeData += IndexerGatheringNodeData; }


Shannon Deminick 06 May 2013, 22:56:01

@Adam... not sure how that is working but I guess that is good news for you ! :)


Sebastiaan Janssen 16 Oct 2014, 16:16:32

Just happened to run into this issue (not in my code or anything, I was just browsing this issue tracker!), seems like it was fixed.


Priority: Major

Type: Bug

State: Fixed

Assignee: Shannon Deminick

Difficulty: Very Easy

Category: Extensibility

Backwards Compatible: True

Fix Submitted: Inline code

Affected versions: 4.9.1

Due in version: 6.0.6

Sprint:

Story Points:

Cycle: