2013-03-05 3 views
1

런타임 중에 코드를 컴파일하기 위해 C# WPF 응용 프로그램을 작성했습니다. 응용 프로그램은 기본적으로 다음은BuildManager에서 생성 후 DLL 해제

  1. 클릭 버튼
  2. 가 DLL 파일에 액세스하는 반사를 사용하는 Microsoft.Build.Execution.BuildManager 클래스를 사용하여 StreamWriter
  3. 빌드 코드 파일을 통해 코드 파일 만들기 [물건 컴파일 (Assembly.LoadFrom(filePath)을) 단계 않는다
  4. 은 dll에 포함 된 클래스의 인스턴스를 만듭니다 (assembly.CreateInstance(NamespaceName + "." + ClassName))

나는 잘 작동하지만 한 번만

이것은

  1. 클릭 버튼
  2. [물건 컴파일] 다음을 실행하는 동안 발생하는 것입니다 (다시 그것을 할 응용 프로그램을 다시 시작해야합니다) StreamWriter
  3. 코드 파일 생성 Microsoft.Build.Execution.BuildManager 클래스를 사용하여 코드 파일 -> DLL 파일이 잠겨 있다는 오류가 발생합니다.

과정은

문제는 그때 때문에 2 단계를 생략하는 경우가 발생하지 않습니다 다른 프로세스에서 사용하고 때문에 파일 'DLL의 \의 generatedflexform.dll'를 액세스 할 수 없습니다 코드 파일은 동일합니다. 따라서 BuildManager은 dll을 다시 만들거나 복사하지 않습니다.

BuildManager이 작업을 마친 후 DLL을 해제하는 방법을 알아야합니다. 이것은 코드 파일이 자주 변경 될 가능성이 높기 때문이며 그렇지 않으면 모든 코드 변경을 위해 응용 프로그램을 닫고 다시 열어야하기 때문입니다.

편집 : 내 첫 번째 생각은 BuildManager가 잠금을 발생시키는 것이지만 그렇지 않습니다. DLL을로드하려고 할 때 잠금이 발생한다고 생각합니다. 섀도 복사본 생각을 시도 할 것입니다 (@ granadaCoder에서 언급했듯이).

private Window LoadWindowFromDll(string filePathToDll) 
{ 
    var assembly = Assembly.LoadFrom(filePathToDll); 
    var window = assembly.CreateInstance(NamespaceName + "." + ClassName) as Window; 
    return window; 
} 

답변

1

솔루션 :

내가

private Window LoadWindowFromDll(string filePathToDll) 
{ 
    byte[] readAllBytes = File.ReadAllBytes(filePathToDll); 
    Assembly assembly = Assembly.Load(readAllBytes); 

    var window = assembly.CreateInstance(NamespaceName + "." + ClassName) as Window; 

    return window; 
} 

그러나 어떻게 든 PDB 파일이 내가 두 번을 실행하려고 할 때 실패하는 빌드를 일으키는 잠겨 잠금 DLL을 피하기 위해 LoadWindowFromDllmethod을 변경했다. 여기

<DebugType>none</DebugType> 

는 전체 빌드 파일입니다 :

가 내 빌드 파일에 한 줄을 추가하여이 문제를 해결 여기

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> 
    <PropertyGroup> 
    <AssemblyName>generatedflexform</AssemblyName> 
    <OutputPath>DLL\</OutputPath> 
    <OutputType>Library</OutputType> 
    <DebugType>none</DebugType> 
    </PropertyGroup> 
    <ItemGroup> 
    <Reference Include="System" /> 
    <Reference Include="System.Data" /> 
    <Reference Include="System.Xml" /> 
    <Reference Include="Microsoft.CSharp" /> 
    <Reference Include="System.Core" /> 
    <Reference Include="System.Xml.Linq" /> 
    <Reference Include="System.Data.DataSetExtensions" /> 
    <Reference Include="System.Xaml"> 
     <RequiredTargetFramework>4.0</RequiredTargetFramework> 
    </Reference> 
    <Reference Include="WindowsBase" /> 
    <Reference Include="PresentationCore" /> 
    <Reference Include="PresentationFramework" /> 
    </ItemGroup> 
    <ItemGroup> 
    <Page Include="MyForm.xaml"> 
     <Generator>MSBuild:Compile</Generator> 
     <SubType>Designer</SubType> 
    </Page> 
    <Compile Include="MyForm.xaml.cs"> 
     <DependentUpon>MyForm.xaml</DependentUpon> 
     <SubType>Code</SubType> 
    </Compile> 
    </ItemGroup> 
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> 
</Project> 

그리고 컴파일 마법> 을 수행하는 방법을 제공 public Window BuildXamlWindowFromStrings (string xaml, string codeBehind) { // XAML und CodeBehind) this.CreateCodeFile (codeBehind); this.CreateXamlFile (xaml);

 //Erstellen der project file 
     this.CreateProjectFile(); 

     //Build der DLL 
     //using (var buildManager = BuildManager.DefaultBuildManager) 
     using (var buildManager = new BuildManager()) 
     { 
      var result = buildManager.Build(this.CreateBuildParameters(), this.CreateBuildRequest()); 

      if (result.OverallResult == BuildResultCode.Success) 
      { 
       return this.LoadWindowFromDll(FolderPath + DllRelativeFilePath + NamespaceName + DllFileExtension); 
      } 
     } 

     //Error handling 
     var stringbuilder = new StringBuilder(); 

     using (var reader = new StreamReader(DebuggerLogFileName)) 
     { 
      stringbuilder.Append(reader.ReadToEnd()); 
     } 

     throw new CompilerException(stringbuilder.ToString()); 
    } 

도우미 방법 :

private BuildParameters CreateBuildParameters() 
{ 
    var projectCollection = new ProjectCollection(); 
    var buildLogger = new FileLogger { Verbosity = LoggerVerbosity.Detailed, Parameters = "logfile=" + DebuggerLogFileName }; 
    var buildParameters = new BuildParameters(projectCollection) { Loggers = new List<ILogger>() { buildLogger } }; 
    return buildParameters; 
} 

private BuildRequestData CreateBuildRequest() 
{ 
    var globalProperties = new Dictionary<string, string>(); 
    var buildRequest = new BuildRequestData(FolderPath + ProjectFileName, globalProperties, null, 
              new string[] { "Build" }, null, BuildRequestDataFlags.ReplaceExistingProjectInstance); 
    return buildRequest; 
} 
+0

다른 솔루션을 활용할 수 있도록 솔루션을 게시 해 주셔서 감사합니다. – granadaCoder

0

"섀도 복사본"을 확인하십시오.

섀도 복사본을 사용하면 응용 프로그램 도메인에서 사용되는 어셈블리를 응용 프로그램 도메인을 언로드하지 않고도 업데이트 할 수 있습니다. 이는 특히 지속적으로 사용할 수 있어야하는 응용 프로그램에 유용합니다.

http://msdn.microsoft.com/en-us/library/ms404279.aspx

은 참조 :

http://gotchahunter.net/2010/12/net-how-do-you-load-an-assembly-programmatically-and-avoid-a-file-lock/

http://blogs.msdn.com/b/junfeng/archive/2004/02/09/69919.aspx

+0

내가 그것을 샷 – Joel

+0

섀도 복사를 줄 것이다, 감사합니다 정말 좋은뿐만 아니라 내 목적을 위해 조금 잔인한 것 같다. 그러나 나는 또 다른 해결책을 발견했다. – Joel