Как использовать WixSharp для установки веб-сайта и связывания AppPool - PullRequest
2 голосов
/ 16 марта 2010

Я пытаюсь найти примеры использования WixSharp (интерфейс управляемого кода для WiX) для установки веб-сайта и связывания AppPool.

Шаги, которые я хочу достичь:

  1. Если веб-сайт существует в IIS 6, удалите его.
  2. Если AppPool существует в IIS 6, удалите его.
  3. Удалить артефакты приложения из каталога назначения.
  4. Скопируйте новые артефакты приложения в каталог назначения.
  5. Создайте AppPool.
  6. Создайте сайт, связав его с AppPool.

Я добился этого в MSBuild, но это не так полезно, как MSI. Поэтому я пытаюсь «переписать» вышеприведенное в синтаксисе WixSharp.

WixSharp, очевидно, поддерживает WIXIISExtension, но Google пока не дал никаких примеров.

Как бы я кодировал вышеупомянутое в WixSharp?

Ответы [ 2 ]

1 голос
/ 13 января 2011

Я использую WIX для той же цели. Приложение, которое я пытаюсь развернуть, составляет около 300 МБ, и мне нужно создать виртуальный каталог для того же приложения, пула приложений и т. Д.

Я думаю, что ваше требование такое же.

Я бы предположил, что WIX действительно хорош для этого. У вас могут быть экраны с запросом имени виртуального каталога пользователя, пула приложений и т. Д.

Код WIX отлично работает для IIS 5.1, 6, 7. Для версии 7.5 вам необходимо создать кастмацию. Таким образом, вы можете использовать wix для создания виртуального каталога даже для IIS 7.5, если установлен режим совместимости с IIS 6.

До сих пор я не сталкивался с ошибками при использовании WIX для развертывания веб-приложений.

0 голосов
/ 13 апреля 2019

Хороший вопрос.

Я использую WixSharp для моего текущего проекта, и я действительно доволен им. Удивительно, как вы можете избежать написания XML-файлов, используя все с синтаксисом C #. Кстати, я не думаю, что вы заново изобретаете колесо ... вы ускоряете колесо с помощью WixSharp.

Поскольку WixSharp версии 1.9.6 не предусматривает создание веб-сайта со связанным WebAppPool, я сделал это, создав файл CustomWebSite.cs. Таким образом, я создал свое веб-приложение, используя этот код:

...

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));
            }
        }
    }
}

У вас также есть другой способ решения вашей проблемы: сгенерируйте файл WIX xml, следуя Определения веб-сайта , и используйте XML-инъекцию, как указано в Пример WixSharp IIS с XMLInjection , где вы можете подписаться на событие WixSourceGenerated.

project.WixSourceGenerated += Compiler_WixSourceGenerated;

Помните, что WixSharp генерирует файл определения Wix XML, и вы можете изменить этот файл XML после события WixSourceGenerated.

...