【问题标题】:How to use WixSharp to install a website and associate an AppPool如何使用 WixSharp 安装网站并关联 AppPool
【发布时间】:2010-03-16 10:25:50
【问题描述】:

我正在尝试查找如何使用WixSharp(WiX 的托管代码接口)安装网站并关联 AppPool 的示例。

我想要实现的步骤是:

  1. 如果网站存在于 IIS 6 中,请将其删除。
  2. 如果 IIS 6 中存在 AppPool,请将其删除。
  3. 从目标目录中删除应用程序工件。
  4. 将新的应用程序工件复制到目标目录。
  5. 创建应用程序池。
  6. 创建网站,将其链接到 AppPool。

我在 MSBuild 中实现了这一点,但这不如 MSI 有用。因此,我试图用 WixSharp 语法“重写”上述内容。

WixSharp 显然支持 WIXIISExtension,但 Google 尚未提供任何示例。

如何在 WixSharp 中编写上述代码?

【问题讨论】:

  • 您能说明为什么需要在 WixSharp 中执行此操作吗? Wix 开箱即用地支持这一点。 blogs.dovetailsoftware.com/blogs/kmiller/archive/2007/12/12/…
  • 我认为您正在尝试在这里重新发明轮子。 WixSharp 只是基于 Wix 的托管 UI,您仍应使用 Wix 来安装您的应用程序。在 Wix 中,所有这些任务都更容易完成。

标签: msbuild wix wixsharp


【解决方案1】:

我出于同样的目的使用 WIX。我要部署的应用程序大约 300 MB,我需要为相同的应用程序池等创建虚拟目录。

我认为你的要求是一样的。

我建议 WIX 非常适合这个。您可以有屏幕询问用户虚拟目录名称、应用程序池等。

WIX 代码适用于 IIS 5.1、6、7。对于 7.5,您需要创建自定义操作。因此,如果安装了 IIS 6 兼容模式,即使是 IIS 7.5,您也可以使用 wix 创建虚拟目录。

到目前为止,我在使用 WIX 部署 Web 应用程序时没有遇到任何错误。

