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