十大靠谱网赌平台-十大赌博平台排行榜

十大靠谱网赌平台-十大赌博平台排行榜

基于托管插件框架创建真正可靠的插件

表的内容

介绍

为了高质量和快速实现不同的客户需求,十大靠谱网赌平台需要插件. 学习过各种插件, 十大靠谱网赌平台发现微软的托管加载项框架(以下简称MAF)是十大靠谱网赌平台的最佳选择. 实践证明,十大靠谱网赌平台是正确的——插件可以工作, 用户满意, 顾客很满意. 然而,MAF有一个缺点——缺少描述如何使用它的文档和文章. 十大靠谱网赌平台所发现的只是贫乏的文档和一些关于Stack Overflow的文章. 然而, 十大靠谱网赌平台将通过描述如何从零开始创建一个插件来部分地解决这个问题, 考虑到在这个过程中使用MAF的所有细微差别.

十大靠谱网赌平台的项目之一是文档和电子邮件管理系统. 它被电视公司使用, 基本上是律师和医疗保健中心, 那些关心储存大量文件安全的人. 最初, 它的目的是作为文档的版本控制系统, 但是一个特征一个特征, 添加了新的功能来加快和简化文档工作, 包括开发文档和文档集的模板, 标签, 用电子邮件发送文件, 文档预览, 等等. 随着时间的推移, 用户需要越来越多的特定功能, 还有一种需要带有日期和时间戳的文档导出功能. 另一个则想添加带有页眉和页脚格式的文档, 而另一些则需要一种直观的方法来从模板创建一组文档. 如果所有这些特性都实现了,十大靠谱网赌平台的应用程序将会是这样的:

有太多工具栏的浏览器

为了避免这种拥塞, 十大靠谱网赌平台建议十大靠谱网赌平台的客户将特定的功能作为插件来实现,这些插件将包含在每个客户或组织的配置中. 这种方法也允许第三方开发者创建新的插件.

经过十大靠谱网赌平台插件平台的研究, 选择MAF是因为它允许在 .净框架,并提供以下必需的特性:

  • 发现:从主机支持的契约中继承的插件.
  • 激活:加载、启动和建立与插件的连接.
  • 隔离:使用应用程序域或进程创建隔离边界,以保护主机免受可能的安全问题或未处理的异常.
  • 交互:通过方法调用和数据交换,在主机和插件之间提供跨隔离边界的通信.
  • 生命周期管理:可预测且易于使用的应用域和进程的加载和卸载.
  • 版本控制:当创建新版本的主机或插件时,验证主机和插件是否可以通信.

MAF中的基本元素是契约,它定义了主机和插件如何通信. 主机使用一个host视图的契约,而插件使用一个插件视图的契约. 对于通过视图在插件和主机之间进行数据交换,需要使用适配器:

隔离边界

契约、视图和适配器都是组成插件管道的段. 管道处理插件和主机之间的数据交换,并支持版本控制, 生命周期管理, 和隔离.

通常,在宿主应用程序中需要显示插件UI. 因为不同的 .净框架技术有不同的UI实现,WPF扩展了 .净 Framework插件模型,支持插件接口显示.

MAF技术的发布范围是 .净框架3.5和目前尚未更改. 这使得这项技术显得过时,其复杂性也吓跑了用户. 实施这五条管道的必要性似乎有些过分, 但正是这种方法提供了隔离和版本控制.

例如, 让十大靠谱网赌平台实现一个简单的应用程序,显示选定文件夹中的文件列表,并添加一个插件,将文件复制到导出文件夹,并将其转换为PDF.

开始

项目和文件夹结构

首先,让十大靠谱网赌平台看看插件的管道结构:

管道结构

加载项的宿主视图

包含接口或抽象类,它们代表插件的宿主视图以及在它们之间流动的类型.

合同

如果主机和插件被加载到单独的应用域, 那么契约段就是它们之间的一个隔离边界.

需求:所有契约都必须继承自I合同接口. 合同Base类包含IContact的基本实现. 隔离的原因, 合同只能使用从合同衍生而来的其他合同, 原始数据类型(整数和布尔类型), 可序列化的类型(引用类型和在Mscorlib中定义的类型.或枚举(在Mscorlib . dll中定义).DLL或契约程序集中).

