2011-03-28 5 views
6

우리는 System.AddIn을 사용하여 별도의 하위 AppDomains에 추가 기능을로드하고 처리되지 않은 예외가있는 경우 추가 기능 AppDomain을 언로드합니다.자식에서 직렬화 할 수없는 처리되지 않은 예외 처리 AppDomain

버전 2.0에서 .NET의 기본 동작은 AppDomain에 처리되지 않은 예외가있는 경우 전체 프로세스를 중단하기 때문에 App.config에서 "legacyUnhandledExceptionPolicy"옵션을 사용하여이 작업을 수행 한 다음 처리되지 않은 예외가 기본 AppDomain에있는 경우 처리하거나 추가 기능에있는 경우 적절한 AppDomain을 언로드합니다.

한 가지 작은 문제를 제외하면이 모든 것이 효과적입니다. 처리되지 않은 예외는 항상 하위 AppDomains에서 주 AppDomains로 바뀌며, 직렬화되지 않으면 AppDomain 경계를 성공적으로 넘을 수 없습니다.

대신 주 AppDomain에 UnhandledException으로 나타나는 SerializationException이 발생하여 응용 프로그램이 스스로 찢어 지도록 만듭니다.

나는이 문제에 대한 몇 가지 가능한 해결책을 생각할 수 : 우리는 처리되지 않은 SerializationExceptions (우웩)에 대한 프로세스를 철거 할 수 없습니다

  • .

  • 예외가 자식 AppDomain에서 기본 AppDomain으로 전파되는 것을 막을 수 있습니다.

  • 우리는 직렬화 가능 예외를 직렬화 대리자 및 직렬화 바인더를 사용하여 직렬 가능 대체로 대체 할 수 있습니다. [편집이 가능하지 않은 이유에 대한 최종 참조하여 대리] 첫 번째는 꽤 끔찍한이며, 나는 교차와 다른 옵션 중 하나를 수행하는 방법을 알아내는 데 실패 있었어요 그러나

AppDomain 원격.

누구든지 조언을 해줄 수 있습니까? 어떤 도움을 주셔서 감사합니다.

<?xml version="1.0"?> 
<configuration> 
    <runtime> 
    <legacyUnhandledExceptionPolicy enabled="true"/> 
    </runtime> 
</configuration> 

그리고 다음 코드 :

class Program 
{ 
    private class NonSerializableException : Exception 
    { 
    } 

    static void Main(string[] args) 
    { 
     AppDomain.CurrentDomain.UnhandledException += MainDomain_UnhandledException; 

     AppDomain childAppDomain = AppDomain.CreateDomain("Child"); 
     childAppDomain.UnhandledException += ChildAppDomain_UnhandledException; 

     childAppDomain.DoCallBack(
      () => new Thread(delegate() { throw new NonSerializableException(); }).Start()); 

     Console.ReadLine(); 
    } 

    static void MainDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Console.WriteLine("Main AppDomain Unhandled Exception: " + e.ExceptionObject); 
     Console.WriteLine(); 
    } 

    static void ChildAppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 
    { 
     Console.WriteLine("Child AppDomain Unhandled Exception: " + e.ExceptionObject); 
     Console.WriteLine(); 
    } 
} 



편집 :

는 다음의 App.config와 콘솔 응용 프로그램을 만들 재현하려면 I가 반사판을 사용 교차 AppDomain에 사용 된 BinaryFormatter에 액세스 할 수있는 방법이 있는지 확인하십시오. 원격,하지만 그것은 CrossAppDomainSerializer 클래스의 내부 코드에 끝 :

internal static void SerializeObject(object obj, MemoryStream stm) 
{ 
    BinaryFormatter formatter = new BinaryFormatter(); 
    RemotingSurrogateSelector selector = new RemotingSurrogateSelector(); 
    formatter.SurrogateSelector = selector; 
    formatter.Context = new StreamingContext(StreamingContextStates.CrossAppDomain); 
    formatter.Serialize(stm, obj, null, false); 
} 

