"Тип LogWriter не может быть создан" в веб-приложении в новом домене приложений

Я пытаюсь использовать блок приложения Microsoft Enterprise Library 5.0 Logging в веб-приложении. Я могу записывать в журнал из основного приложения, но когда я пытаюсь сделать это из второго AppDomain, любая попытка записи в журнал вызывает исключение (показано ниже).

Точно такой же код в консольном приложении работает нормально. Я сузил его до следующего тестового кода (просто нужно изменить константы имени сборки и типа в соответствии с вашим проектом):

public class LogTester
{
    public const string LogWriterAssembly = "LogTest";
    public const string LogWriterType = "LogTest.LogWriter";

    public static void DoLogTest()
    {
        LogWriter localLogger = new LogWriter();
        localLogger.Log("In first AppDomain");

        AppDomain domain = GetAppDomain();

        LogWriter remoteLogger = (LogWriter)domain.CreateInstanceAndUnwrap(LogWriterAssembly, LogWriterType);
        remoteLogger.Log("In second AppDomain");
    }

    private static AppDomain GetAppDomain()
    {
        string baseFolder = AppDomain.CurrentDomain.BaseDirectory;

        string folder = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;

        if (String.IsNullOrEmpty(folder))
            folder = baseFolder;

        AppDomainSetup setup = new AppDomainSetup();
        setup.ApplicationName = "TestAppName";
        setup.ApplicationBase = baseFolder;
        setup.PrivateBinPath = folder;
        setup.ShadowCopyFiles = "true";

        return AppDomain.CreateDomain("TestAppName", null, setup);
    }
}

public class LogWriter : MarshalByRefObject
{
    public void Log(string message)
    {
        Logger.Write(AppDomain.CurrentDomain.FriendlyName + ": " + message);
    }
}

Конфигурация журнала, которую я использую, используется по умолчанию (создается утилитой конфигурирования Enterprise Library):

<configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
</configSections>
<loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
        <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            source="Enterprise Library Logging" formatter="Text Formatter"
            log="" machineName="." traceOutputOptions="None" />
    </listeners>
    <formatters>
        <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
            template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
            name="Text Formatter" />
    </formatters>
    <categorySources>
        <add switchValue="All" name="General">
            <listeners>
                <add name="Event Log Listener" />
            </listeners>
        </add>
    </categorySources>
    <specialSources>
        <allEvents switchValue="All" name="All Events" />
        <notProcessed switchValue="All" name="Unprocessed Category" />
        <errors switchValue="All" name="Logging Errors &amp; Warnings">
            <listeners>
                <add name="Event Log Listener" />
            </listeners>
        </errors>
    </specialSources>
</loggingConfiguration>

В консольном приложении все работает нормально, оба сообщения журнала записываются. Однако в веб-приложении я получаю следующее исключение при попытке написать второе сообщение:

[InvalidOperationException: The type LogWriter cannot be constructed. You must configure the container to supply this value.]

[ResolutionFailedException: Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The type LogWriter cannot be constructed. You must configure the container to supply this value.
-----------------------------------------------
At the time of the exception, the container was:

  Resolving Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter,(none)
]

[ActivationException: Activation error occured while trying to get instance of type LogWriter, key ""]
   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +10582079
   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +336
   MvcApplication1.Controllers.LogWriter.Log(String message) in c:\dev\Sage Data Cloud\Development\MvcApplication1\MvcApplication1\Controllers\DefaultController.cs:65
   MvcApplication1.Controllers.LogTester.DoLogTest() in c:\dev\Sage Data Cloud\Development\MvcApplication1\MvcApplication1\Controllers\DefaultController.cs:38
   MvcApplication1.Controllers.DefaultController.Index() in c:\dev\Sage Data Cloud\Development\MvcApplication1\MvcApplication1\Controllers\DefaultController.cs:18
   lambda_method(Closure , ControllerBase , Object[] ) +101
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +59
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +435
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +60
   System.Web.Mvc.Async.AsyncControllerActionInvoker.InvokeSynchronousActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +50
   System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +75
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +44
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +139
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +49
   System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +126
   System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +323
   System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +44
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +139
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +50
   System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +68
   System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +184
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +136
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40
   System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +40
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +47
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +151
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +47
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +151
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +45
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +47
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +151
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9629708
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

У меня есть ссылки на необходимые сборки Enterprise Library, поэтому сборки Logging, ServiceLocation, Unity и Unity.Configuration копируются локально.

Я попытался отладить код в Enterprise Library с помощью.NET Reflector, но создание объекта все делается с использованием динамически сгенерированного кода, в который я не могу войти (и я не хочу пытаться выполнить обратный инжиниринг этого из некомментированный декомпилированный источник!).

Просто интересно, сталкивался ли кто-нибудь с этой проблемой раньше, и возможные решения? Не могу найти такую ​​же проблему нигде.

Заранее спасибо. Пит

1 ответ

Решение

Необходимо настроить файл конфигурации нового домена приложений, чтобы можно было настроить корпоративную библиотеку в новом домене приложений. Вы можете сделать это с помощью AppDomainSetup.ConfigurationFile имущество:

AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = "TestAppName";
setup.ApplicationBase = baseFolder;
setup.PrivateBinPath = folder;
setup.ShadowCopyFiles = "true";
setup.ConfigurationFile = 
    AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
Другие вопросы по тегам