建造管道, 表示外接程序的契约必须用外接程序合同Attribute属性标识.

外接程序视图

接口或抽象类作为视图提供给主机, 它们的类型在插件和主机之间流动.

建造管道, 外接程序实现或继承的外接程序视图中的类型由外接程序BaseAttribute标识.

Host-side适配器

视图可以转换为契约,反之亦然,这取决于调用的方向.

视图到契约的适配器通过调用传递给其构造函数的视图来实现契约,并作为契约跨边界编组. 这个类必须继承合同Base并实现契约. 与此同时, 契约到视图适配器实现或继承它正在转换的视图段, 这取决于视图是接口还是抽象基类型, 并通过调用传递给适配器构造函数的契约来实现视图的成员.

建造管道, 您必须通过应用HostAdapterAttribute属性来识别主机端适配器类.

Add-in-side适配器

这些与主机端适配器相同, 但相比之下, 他们将契约转换为插件视图.

建造管道, 必须通过应用外接程序AdapterAttribute属性来识别外接程序端适配器类.

对于每个管道段,应该有一个对应的项目和文件夹(主机除外). 让十大靠谱网赌平台为管道创建所有必要的项目(所有项目的项目类型应该是“类库”):

  1. 管道.合同. 增加对系统的引用.外接程序и系统.外接程序.合同.
  2. 管道.外接程序Views. 增加对系统的引用.外接程序.
  3. 管道.HostViews.
  4. 管道.外接程序Adapters. 增加对系统的引用.外接程序、系统.外接程序.合同,管道.外接程序Views、管道.合同. 对于最后两个引用,应该禁用复制到输出文件夹(Copy local = False). 否则, MAF不会识别要加载的dll, 而这段管道在施工时不会被加载.
  5. 管道.HostAdapters. 对于管道来说也是如此.adddinadapters,而不是管道项目.外接程序Views指的是管道.HostViews.
  6. DemoPlugin(主机).

所有这些库输出应该映射到一个严格的文件夹结构:

 MAF的褶皱结构

主机视图可以位于任何位置,因为它被主机使用.

配置在分配给适当目录的所有项目中复制生成结果. 输出如下:

 Note: It is important to copy each 插件 to a separate folder; otherwise, MAF will not find them Note: It is important to copy each 插件 to a separate folder; otherwise, MAF will not find them.

实现主机到插件的通信

让主机能够管理插件, 十大靠谱网赌平台需要创建一个由插件实现的契约. 让十大靠谱网赌平台开始创建一个接口,其中有一个返回插件显示名称的方法:

[外接程序Base]
公共 接口 IExportPluginView
{
  字符串 DisplayName { 得到; }
}

在主机视图和插件视图中使用MAF接口可能会导致不同的结果, 适配器将使它们相互适应. 为了简化这个过程,让十大靠谱网赌平台在所有管道段中使用类似的接口. IExportPluginView应该在管道中创建.外接程序Views、管道.合同和管道.HostViews项目. 区别在于插件视图中的接口必须有外接程序Baseattribute(允许MAF将这个类识别为插件), 契约中的接口应该继承自合同Base.

然后,应该创建适配器类. 首先,让十大靠谱网赌平台从插件视图到契约视图来看看适配器:

[外接程序Adapter]
公共 class ExportPluginViewTo合同Adapter : 合同Base, 管道.合同.IExportPlugin
{	
  私人 只读的 管道.外接程序Views.IExportPluginView视图;
  公共 字符串 DisplayName => 视图.DisplayName;
  
  公共 ExportPluginViewTo合同Adapter(管道.外接程序Views.IExportPluginView视图)
  {
  	.视图=视图;
  }
}

作为参数,构造函数在插件视图中接受相应的if接口. 外接程序Adapter属性应该应用于这个类.

然后,适配器可以在宿主视图(project 管道)中从契约中创建.HostAdapters):

