2013-03-05 57 views
1

我編寫了一個C#WPF應用程序來在運行時編譯代碼。該應用程序主要進行以下的工序在BuildManager中創建後發佈DLL

  1. 點擊按鈕[編譯東西]
  2. 通過StreamWriter
  3. 生成代碼文件使用Microsoft.Build.Execution.BuildManager
  4. 使用反射來訪問該DLL文件創建代碼文件(Assembly.LoadFrom(filePath)
  5. 創建一個包含在dll中的類的實例(assembly.CreateInstance(NamespaceName + "." + ClassName)

我工作得很好,但只有一次(我需要重新啓動應用程序做一遍)

這是下一個執行過程中發生了什麼

  1. 點擊按鈕[編譯東西]
  2. 通過StreamWriter創建代碼文件
  3. 使用Microsoft.Build.Execution.BuildManager類構建代碼文件 - >產生錯誤,指出DLL文件已被鎖定。

的過程不能訪問因爲 它正被另一個進程文件「DLL \ generatedflexform.dll」

當我離開了步驟2,因爲然後該問題不會發生代碼文件是相同的。因此BuildManager不會重新創建/複製dll。

我需要弄清楚BuildManager完成他的工作後如何釋放DLL。這是因爲代碼文件可能會經常更改,否則我必須關閉並重新打開每個代碼更改的應用程序。

編輯:我的第一個想法是BuildManager導致鎖定,但事實並非如此。 我寧願當我嘗試加載DLL時發生鎖定。我會嘗試Shadow Copy think(如@granadaCoder所述)。

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

回答

1

解決方案:

我不得不改變LoadWindowFromDllmethod避免DLL鎖定

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文件被鎖定從而導致當我嘗試兩次執行它失敗的構建。

<DebugType>none</DebugType> 

下面是完整的構建文件:

我通過添加一行到我的build文件解決了這個問題

<?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> 

這裏來這做編譯魔> 方法公共窗口BuildXamlWindowFromStrings(字符串xaml,字符串codeBehind) // Erstellen der Codefiles(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 2013-03-06 14:04:12

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 2013-03-06 09:37:24

+0

陰影複製似乎是非常好的,但也爲我的目的有點大材小用。但是我找到了另一個解 – Joel 2013-03-06 10:03:14