2014-07-04 2 views
5

샌드 박스 AC# 스크립트 컴파일러를로드하는 방법을 연구 한 후로드 된 어셈블리가 기본 AppDomain이 아닌 샌드 박스 AppDomain에만로드되도록 실행했습니다. 모든 dll 파일을 AppDomain 샌드 박스를 언로드 할 때 언로드합니다.AppDomain을 언로드 한 후 모든 어셈블리가 해제됩니다.

return new Func<List<int>,int> 
(
    (list) => 
    { 
    var total = 0; 
    foreach (int i in list) 
    { 
     total += i;   
    } 
    return total; 
    } 
); 

이제 어떻게 스크립트의 반환에 발생하는 그들은 모두 결국 기본 응용 프로그램 도메인에 사전에 반환이다 : 그것은 하나처럼 보이는 스크립트입니다. 나머지 스크립트는 모두 간단한 직렬화 가능 객체 또는 프리미티브를 반환하며 모든 어셈블리가 올바르게 언로드되었다고 말했고 여전히 기본 도메인을 사용하여 삭제할 수있었습니다. 이 특정 반환 값이 Func이므로 기본 AppDomain에 생성 어셈블리를 "전달"해야합니까? 이 주변에 방법이 없을까요?

처음부터 샌드 박스가있는 이유는 스크립트 집합을 실행 한 후에 실행 한 개체를 처리 할 수 ​​있고 dispose 메서드가 샌드 박스 도메인을 언로드하고 생성 된 어셈블리를 모두 삭제하기 때문입니다. 어셈블리의 빌드가 문제가되는 웹 서버와 같이 지속적으로 실행되는 환경에서 이것을 사용할 수 있기를 원합니다. 현재 스크립트 세트가 Func을 반환 할 때마다 느린 어셈블리가 있습니다. 차라리이 라이브러리를 사용하는 문서 옆에 별표가 없으므로 어떤 아이디어라도 환영받을 것입니다.

var provider = new CSharpCodeProvider(new Dictionary<string, string>() { { CompilerOptionName, CompilerOptionVersion } }); 
     var compilerParams = new CompilerParameters { GenerateExecutable = false, GenerateInMemory = false }; 
     compilerParams.ReferencedAssemblies.AddRange(References); 
     compilerParams.TempFiles = new TempFileCollection(BinPath); 
     compilerParams.OutputAssembly = Path.Combine(BinPath, 
      Utilities.AssemblyPrefix + ProfigurationExe.Profiguration.ID + "_" + Action.ID + "_Script" + Utilities.DllExt); 
     // If no object is returned by user code, enter in a return null to satisfy returning an object for 
     // default code template. If they do have a return that will return first. 
     Code = Code + ReturnNull; 
     var parameterString = BuildParameterString(); 
     parameterString = !String.IsNullOrEmpty(parameterString) ? ", " + parameterString : String.Empty; 

     // If someone simply imports namespaces separated by spaces, commas, or semicolons, create a proper using statement 
     if (!String.IsNullOrEmpty(Imports) && !IsUsingRegex.IsMatch(Imports)) 
     { 
      Imports = String.Join("; ", Imports.Split(" ,;".ToCharArray()).Select(s => Using + " " + s)) + "; "; 
     } 
     FinalCode = String.Format(Imports + CodeTemplate, 
      new object[] {DefaultNamespace, ClassName, DefaultMethod, parameterString, Code}); 
     // This just is a variable of the code that will be compiled, with all spaces and line breaks removed 
     var debugFriendlierFinalCode = U.CompressWhiteSpaceRegex.Replace(FinalCode.Replace("\r", String.Empty).Replace("\n", String.Empty), U.OneSpace); 
     // Note that we are adding the import fields to the beginning in case user wants to import namespaces (and not have to always use fully qualified class names) 
     var results = provider.CompileAssemblyFromSource(compilerParams, FinalCode); 
     Assembly = results.CompiledAssembly; 
     if (!results.Errors.HasErrors) 
     { 
      return Assembly; 
     } 


     // If there were compiler errors, aggregrate them into an exception. 
     var errors = new StringBuilder("Dynamic Code Compiler Errors :\r\n"); 
     foreach (CompilerError error in results.Errors) 
     { 
      errors.AppendFormat("Line {0},{1}\t: {2}\n", 
       error.Line, error.Column, error.ErrorText); 
     } 
     throw new ProfigurationException(errors.ToString()); 
+0

http://msdn.microsoft.com/en-us/library/system.marshalbyrefobject%28v=vs.110%29.aspx –

+0

감사합니다. 예, 도메인간에 전달되는 모든 객체에 대해이를 사용합니다. –

답변

4

Func가 직렬화 가능하고 의도처럼 복사되는 :

는 참고로, 여기에 스크립트를 컴파일 내 코드입니다. 그러나 언로드하려는 어셈블리 내부에있는 코드를 가리 킵니다. 이것이 어셈블리가 상위 AppDomain에도로드되는 이유입니다.

무엇을 권하고 싶습니다. 사용중인 코드를 언로드 할 수 없다는 의미가되기를 바랍니다.

+0

응답 해 주셔서 감사합니다. 사실입니다. 이 질문을 한 다음에는 위임 유형이 기본적으로 항상이 정보를 유지할 것이며 AppDomains를 통해 "복사본"을 전달하여 생성 된 어셈블리가로드되지 않도록 할 수는 없습니다. 내가하고자하는 일은 출력에서 ​​모든 델리게이트 유형 (Func, Action 등)을 필터링하는 옵션이 있습니다. 사용자가 대리인을 필터링하지 않도록 선택한 경우 기본 앱 도메인의 원래 코드 문자열에서 다시 생성되므로 보조 앱 도메인의 임시 DLL이 여전히 언로드 될 수 있습니다. –