[HostAdapter]
公共 class ExportPlugin合同ToHostAdapter : IExportPluginView
{
  私人 只读的 合同.IExportPlugin合同;
  私人 只读的 合同H和le处理;
  
  公共 字符串 DisplayName => 合同.DisplayName;
  
  公共 ExportPlugin合同ToHostAdapter(合同.IExportPlugin合同)
  {
  	.合同=合同;
    处理=  合同H和le(合同);
  }
}

HostAdapter属性应用于此适配器, 作为一个构造函数参数, 它获得相应的联系人接口的实例. 这个句柄由合同t处理类管理. 因为插件和主机通常在不同的应用域, 标准垃圾收集不能正常工作. 合同th处理通过使用内置的跟踪令牌来接收和释放契约实例来解决这个问题.

插件激活和集成

第一次激活插件, 应该通过指定所有管道库所在的目录来更新管道缓存. 在十大靠谱网赌平台的例子中,它是主机可执行文件旁边的' 管道 '文件夹:

字符串 pipelinePath =路径.结合(路径.GetDirectoryName(组装.GetExecutingAssembly ().位置), “管道”); 

外接程序Store.更新(pipelinePath); 

因此,MAF创建了两个文件:

  • “管道/ 管道Segments.Store " -管道段缓存
  • “管道/外接程序/外接程序.-插件缓存在外接程序s文件夹.

当插件代码或管道段的接口/对象改变时, 必须删除相应的缓存文件,以便下次启动时再次生成.

如果插件不在addin文件夹中,也应该为它们创建一个缓存文件:

外接程序Store.Update外接程序s (otherPluginsPath);

在这个例子中,' otherPluginsPath '是一个插件路径列表. 除了, Update外接程序s方法用于更新添加的插件的信息, 删除或更改.

然后,需要找到所有实现IExportPlugin接口的插件:

var addInTokens = 外接程序Store.Find外接程序s (typeof(IExportPluginView) pipelinePath);

接口类型, 管道目录, 搜索所有可能出现插件的目录路径列表. 结果,将返回一个外接程序Token对象列表. 外接程序Token类包含了一个插件的基本信息,并且有一个插件激活方法.

有几个插件激活选项取决于所需的主机隔离:

  1. 没有隔离:插件和主机运行在相同的进程和应用程序域.

    这种隔离提供了最低限度的保护和安全:所有数据都是可用的, 没有针对未处理异常的保护, 并且没有能力卸载有问题的代码. 有可能因为插件中未处理的异常而导致主机故障.

  2. 介质隔离:每个插件运行在自己的应用域.

    使用这个选项, 安全级别和激活配置可以通过激活方法参数进行管理. 也, 这个选项提供了在出现错误时卸载插件的能力, 但在某些情况下, 这可能行不通, 因此,插件可能仍然会使整个应用程序崩溃.

  3. 高的隔离:每个插件在自己的进程中运行.

    这个选项为主机提供了最大的安全性,因为插件异常不会导致崩溃. 同时, 这个选项需要更复杂的实现多个主机的进程间通信和同步. 在进程之间传递WPF元素也更加费力.

为十大靠谱网赌平台的项目, 选择第二种介质隔离是因为它提供了足够的安全性和灵活性,并且不需要复杂的进程间通信实现. 在十大靠谱网赌平台的演示中,让十大靠谱网赌平台也选择具有最低安全级别的中间隔离选项.

var 插件= addInTokens.第().Activate(外接程序SecurityLevel.FullTrust);

因此,一个插件类实例将被创建. 例如,它可以用来显示激活插件的名称:

对话框.显示(美元的“插件”{插件.DisplayName}“已经被激活”“加演示信息”, 对话框Button.OK);

扩展功能

实现从插件到主机的反向通信

在某些情况下,插件可能需要来自主机应用程序的数据. 例如,可能需要获取最新的文档版本或文档属性. 要做到这一点, 应该创建一个特殊的契约,并作为参数传递给初始化插件方法.

现在,让插件API有一个方法返回文件的最后修改日期和时间. 让十大靠谱网赌平台在管道段中创建IPluginApi: HostView, 外接程序View和合同(不要忘记设置外接程序合同属性并从I合同继承——和IPluginView一样):

[外接程序合同]
公共 接口 IPluginApi : I合同
{
	DateTime GetLastModifiedDate(字符串 路径);
}

