使用 WCF LOB 配接器 SDK 建立部署套件
在開發週期期間,您可以在 Visual Studio 內建置、偵錯和執行配接器。 配接器解決方案的輸出是 DLL 元件。 您可以使用 Visual Studio IDE 建置配接器解決方案,或使用 devenv.exe 腳本來建立配接器元件。 一旦開發配接器並準備好在配接器取用者的環境中使用,您必須建立部署套件,以允許在測試和生產環境中安裝介面卡。
您可以在方案中包含 Visual Studio 安裝程式和部署專案。 這可用來在解決方案組建中自動產生 .msi 檔案。
注意
您可以透過 Visual Studio .NET 內的 [建置] 功能表上的 [建置]) 功能表的 [Configuration Manager (排除方案,以防止每次在本機工作站上建置方案時建置安裝程式和部署專案。 如果您使用此方法從方案組建中排除專案,則不會影響原始檔控制的解決方案檔。 變更會保留在解決方案使用者選項檔案內,這是開發人員特定的,而不是在原始檔控制之下。
每當將新專案新增至您的方案時,您必須記得更新和設定部署專案,以確保新專案的輸出包含在 .msi 檔案中,以及執行任何專案特定的安裝步驟。
它不足以在使用者的電腦上安裝配接器專案的輸出。 介面卡必須安裝在全域組件快取中, (GAC) ,而且必須更新 machine.config 檔案,才能向 WCF 註冊配接器。
以下是可用來向 WCF 註冊或取消註冊配接器的範例自訂動作。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Reflection;
using System.ServiceModel.Configuration;
using System.Diagnostics;
using System.Configuration;
namespace Microsoft.Adapters.Samples.EchoV2
{
//Custom action to register the adapter with WCF configuration in machine.config
//<system.serviceModel>
// <extensions>
// <bindingElementExtensions>
// <add name="{BINDINGELEM_NAME}" type="{BINDINGELEM_TYPE}, {Assembly Information}" />
// </bindingElementExtensions>
// <bindingExtensions>
// <add name="{BINDING_NAME}" type="{BINDING_TYPE}, {Assembly Information}" />
// </bindingExtensions>
// </extensions>
// <client>
// <endpoint binding="{BINDING_NAME}" contract="IMetadataExchange" name="{BINDING_SCHEME}" />
// </client>
//</system.serviceModel>
[RunInstaller(true)]
public partial class WCFLOBAdapterInstaller : Installer
{
private Assembly adapterAssembly;
private Type bindingSectionType;
private Type bindingElementExtensionType;
const string INSTALLER_PARM_INSTALLDIR = "INSTALLDIR";
const string BINDING_ASSEMBLY_NAME = "Microsoft.Adapters.Samples.EchoV2.EchoAdapter.dll";
const string BINDINGELEM_NAME = "echoAdapterV2";
const string BINDINGELEM_TYPE = "Microsoft.Adapters.Samples.EchoV2.EchoAdapterBindingElementExtensionElement";
const string BINDING_NAME = "echoAdapterBindingV2";
const string BINDING_TYPE = "Microsoft.Adapters.Samples.EchoV2.EchoAdapterBindingCollectionElement";
const string BINDING_SCHEME = "echov2";
/// <summary>
/// Constructor - initialize the components and register the event handlers
/// </summary>
public WCFLOBAdapterInstaller()
{
InitializeComponent();
this.AfterInstall += new InstallEventHandler(AfterInstallEventHandler);
this.BeforeUninstall += new InstallEventHandler(BeforeUninstallEventHandler);
}
/// <summary>
/// Add the WCF configuration information in machine.config when installing the adapter.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AfterInstallEventHandler(object sender, InstallEventArgs e)
{
try
{
Debug.Assert(this.Context != null, "Context of this installation is null.");
string path = this.Context.Parameters[INSTALLER_PARM_INSTALLDIR] + BINDING_ASSEMBLY_NAME;
adapterAssembly = Assembly.LoadFrom(path);
Debug.Assert(adapterAssembly != null, "Adapter assembly is null.");
bindingSectionType = adapterAssembly.GetType(BINDING_TYPE, true);
Debug.Assert(bindingSectionType != null, "Binding type is null.");
bindingElementExtensionType = adapterAssembly.GetType(BINDINGELEM_TYPE, true);
Debug.Assert(bindingElementExtensionType != null, "Binding element extension type is null.");
AddMachineConfigurationInfo();
}
catch (Exception ex)
{
throw new InstallException("Error while adding adapter configuration information. " + ex.InnerException.Message);
}
}
/// <summary>
/// Registers the adapter with the WCF configuration
/// NOTE: The
/// </summary>
public void AddMachineConfigurationInfo()
{
System.Configuration.Configuration config = ConfigurationManager.OpenMachineConfiguration();
Debug.Assert(config != null, "Machine.Config returned null");
// add <client><endpoint>
ServiceModelSectionGroup sectionGroup = config.GetSectionGroup("system.serviceModel") as ServiceModelSectionGroup;
if (sectionGroup != null)
{
bool channelEndpointElementExists = false;
// this call can throw an exception if there is problem
// loading endpoint configurations - e.g. each endpoint
// tries to load binding which in turn loads the DLL
ClientSection clientSection = sectionGroup.Client;
foreach (ChannelEndpointElement elem in clientSection.Endpoints)
{
if (elem.Binding.Equals(BINDING_NAME, StringComparison.OrdinalIgnoreCase) && elem.Name.Equals(BINDING_SCHEME, StringComparison.OrdinalIgnoreCase) && elem.Contract.Equals("IMetadataExchange", StringComparison.OrdinalIgnoreCase))
{
channelEndpointElementExists = true;
break;
}
}
if (!channelEndpointElementExists)
{
Debug.WriteLine("Adding ChannelEndpointElement for : " + BINDING_NAME);
ChannelEndpointElement elem = new ChannelEndpointElement();
elem.Binding = BINDING_NAME;
elem.Name = BINDING_SCHEME;
elem.Contract = "IMetadataExchange";
sectionGroup.Client.Endpoints.Add(elem);
Debug.WriteLine("Added ChannelEndpointElement for : " + BINDING_NAME);
}
// add <bindingElementExtension>
if (!sectionGroup.Extensions.BindingElementExtensions.ContainsKey(BINDINGELEM_NAME))
{
ExtensionElement ext = new ExtensionElement(BINDINGELEM_NAME, bindingElementExtensionType.FullName + "," + bindingElementExtensionType.Assembly.FullName);
sectionGroup.Extensions.BindingElementExtensions.Add(ext);
}
// add <bindingExtension>
if (!sectionGroup.Extensions.BindingExtensions.ContainsKey(BINDING_NAME))
{
ExtensionElement ext = new ExtensionElement(BINDING_NAME, bindingSectionType.FullName + "," + bindingSectionType.Assembly.FullName);
sectionGroup.Extensions.BindingExtensions.Add(ext);
}
config.Save();
}
else throw new InstallException("Machine.Config doesn't contain system.serviceModel node");
}
/// <summary>
/// Remove the machine configuration information when uninstalling the adapter
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BeforeUninstallEventHandler(object sender, InstallEventArgs e)
{
try
{
RemoveMachineConfigurationInfo();
}
catch (Exception ex)
{
throw new InstallException("Error while removing adapter configuration information" + ex.InnerException.Message);
}
}
/// <summary>
/// Unregisters the adapter with WCF configuration
/// </summary>
public void RemoveMachineConfigurationInfo()
{
System.Configuration.Configuration config = ConfigurationManager.OpenMachineConfiguration();
Debug.Assert(config != null, "Machine.Config returned null");
ServiceModelSectionGroup sectionGroup = config.GetSectionGroup("system.serviceModel") as ServiceModelSectionGroup;
ChannelEndpointElement elemToRemove = null;
if (sectionGroup != null)
{
// Remove <client><endpoint>
foreach (ChannelEndpointElement elem in sectionGroup.Client.Endpoints)
{
if (elem.Binding.Equals(BINDING_NAME, StringComparison.OrdinalIgnoreCase) && elem.Name.Equals(BINDING_SCHEME, StringComparison.OrdinalIgnoreCase) && elem.Contract.Equals("IMetadataExchange", StringComparison.OrdinalIgnoreCase))
{
elemToRemove = elem;
break;
}
}
if (elemToRemove != null)
{
Debug.WriteLine("Removing ChannelEndpointElement for : " + BINDING_NAME);
sectionGroup.Client.Endpoints.Remove(elemToRemove);
Debug.WriteLine("Removed ChannelEndpointElement for : " + BINDING_NAME);
}
// Remove <bindingExtension> for this adapter
if (sectionGroup.Extensions.BindingExtensions.ContainsKey(BINDING_NAME))
{
sectionGroup.Extensions.BindingExtensions.RemoveAt(BINDING_NAME);
}
// Remove <bindingElementExtension> for this adapter
if (sectionGroup.Extensions.BindingElementExtensions.ContainsKey(BINDINGELEM_NAME))
{
sectionGroup.Extensions.BindingElementExtensions.RemoveAt(BINDINGELEM_NAME);
}
config.Save();
}
else
{
throw new InstallException("Machine.Config doesn't contain system.serviceModel node");
}
}
/// <summary>
/// Use this for testing outside of the Setup project
/// </summary>
/// <param name="assemblyDirectory">Directory where the adapter assembly is located</param>
public static void TestAddConfiguration(string assemblyDirectory)
{
WCFLOBAdapterInstaller action = new WCFLOBAdapterInstaller();
InstallContext context = new InstallContext();
// In the Setup project, this is set by selecting custom action
// and in Properties setting /INSTALLDIR="[TARGETDIR]\" for CustomActionData
context.Parameters.Add("INSTALLDIR", assemblyDirectory);
action.Context = context;
action.AfterInstallEventHandler(null, null);
}
/// <summary>
/// Use this for testing outside of the Setup project
/// </summary>
/// <param name="assemblyDirectory">Directory where the adapter assembly is located</param>
public static void TestRemoveConfiguration(string assemblyDirectory)
{
WCFLOBAdapterInstaller action = new WCFLOBAdapterInstaller();
InstallContext context = new InstallContext();
// In the Setup project, this is set by selecting custom action
// and in Properties setting /INSTALLDIR="[TARGETDIR]\" for CustomActionData
context.Parameters.Add("INSTALLDIR", assemblyDirectory);
action.Context = context;
action.BeforeUninstallEventHandler(null, null);
}
}
}
如果您想要探索具有部署套件的範例配接器,您可以下載完整的 Echo 配接器,包括測試程式碼和安裝腳本。 此範例隨附于 或 \BizTalk Server\ASDK_x64\Program Files\WCF LOB Adapter SDK\Documents\Samples
的 \BizTalk Server\ASDK_x86\Program Files\WCF LOB Adapter SDK\Documents\Samples
BizTalk 安裝檔案中。