How can I specify the path for ASP.NET probing for automatic scopes of C ++ / CLI applications?

I have a C ++ / CLI DLL that needs to run in the context of an ASP.NET WebApi action.

The action is affected by the ActionFilter, which uses log4net LogicalThreadContext

to set the property containing the request ID; this works well to write the request id in the log entry.

The problem is that ASP.NET seems to create an appdomain when it's time to load the class from the C ++ / CLI dll. (I can't find any documentation on how this works, I would love to find it.) When the appendix application tries to deserialize everything, it chokes because it can't find log4net.dll (see below for the stack trace).

Fusion logs show what they look in C:\Windows\System32\inetsrv

, which is not correct ... I would expect it to look for a exploration path or environment variable %PATH%

.

Multiple data points:

  • log4net.dll is available in the web application directory bin

    and works great for everything I use for it.
  • C ++ / CLI code has no dependencies on log4net.
  • If I comment on my calls at log4net.LogicalThreadContext.Properties[...]

    , everything will be fine.
  • If I copy the log4net.dll from my folder bin

    to C:\Windows\System32\inetsrv

    everything is fine.
  • The web.config file specifies the path to discover using the item <probing privatePath="bin"/>

    .
  • My method Application_Start

    in global.asax.cs

    adds the web application directory bin

    to the environment variable %PATH%

    :

        var currentPathEnvVar = Environment.GetEnvironmentVariable("PATH");
        var binPath = Path.Combine(Server.MapPath("~") ?? String.Empty, "bin");
        _log.DebugFormat("Prepending paths to PATH: [{0}]", binPath);
        Environment.SetEnvironmentVariable("PATH", String.Concat(binPath, Path.PathSeparator, currentPathEnvVar));
    
          

  • The log shows it is %PATH%

    getting the correct addition:

    2015-06-05 17:07:48,816 1   DEBUG   MyNamespace.WebApiApplication   (null)  Prepending paths to PATH: [C:\Program Files\MyCompany\MyApp\web\bin]
    
          

So how do I get the appdomain that ASP.NET creates to find the correct location to load the assemblies?

Thank.


Here's a stack trace that is logged when it all crashes.

2015-06-05 17:08:41,148 23  ERROR   MyNamespace.MyController    (null)  Controller action failed
System.TypeInitializationException: The type initializer for '<Module>' threw an exception. ---> <CrtImplementationDetails>.ModuleLoadException: The C++ module failed to load while attempting to initialize the default appdomain.
 ---> System.Runtime.Serialization.SerializationException: Unable to find assembly 'log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'.

Server stack trace: 
   at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
   at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)
   at System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage.FixupForNewAppDomain()
   at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(Byte[] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, SmuggledMethodReturnMessage& smuggledMrm)
   at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(Object[] args)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at System.AppDomain.IsDefaultAppDomain()
   at <CrtImplementationDetails>.GetDefaultDomain() in f:\dd\vctools\crt\crtw32\h\minternal.h:line 367
   at <CrtImplementationDetails>.DoCallBackInDefaultDomain(IntPtr function, Void* cookie) in f:\dd\vctools\crt\crtw32\h\minternal.h:line 401
   at <CrtImplementationDetails>.DefaultDomain.Initialize() in f:\dd\vctools\crt\crtw32\msilcrt\mstartup.cpp:line 278
   at <CrtImplementationDetails>.LanguageSupport.InitializeDefaultAppDomain(LanguageSupport* ) in f:\dd\vctools\crt\crtw32\msilcrt\mstartup.cpp:line 343
   at <CrtImplementationDetails>.LanguageSupport._Initialize(LanguageSupport* ) in f:\dd\vctools\crt\crtw32\msilcrt\mstartup.cpp:line 546
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* ) in f:\dd\vctools\crt\crtw32\msilcrt\mstartup.cpp:line 703
   --- End of inner exception stack trace ---
   at <CrtImplementationDetails>.ThrowModuleLoadException(String errorMessage, Exception innerException) in f:\dd\vctools\crt\crtw32\h\minternal.h:line 194
   at <CrtImplementationDetails>.LanguageSupport.Initialize(LanguageSupport* ) in f:\dd\vctools\crt\crtw32\msilcrt\mstartup.cpp:line 713
   at .cctor() in f:\dd\vctools\crt\crtw32\msilcrt\mstartup.cpp:line 754
   --- End of inner exception stack trace ---
   at MyNamespace.MyController.MyAction(String foo, Int64 bar, String baz)

      

+3


source to share





All Articles