这个步骤需要一个适配器和IPluginView,但方向相反. 相应的, 在主机端适配器级别, 这将是从主机视图到联系人的适配器, 在插件端适配器级别, 这将是从契约到插件视图的适配器:

[HostAdapter]
公共 class PluginApiHostViewTo合同Adapter : 合同Base, IPluginApi
{
  私人 只读的 HostViews.IPluginApi视图;
  
  公共 PluginApiHostViewTo合同Adapter(HostViews.IPluginApi视图)
  {
  	.视图=视图;
  }
  
  公共 DateTime GetLastModifiedDate(字符串 路径)
  {
  	返回 视图.GetLastModifiedDate(路径);
  }
}

使用这些适配器, 十大靠谱网赌平台需要添加初始化方法, 它们将依次在适配器中使用如下:

主机适配器:

公共 无效 初始化(IPluginApi api)
{
  合同.初始化( PluginApiHostViewTo合同Adapter (api));
}

插件适配器:

公共 无效 初始化(IPluginApi api)
{
  视图.初始化( PluginApi合同ToPluginViewAdapter (api));
}

最后,让十大靠谱网赌平台实现管道.HostView.在主机端的IPluginApi接口上初始化十大靠谱网赌平台的插件:

var 插件= addInTokens.第().Activate(外接程序SecurityLevel.FullTrust); 

插件.初始化( PluginApi ()); 

添加插件的用户界面

在宿主应用程序中显示插件UI, MAF有一个特殊的INativeH和le接口,用于保存窗口描述符(Hwnd). 在从资源中获取窗口描述符之后, INativeH和le在应用域之间传递,这样宿主就可以显示插件的UI元素.

来演示它是如何工作的, 让十大靠谱网赌平台添加一个返回小插件面板元素的方法, 主机将在它的窗口中显示它.

在host和插件 segment方法中,返回的UI面板将声明如下:

FrameworkElement GetPanelUI()

然而, 在合同部分, 使用相同的inative处理c合同跨越隔离边界进行传递.

INativeH和le合同 GetPanelUI();

要在插件端适配器中创建inative处理c合同,需要使用集成在MAF中的转换器:

公共 INativeH和le合同 GetPanelUI()
{
  FrameworkElement =视图.GetPanelUI ();
  返回 FrameworkElementAdapters.ViewTo合同Adapter (frameworkElement);
}

要从描述符接口获取UI元素,需要使用逆转换器方法:

公共 FrameworkElement GetPanelUI() 
{
  inative处理con合同 处理con合同 =合同.GetPanelUI ();
  返回 FrameworkElementAdapters.合同ToViewAdapter (处理合同); 
} 

要使用FrameworkElementAdapters类,请添加对System的引用.窗户.介绍图书馆.

做完这些之后, 剩下的唯一步骤是创建一个控件,按需传递给主机应用程序:

公共 FrameworkElement GetPanelUI() 
{
  返回  PanelUI (); 
} 

反过来,宿主可以使用这个UI元素作为ContentControl的内容. 结果可能是这样的:

UI中的插件面板

以这种方式传递UI元素有一些细微差别:

  • 触发器不能应用于插件元素.
  • 插件元素将始终显示在其他元素的顶部,而不管ZIndex. 然而,其他应用程序窗口(e.g., 对话框和弹出窗口)将被正确显示(这就是为什么十大靠谱网赌平台必须使用弹出窗口更改toast通知的实现).
  • Plugin elements will not be displayed at all if windows have opacity or transparency; in addition, AllowTransparenсy属性必须设置为false(在十大靠谱网赌平台的例子中, 显示插件UI的问题是由WindowChrome引起的.GlassFrameThickness属性).
  • 主机无法从插件元素接收到任何鼠标事件或GotFocus和LostFocus事件. 此外,IsMouseOver属性始终为false.
  • VisualBrush不能在插件元素中使用,媒体不能在媒体Element上播放.
  • 转换(e.g.,旋转,缩放和螺丝)不能应用于插件元素.
  • The 插件 element will not display XAML changes on the fly; instead, 你必须构建一个插件并刷新缓存文件来更新元素的UI.
  • 在插件关闭之前,所有在插件中使用的调度程序都应该手动关闭. 要做到这一点,相应的方法应该在插件契约中实现. 这将允许主机在关闭插件之前发出信号.

