在BuildManager中创建后释放DLL

时间:2013-03-05 16:27:56

标签: c# .net dll build msbuild

我编写了一个C#WPF应用程序来在运行时编译代码。该应用程序基本上执行以下步骤

  1. 点击按钮[编译内容]
  2. 通过StreamWriter
  3. 创建代码文件
  4. 使用Microsoft.Build.Execution.BuildManager
  5. 构建代码文件
  6. 使用反射来访问DLL文件(Assembly.LoadFrom(filePath)
  7. 创建dll(assembly.CreateInstance(NamespaceName + "." + ClassName)
  8. 中包含的类的instanz

    我工作正常,但只有一次(我需要重新启动应用程序才能再次执行)

    这是下一次执行期间发生的事情

    1. 点击按钮[编译内容]
    2. 通过StreamWriter
    3. 创建代码文件
    4. 使用Microsoft.Build.Execution.BuildManager类构建代码文件 - >产生错误,说明DLL文件已被锁定。
    5.   

      该进程无法访问文件&DLL \ generatedflexform.dll'因为   它被另一个进程使用

      当我省略第2步时,问题不会发生,因为那时代码文件是相同的。因此,BuildManager不会重新创建/复制dll。

      我需要弄清楚BuildManager完成工作后如何释放DLL。这是因为代码文件很可能经常更改,否则我必须为每次代码更改关闭并重新打开应用程序。

      编辑:我的第一个想法是BuildManager导致锁定,但事实并非如此。 我宁愿认为当我尝试加载DLL时会发生锁定。我将尝试使用Shadow Copy思考(如@granadaCoder所述)。

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

2 个答案:

答案 0 :(得分: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>

这是完整的构建文件:

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

这里有编译魔法的方法&gt;         public Window BuildXamlWindowFromStrings(string xaml,string codeBehind)         {             // Erstellen der Codefiles(XAML和CodeBehind)             this.CreateCodeFile(代码隐藏);             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;
}

答案 1 :(得分: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