그래서 방법에서 로컬 포맷을 생성하고, 내 자신의 대리를 부착하는 방법은 분명히 없다 ... 나는이 하나를 만드는 생각 그 방향으로 더 많은 노력이 쓸데없는.

+0

안녕하세요 James, 혹시 이것에 대한 해결책을 찾았습니까? – Joshjje

+0

@Joshjje, 좋은 해결책은 아니지만 ... 우리는 각 AppDomain 내에서 처리되지 않은 예외를 처리 한 다음 AppDomain이 거기에서 언로드되도록 허용했습니다. 이것은 분명히이 시스템을 설정하기 위해 각 애드 인을 신뢰해야합니다. 우리는 고맙게도 우리의 어플리케이션을 위해 그것을 할 수 있습니다. 그러나 주 AppDomain 내에서 전체 프로세스를 관리하는 방법을 찾지 못했습니다. –

답변

2

원격 응용 프로그램 도메인에서 예외를 처리합니다. 먼저 예외 처리 코드로 새 어셈블리를 만든 다음 자식 응용 프로그램 도메인에로드합니다.

다음 코드는 몇 가지 아이디어를 제공해야합니다.

class Program { 
    private class NonSerializableException : Exception { } 

    static void Main(string[] args) { 
     var childAppDomain = AppDomain.CreateDomain("Child"); 
     Console.WriteLine("Created child AppDomain #{0}.", childAppDomain.Id); 

     // I did not create a new assembly for the helper class because I am lazy :) 
     var helperAssemblyLocation = typeof(AppDomainHelper).Assembly.Location; 
     var helper = (AppDomainHelper)childAppDomain.CreateInstanceFromAndUnwrap(
       helperAssemblyLocation, typeof(AppDomainHelper).FullName); 
     helper.Initialize(UnloadHelper.Instance); 

     childAppDomain.DoCallBack(
      () => new Thread(delegate() { throw new NonSerializableException(); }).Start()); 

     Console.ReadLine(); 
    } 

    private sealed class UnloadHelper : MarshalByRefObject, IAppDomainUnloader { 
     public static readonly UnloadHelper Instance = new UnloadHelper(); 

     private UnloadHelper() { } 

     public override object InitializeLifetimeService() { 
      return null; 
     } 

     public void RequestUnload(int id) { 
      // Add application domain identified by id into unload queue. 
      Console.WriteLine("AppDomain #{0} requests unload.", id); 
     } 
    } 
} 

// These two types could be in another helper assembly 

public interface IAppDomainUnloader { 
    void RequestUnload(int id); 
} 

public sealed class AppDomainHelper : MarshalByRefObject { 
    public void Initialize(IAppDomainUnloader unloader) { 
     AppDomain.CurrentDomain.UnhandledException += (sender, e) => 
       unloader.RequestUnload(AppDomain.CurrentDomain.Id); 
    } 
} 
+0

감사의 말로는이 솔루션을 사용해도 NonSerializableException이 여전히 처리되지 않은 SerializationException으로 부모 AppDomain에 전파됩니다. 나는 AppDomain 자식에서 오는 SerializationException을 식별 할 수 없다. AppDomain은 그것을 무시하거나 다른 처리되지 않은 예외로 취급하고 응용 프로그램을 종료하도록 강제한다. –

+0

추가하기 만하면 Dispatcher.UnhandledException 이벤트를 처리하기 위해 제안한 것과 유사한 기술을 사용합니다 ... 예외를 처리 된 것으로 표시 할 수 있고 더 이상 전파하지 않기 때문에 실제로 제대로 작동합니다. AppDomain.UnhandledException 슬프게도 이것을 지원하지 않고 항상 주 AppDomain에 예외를 버블 링합니다. ( –

+0

자식 도메인에서 코드를 어떻게 실행합니까? 코드를 호출하고 남아있는 예외를 포착하는 도우미 메서드를 사용할 수 있습니까? 처리되지 않음? – mgronber

관련 문제