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
toC:\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
inglobal.asax.cs
adds the web application directorybin
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)
source to share
No one has answered this question yet
Check out similar questions: