Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeLoadException on Attribute in shared assembly

UPDATE 10:29 MST on 11/7

Oddly enough if I move the attribute out of the ComponentModel folder back into the root of the Common project the code works fine. I can't imagine what's possibly referencing the old namespace after all of the references were refactored for the InflowHealth.Common.ComponentModel namespace.

It's almost like there is some reference hiding somewhere that's not code-based but rather runtime and dynamic, but I sure don't see it when looking through all find results of InflowHealthErrorContext.

UPDATE 19:33 MST on 11/6

Of new interest, when I commented out the line to use the custom attribute to inherit routes, and use the default one, it still blew up. Of further interest, the namespace it's looking for InflowHealth.Common.InflowHealthErrorContextAttribute is actually the old FQN before I refactored it and moved it to a folder (and namespace) ComponentModel.

UPDATE 07:42 MST on 11/6

I believe I've identified that the issue is related to another custom attribute I'm using to inherit actions. This attribute is added to the HttpConfiguration like this:

public static void MapInheritedAttributeRoutes(this HttpConfiguration config)
{
    config.MapHttpAttributeRoutes(new InheritanceDirectRouteProvider());
}

The implementation of that attribute is pretty simple:

public class InheritanceDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    {
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(true);
    }
}

It appears that inheriting this InflowHealthErrorContext attribute is causing issues, but I'm not sure exactly what the issue is. I've tried:

  • Removing Inherited = false so that it is inheritable.
  • Removing AllowMultiple = true just because that was misconfigured.

Those did not change the error.


ORIGINAL POST

I have a very simple attribute in a Common assembly shared by a couple Web API applications. As simple as this is I just can't figure out what would cause this exception.

I have tried to collect Fusion logs on this, but it's not logging them.

This is the Attribute:

using System;

namespace InflowHealth.Common.ComponentModel
{
    [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
    public sealed class InflowHealthErrorContextAttribute : Attribute
    {
        // This is a positional argument
        public InflowHealthErrorContextAttribute(string errorContext)
        {
            ErrorContext = errorContext;
        }

        public string ErrorContext { get; }
    }
}

This would be used on a route to later provide some extra context to the automated error logging done inside of a filter:

[Authorize(Roles = Roles.ALL_ADMINS)]
[Route("api/ControlPanelApi/PayerClassifications")]
[InflowHealthErrorContext("Error getting payer classifications.")]
public IHttpActionResult GetPayerClassifications(int clientId, bool showAllRows)
{
    return Ok(GetData(payerClassificationManager, clientId, showAllRows));
}

Upon loading the application, when Web API Routes are registered, it fails. Here is the line it's breaking on:

GlobalConfiguration.Configure(WebApiConfig.Register);

It's throwing this exception:

Could not load type 'InflowHealth.Common.InflowHealthErrorContextAttribute' from assembly 'InflowHealth.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

This is the stack trace:

   at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
   at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
   at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
   at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, Boolean inherit)
   at System.Reflection.RuntimeMethodInfo.GetCustomAttributes(Type attributeType, Boolean inherit)
   at System.Attribute.GetCustomAttributes(MemberInfo element, Type type, Boolean inherit)
   at System.Attribute.GetCustomAttribute(MemberInfo element, Type attributeType, Boolean inherit)
   at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](MemberInfo element)
   at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.IsValidActionMethod(MethodInfo methodInfo)
   at System.Array.FindAll[T](T[] array, Predicate`1 match)
   at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem..ctor(HttpControllerDescriptor controllerDescriptor)
   at System.Web.Http.Controllers.ApiControllerActionSelector.GetInternalSelector(HttpControllerDescriptor controllerDescriptor)
   at System.Web.Http.Controllers.ApiControllerActionSelector.GetActionMapping(HttpControllerDescriptor controllerDescriptor)
   at System.Web.Http.Routing.AttributeRoutingMapper.AddRouteEntries(SubRouteCollection collector, HttpConfiguration configuration, IInlineConstraintResolver constraintResolver, IDirectRouteProvider directRouteProvider)
   at System.Web.Http.Routing.AttributeRoutingMapper.<>c__DisplayClass2.<>c__DisplayClass4.<MapAttributeRoutes>b__1()
   at System.Web.Http.Routing.RouteCollectionRoute.EnsureInitialized(Func`1 initializer)
   at System.Web.Http.Routing.AttributeRoutingMapper.<>c__DisplayClass2.<MapAttributeRoutes>b__0(HttpConfiguration config)
   at System.Web.Http.HttpConfiguration.EnsureInitialized()
   at System.Web.Http.GlobalConfiguration.Configure(Action`1 configurationCallback)
   at InflowHealthPortal.MvcApplication.Application_Start() in Global.asax.cs:line 22
like image 889
Mike Perrenoud Avatar asked Nov 06 '17 02:11

Mike Perrenoud


2 Answers

I would suggest you delete the bin and obj folders and rebuild the project.

This issue sometimes happened when there was a stray dll hanging around that was not overwritten when the projects were compiled. Usually when renaming output files.

Performing the above actions have worked for me in the past when it came to references not reflecting the changes made to code and recompilation.

The same sometimes happened with Nuget packages and this would result in having to remove the package and re-installing it in order for the correct dlls to be referenced.

like image 101
Nkosi Avatar answered Nov 18 '22 07:11

Nkosi


InflowHealthErrorContextAttribute belongs to InflowHealth.Common.ComponentModel namespace however error

Could not load type 'InflowHealth.Common.InflowHealthErrorContextAttribute' from assembly 'InflowHealth.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

shows that it's searched in InflowHealth.Common namespace. Couldn't it be an issue?

Probably in some outdated version of Common assembly that you referenced, attribute is in InflowHealth.Common namespace and code compiles without errors, but in assembly that gets to output folder attribute is actually in InflowHealth.Common.ComponentModel namespace and search of InflowHealth.Common.InflowHealthErrorContextAttribute type fails.

like image 41
CodeFuller Avatar answered Nov 18 '22 09:11

CodeFuller