【讨论】:

    【解决方案2】:

    好问题。

    我正在为我当前的项目使用 WixSharp,我对此非常满意。您可以通过使用 C# 语法来避免编写 XML 文件,这真是太棒了。顺便说一句,我不认为你是在重新发明轮子……你是在用 WixSharp 加速轮子。

    由于 WixSharp 1.9.6 版不提供创建具有关联 WebAppPool 的网站,因此我通过创建 CustomWebSite.cs 文件来实现。通过这种方式,我使用以下代码创建了我的 Web 应用程序:

    ...
    
    var project = new ManagedProject("My Project",
                           new InstallDir(@"c:\my_tool",
    
                                new Dir("my_frontend",
                                    new Files($"{frontendDir}\\app\\*.*"),
    
                                        new CustomWebSite("GateKeeper", "*:31515")
                                        {
                                            WebApplication = new CustomWebApplication("DemoApp")
                                            {
                                                WebAppPool = new WebAppPool("DemoApp", "ManagedPipelineMode=Integrated;Identity=applicationPoolIdentity"),
                                            },
                                            InstallWebSite = true
                                        }
                                    )
                                ),
    ...
    

    这是我仅用于创建一个网站的 CustomWebSite.cs 文件,我相信它会更好:

    using System;
    using System.Collections.Generic;
    using System.Xml.Linq;
    using WixSharp;
    using WixSharp.CommonTasks;
    using static WixSharp.WebSite;
    
    namespace ToolBox.WixSharp
    {
        /// <summary>
        /// Defines the WebSite element to be created associated to a Dir element.
        /// </summary>
        ///<example>The following is an example of associating a CustomWebSite to a Dir element.
        ///
        ///<code>
        /// var project =
        ///     new Project("My Product",
        ///         new Dir(@"%ProgramFiles%\My Company\My Product",
        ///             new Dir(@"some_dir",
        ///                 new CustomWebSite("MyApp", "*:81")
        ///                 {
        ///                     WebApplication = new CustomWebApplication("DemoApp")
        ///                     {
        ///                         WebAppPool = new WebAppPool("DemoApp", "ManagedPipelineMode=Integrated;Identity=applicationPoolIdentity")
        ///                     }
        ///                     InstallWebSite = true
        ///                 }
        ///         ...
        ///
        /// Compiler.BuildMsi(project);
        ///</code>
        /// 
        /// This code will generate something like this:
        ///<code>
        ///     <Component Id="DemoApp_WebSite" Guid="a6896bba-1818-43e0-824f-9c585b3e366b" KeyPath="yes" Win64="yes">
        ///         <iis:WebSite Id = "DemoApp_WebSite" Description="DemoApp_WebSite" Directory="INSTALLDIR.some_dir">
        ///             <iis:WebAddress Id = "WebSite_Address1" IP="*" Port="31515" />
        ///             <iis:WebApplication Id = "DemoApp_WebApplication" Name="DemoApp" WebAppPool="DemoApp_AppPool"/>
        ///         </iis:WebSite>
        ///         <iis:WebAppPool Id = "DemoApp_AppPool" Name="DemoApp" ManagedPipelineMode="Integrated" Identity="applicationPoolIdentity" />
        ///
        ///         <CreateFolder />
        ///         <RemoveFolder Id = "INSTALLDIR.some_dir" On="uninstall" />
        ///     </Component>
        /// </code>
        /// </example>
        public class CustomWebSite : WixEntity, IGenericEntity
        {
            /// <summary>
            /// Indicates if the WebSite is to be installed (created on IIS) or existing WebSite should be used to install the corresponding
            /// WebApplication. The default <see cref="InstallWebSite"/> value is <c>false</c>
            /// <para>Developers should be aware of the WebSite installation model imposed by WiX/MSI and use <see cref="InstallWebSite"/> carefully.</para>
            /// <para>If <see cref="InstallWebSite"/> value is set to <c>false</c> the parent WebApplication (<see cref="T:WixSharp.IISVirtualDir"/>)
            /// will be installed in the brand new (freshly created) WebSite or in the existing one if a site with the same address/port combination already exists
            /// on IIS). The undesirable side affect of this deployment scenario is that if the existing WebSite was used to install the WebApplication it will be
            /// deleted on IIS during uninstallation even if this WebSite has other WebApplications installed.</para>
            /// <para>The "safer" option is to set <see cref="InstallWebSite"/> value to <c>true</c> (default value). In this case the WebApplication will
            /// be installed in an existing WebSite with matching address/port. If the match is not found the installation will fail. During the uninstallation
            /// only installed WebApplication will be removed from IIS.</para>
            /// </summary>
            public bool InstallWebSite = false;
    
            /// <summary>
            /// Initializes a new instance of the <see cref="WebSite" /> class.
            /// </summary>
            public CustomWebSite()
            {
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="CustomWebSite"/> class.
            /// </summary>
            /// <param name="description">The description of the web site (as it shows up in the IIS manager console).</param>
            /// <param name="addressDefinition">The address definition.</param>
            public CustomWebSite(string description, string addressDefinition)
            {
                this.Id = $"{description}_WebSite";
                this.Description = description;
                this.AddressesDefinition = addressDefinition;
            }
    
            /// <summary>
            /// Initializes a new instance of the <see cref="CustomWebSite"/> class.
            /// </summary>
            /// <param name="id">The id</param>
            /// <param name="description">The description of the web site (as it shows up in the IIS manager console).</param>
            /// <param name="addressDefinition">The address definition.</param>
            public CustomWebSite(Id id, string description, string addressDefinition)
            {
                this.Id = id;
                this.Description = description;
                this.AddressesDefinition = addressDefinition;
            }
    
            internal void ProcessAddressesDefinition()
            {
                if (!AddressesDefinition.IsEmpty())
                {
                    List<WebAddress> addressesToAdd = new List<WebAddress>();
    
                    foreach (string addressDef in AddressesDefinition.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
                    {
                        try
                        {
                            string[] tokens = addressDef.Split(":".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                            string address = tokens[0];
                            string port = tokens[1];
                            if (tokens[1].ContainsWixConstants())
                            {
                                addressesToAdd.Add(new WebAddress { Address = address, AttributesDefinition = "Port=" + port });
                            }
                            else
                            {
                                addressesToAdd.Add(new WebAddress { Address = address, Port = Convert.ToInt32(port) });
                            }
                        }
                        catch (Exception e)
                        {
                            throw new Exception("Invalid AddressesDefinition", e);
                        }
                    }
    
                    this.addresses = addressesToAdd.ToArray();
                }
    
            }
    
            /// <summary>
            /// References a WebAppPool instance to use as the application pool for this application in IIS 6 applications.
            /// </summary>
            public string WebAppPool; //WebApplication element attribute
    
            /// <summary>
            /// Specification for auto-generating the <see cref="T:WebSite.WebAddresses"/> collection.
            /// <para>If <see cref="AddressesDefinition"/> is specified, the existing content of <see cref="Addresses"/> will be ignored
            /// and replaced with the auto-generated one at compile time.</para>
            /// </summary>
            /// <example>
            /// <c>webSite.AddressesDefinition = "*:80;*90";</c> will be parsed and converted to an array of <see cref="T:WixSharp.WebSite.WebAddress"/> as follows:
            /// <code>
            /// ...
            /// webSite.Addresses = new []
            ///     {
            ///         new WebSite.WebAddress
            ///         {
            ///             Address = "*",
            ///             Port = 80
            ///         },
            ///         new WebSite.WebAddress
            ///         {
            ///             Address = "*",
            ///             Port = 80
            ///         }
            ///     }
            /// </code>
            /// </example>
            public string AddressesDefinition = "";
    
            //// The iis:WebSite/@Directory attribute must be specified when the element has a Component as an ancestor..
            //public string Directory = "";
    
    
            /// <summary>
            /// Reference to a WebApplication that is to be installed as part of this web site.
            /// </summary>
            public CustomWebApplication WebApplication = null;
    
            /// <summary>
            /// Collection of <see cref="T:WebSite.WebAddresses"/> associated with website.
            /// <para>
            /// The user specified values of <see cref="Addresses"/> will be ignored and replaced with the
            /// auto-generated addresses if <see cref="AddressesDefinition"/> is specified either directly or via appropriate <see cref="WebSite"/> constructor.
            /// </para>
            /// </summary>
            public WebAddress[] Addresses
            {
                get
                {
                    ProcessAddressesDefinition();
                    return addresses;
                }
                set
                {
                    addresses = value;
                }
            }
    
            /// <summary>
            /// This class defines WebAppPool WiX element. It is used to specify the application pool for this application in IIS 6 applications.
            /// </summary>
            public partial class CustomWebApplication : WixEntity
            {
                /// <summary>
                /// References a WebAppPool instance to use as the application pool for this application in IIS 6 applications.
                /// </summary>
                public WebAppPool WebAppPool; //WebApplication element attribute
    
                /// <summary>
                /// Initializes a new instance of the <see cref="WebApplication"/> class.
                /// </summary>
                /// <param name="name">The name.</param>
                /// <param name="attributesDefinition">The attributes definition. This parameter is used to set encapsulated <see cref="T:WixSharp.WixEntity.AttributesDefinition"/>.</param>
                public CustomWebApplication(string name, string attributesDefinition)
                {
                    base.Id = $"{name}_WebApplication";
                    base.Name = name;
                    base.AttributesDefinition = attributesDefinition;
                }
    
                /// <summary>
                /// Initializes a new instance of the <see cref="WebAppPool"/> class.
                /// </summary>
                /// <param name="name">The name.</param>
                public CustomWebApplication(string name)
                {
                    base.Id = $"{name}_WebApplication";
                    base.Name = name;
                }
    
                /// <summary>
                /// Initializes a new instance of the <see cref="WebAppPool"/> class.
                /// </summary>
                public CustomWebApplication()
                {
                }
            }
    
            WebAddress[] addresses = new WebAddress[0];
    
            /// <summary>
            /// Primary key used to identify this particular entry.
            /// </summary>
            [Xml]
            public new string Id
            {
                get
                {
                    return base.Id;
                }
                set
                {
                    base.Id = value;
                }
            }
    
            /// <summary>
            /// The value to set into the environment variable. If this attribute is not set, the environment variable is removed
            /// during installation if it exists on the machine.
            /// </summary>
            [Xml]
            public string Description;
    
            /// <summary>
            /// Defines the installation <see cref="Condition"/>, which is to be checked during the installation to
            /// determine if the registry value should be created on the target system.
            /// </summary>
            public Condition Condition;
    
            /// <summary>
            /// Adds itself as an XML content into the WiX source being generated from the <see cref="WixSharp.Project"/>.
            /// See 'Wix#/samples/Extensions' sample for the details on how to implement this interface correctly.
            /// </summary>
            /// <param name="context">The context.</param>
            public void Process(ProcessingContext context)
            {
                // IIS namespace
                XNamespace ns = WixExtension.IIs.ToXNamespace();
    
                XElement component = this.CreateAndInsertParentComponent(context);
                component.Add(this.ToXElement(ns + "WebSite"));
    
                XElement webSiteElement = component.FindAll("WebSite")[0];
    
                if (webSiteElement.Parent.Name == "Component" && webSiteElement.Parent.Parent.Name == "Directory")
                {
                    // Add attributes for WebSite element
                    webSiteElement.AddAttributes($"Directory={webSiteElement.Parent.Parent.Attribute("Id").Value}");
                }
    
                if (Addresses != null)
                {
                    int index = 1;
    
                    // Generates the XML fragment for WebAddress element
                    foreach (WebAddress address in Addresses)
                    {
                        webSiteElement.AddElement(new XElement(ns + "WebAddress",
                                                new XAttribute("Id", $"WebSite_Address{index}"),
                                                new XAttribute("IP", "*"),
                                                new XAttribute("Port", address.Port)));
                        index++;
                    }
                }
    
                if (WebApplication != null)
                {
                    // Generates the XML fragment for WebApplication element
                    XElement webApplicationElement = new XElement(ns + "WebApplication",
                                            new XAttribute("Id", WebApplication.Id),
                                            new XAttribute("Name", this.WebApplication.Name));
    
                    webSiteElement.AddElement(webApplicationElement);
    
                    if (WebApplication.WebAppPool != null)
                    {
                        WebApplication.WebAppPool.Id = $"{WebApplication.WebAppPool.Name}_WebAppPool";
                        webApplicationElement.SetAttribute($"WebAppPool={WebApplication.WebAppPool.Id}");
    
                        // Generates the XML fragment for WebAppPool element
                        webSiteElement.Parent.AddElement(new XElement(ns + "WebAppPool",
                                                new XAttribute("Id", WebApplication.WebAppPool.Id),
                                                new XAttribute("Name", WebApplication.WebAppPool.Name),
                                                new XAttribute("ManagedPipelineMode", "Integrated"),
                                                new XAttribute("Identity", "applicationPoolIdentity")));
                    }
                }
    
                if (Condition != null)
                {
                    component.AddElement(new XElement("Condition", Condition.ToXValue())
                             .AddAttributes(Condition.Attributes));
                }
            }
        }
    }
    

    您还可以通过其他方法来解决您的问题,通过在WebSite definitions 之后生成 WIX xml 文件并使用WixSharp IIS Sample with XMLInjection 中指示的 XML 注入,您可以在其中订阅 WixSourceGenerated 事件。

    project.WixSourceGenerated += Compiler_WixSourceGenerated;
    

    请记住,WixSharp 会生成 Wix XML 定义文件,您可以在 WixSourceGenerated 事件之后修改此 XML 文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-01
      • 1970-01-01
      相关资源
      最近更新 更多