【问题标题】:Assembly dependencies issue程序集依赖问题
【发布时间】:2020-06-11 10:42:38
【问题描述】:

情况:

我有树项目(ZShared、ZSearcher 和 ZClient),它们将在其中相互引用。

ZShared 是一个常见的 DLL 程序集,包含一些样式和资源。

ZSearcher 也是一个带有一些 WPF 控件的 DLL 程序集。

ZClient 理论上可以是任何东西(WPF 应用程序、Winforms、Excel 等),用于测试目的我已将其作为 WPF 应用程序。

问题:

当我在 ZSearcher 中引用 ZShared 时,它会生成两个 DLL 文件:ZShared.DLL 和 ZSearcher.DLL

在 ZClient 中引用 ZSearcher 时,仅将 ZSearcher 复制到 ZClient 文件夹中。这也可以通过引用 ZShared 来解决。

但我希望 ZSearcher 作为独立应用程序运行。就像引用 ZSearcher 时一样,依赖项应该自动跟随。

因此,我认为也许使用反射而不是引用可以解决问题。但是反射也会出现完全相同的问题。

System.Windows.Markup.XamlParseException HResult=0x80131501
Message='Set property 'System.Windows.ResourceDictionary.Source' 抛出 一个例外。行号“10”和行位置“18”。
来源=PresentationFramework
堆栈跟踪:在 System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory,布尔值 skipJournaledProperties、对象 rootObject、XamlObjectWriterSettings 设置,Uri baseUri)在 System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, 布尔型 skipJournaledProperties、对象 rootObject、XamlAccessLevel accessLevel, Uri baseUri) 在 System.Windows.Markup.XamlReader.LoadBaml(流流,ParserContext parserContext, Object parent, Boolean closeStream) at System.Windows.Application.LoadComponent(对象组件,Uri resourceLocator) 在 ZSearcher.SearcherWindow.InitializeComponent() 在 C:\Users\nn\Desktop\WorkSpaceVS\TestApplication\ZSearcher\SearcherWindow.xaml:line 1

内部异常 1:FileNotFoundException:无法加载文件或 程序集 'ZShared, Culture=neutral' 或其依赖项之一。这 系统找不到指定的文件。

问题再现:

创建一个.NET-FrameworkC#DLL 装配项目(ZShared)。这个程序集只包含一个ResourceDictionary

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <SolidColorBrush x:Key="ZSolidColorBrushRed" Color="Red"/>
    <Style x:Key="ZButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Foreground" Value="Green"/>
    </Style>
</ResourceDictionary>

创建另一个 .NET-Framework C# DLL 程序集项目 (ZSearcher)。此程序集包含一个 Window 和一个 Class

Searcher.cs 类:

namespace ZSearcher
{
    public static class Searcher
    {
        public static object Search(string param)
        {
            var window = new SearcherWindow();
            window.ShowDialog();

            return null;
        }
    }
}

SearcherWindow.xaml:

<Window x:Class="ZSearcher.SearcherWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Height="300" Width="500"
         Title="ZSearcher">

   <Window.Resources>
       <ResourceDictionary>
           <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary Source="pack://Application:,,,/ZShared;component/ZResources.xaml"/>
           </ResourceDictionary.MergedDictionaries>
       </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <StackPanel Margin="20">
            <TextBlock Text="SolidColorBrush test" Foreground="{DynamicResource ZSolidColorBrushRed}"/>
            <Button Content="Button style test" Style="{DynamicResource ZButtonStyle}"/>
        </StackPanel>
    </Grid>
</Window>

在 ZSearcher 项目中引用 ZShared.DLL。

创建一个.NET-Framework WPF C# 应用程序。此应用仅包含 MainWindow。

MainWindow.xaml:

<Window x:Class="ZClient.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ZClient" Width="400" Height="200">
    <Grid>
        <Button Content="Open searcher" Click="OpenSearcher_Click" Width="100" Height="30"/>
    </Grid>
</Window>

MainWindow.cs

using System.Reflection;
using System.Windows;
using ZSearcher;

namespace ZClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void OpenSearcher_Click(object sender, RoutedEventArgs e)
        {
            //Referenced tester
            var referenceTest = Searcher.Search("Test");

            //Reflection tester
            var test = Test("Search");
        }

        private static object Test(string methodName)
        {
            var assembly = Assembly.LoadFrom(@"C:\Users\nn\Desktop\WorkSpaceVS\TestApplication\ZSearcher\bin\Debug\ZSearcher.DLL");
            var type = assembly.GetType("ZSearcher.Searcher");

            if (type == null) return null;
            var methodInfo = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);

            if (methodInfo == null) return null;
            var parametersArray = new object[] { "Test" };

            return methodInfo.Invoke(null, parametersArray);
        }
    }
}

问题:

如何使这个 ZSearcher 程序集独立工作?

【问题讨论】:

    标签: c# wpf dll .net-assembly


    【解决方案1】:

    当 MSBuild 构建解决方案时,它需要在 ZSearcher 和 ZShared 之间有一个代码级引用,以便正确检测依赖关系并将其复制到 ZClient bin 文件夹。

    有些人会创建一个虚拟代码引用来解决这个问题。

    using ZShared;
    
    namespace ZSearcher
    {
        public static class Searcher
        {
            static Searcher()
            {
                // Reference something from ZShared here...
            }
    
            public static object Search(string param)
            {
                var window = new SearcherWindow();
                window.ShowDialog();
    
                return null;
            }
        }
    }
    

    【讨论】:

    • 令人兴奋!使用反射时,不涉及复制。我的假设是它只是从绝对路径中读取 DLL。为什么需要虚拟参考?
    • 真的很奇怪。我个人没有遇到过这个问题,但是我在 SO 和其他地方发现了很多其他人,这些人多年来在 Visual Studio 的许多版本中一直在努力解决这个问题。这一切都归结为 MSBuild 中的黑盒魔法。当两个程序集之间存在实际代码引用时,MSBuild 将确保它们被正确复制。然而,仅仅依赖定义是不够的。很可能 MSBuild 只是想变得太聪明。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-02
    • 2010-12-23
    • 1970-01-01
    • 2014-01-05
    • 2016-03-12
    • 1970-01-01
    • 2011-03-19
    相关资源
    最近更新 更多