插件stylisation

为了使插件UI看起来与宿主UI一致,常见控件和元素的样式(如.g.、按钮、输入、组合框、文本块等.)可以被提取到一个单独的库中,供主机和插件使用.

要做到这一点, 添加一个类型为“类库”的新项目, create ResourceDictionary items with styles to be shared, 并创建一个ResourceDictionary来合并所有这些字典:

AllSTyles.XAML

在插件中使用这些样式, 添加对共享样式库的引用,并引用包含XAML文件中所有资源字典的合并字典, 可以应用样式的地方:

<用户控件.资源> 
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries> 
            <ResourceDictionary Source=“包:/ /应用程序:…/演示./ AllStyles风格;组件.xaml”/> 
         ResourceDictionary.MergedDictionaries> 
    ResourceDictionary> 
用户控件.资源> 

下一个, 使用静态或动态资源引用为元素设置适当的样式,或保持其默认样式.

将共享样式库的所有依赖项和第三方库复制到插件输出文件夹中是很重要的. 可以使用带有xcopy命令的后构建事件来实现这一点.

插件停用和关机

有时,应用程序使用场景可能需要卸载插件,加载其他插件. 就十大靠谱网赌平台的项目而言, 在更改到十大靠谱网赌平台器的连接时,这是必要的, 因为每个十大靠谱网赌平台器都有自己的插件集,可以在客户端使用.

插件卸载包括两个步骤:

1. 关闭合同处理.

释放通过管道连接插件和主机的引用和资源是必要的. 实践证明了这一步骤的必要性, 因为有时插件会导致一个错误,该错误指的是在重新激活时无法在插件端适配器上创建契约的句柄.

要做到这一点,插件端适配器应该包含一个方法来处理契约句柄:

[外接程序Adapter] 
公共 class PluginApi合同ToPluginViewAdapter : 外接程序Views.IPluginApi
{
  公共 无效 卸载()
  {
  	处理.处理();
  }
} 

要从主机调用这个方法,也要把它添加到IPluginHostView接口中.

2. 关闭插件

一个插件和它的控制器关闭. 要获取控制器,使用一个插件对象实例:

var 控制器= 外接程序Controller.Get外接程序Controller(插件); 

控制器.关闭();  

shutdown方法通过管道终止主机和插件之间的连接. 此外,如果插件应用域是在插件激活时创建的,那么它将被卸载. 如果插件在关闭方法后在主机应用程序域的范围内被激活, 管道段将不再有对插件实例的引用.

结论

乍一看,MAF似乎过于庞大,可能需要大量重复的代码. 然而, 十大靠谱网赌平台的实践已经展示了开发人员如何习惯在所有管道段中实现新功能, 这似乎不再那么困难了. 编写良好的适配器,带有帮助器和转换器方法和类,可以轻松快速地添加新函数,并在将来扩展现有函数.

总体而言,该技术工作稳定可靠. 十大靠谱网赌平台开发了7个客户经常使用的插件, 而且也没有一个会导致用户注意到的应用程序崩溃.

P. S. 演示应用程序的完整代码可以在下面找到 github.

你可能也喜欢

博客文章 基于表达式树的业务规则编译器
2022年2月09年,
在这篇文章中, 我将告诉您十大靠谱网赌平台如何创建用户通知特性,以及十大靠谱网赌平台如何最终构建了一个基于表达式树的编译器,帮助十大靠谱网赌平台成功地完成了这项任务.
博客文章 例外中的例外 .净
2021年12月24日
c# /中的异常 .净可以有不同的行为. 并不是所有的,也不是所有的,都可以被处理和拦截. 本文描述了一组“击败”尝试-捕获-最终模式的异常.
博客文章 具有示例的可访问组件设计
2021年12月13日
关于ARIA属性、焦点顺序等的设计器指南. 如果您设计新的组件,这些信息将派上用场, 测试接口, 或者和前端工程师一起工作.