File: CreateAppHost.cs
Web Access
Project: ..\..\..\src\Tasks\Microsoft.NET.Build.Tasks\Microsoft.NET.Build.Tasks.csproj (Microsoft.NET.Build.Tasks)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
using Microsoft.Build.Framework;
using Microsoft.NET.HostModel;
using Microsoft.NET.HostModel.AppHost;
 
namespace Microsoft.NET.Build.Tasks
{
    /// <summary>
    /// Creates the runtime host to be used for an application.
    /// This embeds the application DLL path into the apphost and performs additional customizations as requested.
    /// </summary>
    public class CreateAppHost : TaskBase
    {
        /// <summary>
        /// The number of additional retries to attempt for creating the apphost.
        /// <summary>
        /// <remarks>
        /// The default is no retries because internally the `HostWriter` attempts to retry
        /// on different I/O operations. Users can optionally retry at the task level if desired.
        /// </remarks>
        public const int DefaultRetries = 0;
 
        /// The default delay, in milliseconds, for each retry attempt for creating the apphost.
        /// </summary>
        public const int DefaultRetryDelayMilliseconds = 1000;
 
        [Required]
        public string AppHostSourcePath { get; set; }
 
        [Required]
        public string AppHostDestinationPath { get; set; }
 
        [Required]
        public string AppBinaryName { get; set; }
 
        [Required]
        public string IntermediateAssembly { get; set; }
 
        public bool WindowsGraphicalUserInterface { get; set; }
 
        public int Retries { get; set; } = DefaultRetries;
 
        public int RetryDelayMilliseconds { get; set; } = DefaultRetryDelayMilliseconds;
 
        public bool EnableMacOSCodeSign { get; set; } = false;
 
        public bool DisableCetCompat { get; set; } = false;
 
        public ITaskItem[] DotNetSearchLocations { get; set; }
 
        public string AppRelativeDotNet { get; set; } = null;
 
        protected override void ExecuteCore()
        {
            try
            {
                var isGUI = WindowsGraphicalUserInterface;
                var resourcesAssembly = IntermediateAssembly;
 
                int attempts = 0;
 
                while (true)
                {
                    try
                    {
                        HostWriter.DotNetSearchOptions options = null;
                        if (DotNetSearchLocations?.Length > 0)
                        {
                            HostWriter.DotNetSearchOptions.SearchLocation searchLocation = default;
                            foreach (var locationItem in DotNetSearchLocations)
                            {
                                if (Enum.TryParse(locationItem.ItemSpec, out HostWriter.DotNetSearchOptions.SearchLocation location)
                                    && Enum.IsDefined(typeof(HostWriter.DotNetSearchOptions.SearchLocation), location))
                                {
                                    searchLocation |= location;
                                }
                                else
                                {
                                    throw new BuildErrorException(Strings.InvalidAppHostDotNetSearch, locationItem.ItemSpec);
                                }
                            }
 
                            options = new HostWriter.DotNetSearchOptions()
                            {
                                Location = searchLocation,
                                AppRelativeDotNet = AppRelativeDotNet
                            };
                        }
 
                        HostWriter.CreateAppHost(appHostSourceFilePath: AppHostSourcePath,
                                                appHostDestinationFilePath: AppHostDestinationPath,
                                                appBinaryFilePath: AppBinaryName,
                                                windowsGraphicalUserInterface: isGUI,
                                                assemblyToCopyResourcesFrom: resourcesAssembly,
                                                enableMacOSCodeSign: EnableMacOSCodeSign,
                                                disableCetCompat: DisableCetCompat,
                                                dotNetSearchOptions: options);
                        return;
                    }
                    catch (Exception ex) when (ex is IOException ||
                                               ex is UnauthorizedAccessException ||
                                               (ex is AggregateException && (ex.InnerException is IOException || ex.InnerException is UnauthorizedAccessException)))
                    {
                        if (Retries < 0 || attempts == Retries)
                        {
                            throw;
                        }
 
                        ++attempts;
 
                        string message = ex.Message;
                        if (ex is AggregateException)
                        {
                            message = ex.InnerException.Message;
                        }
 
                        Log.LogWarning(
                            string.Format(Strings.AppHostCreationFailedWithRetry,
                                attempts,
                                Retries + 1,
                                message));
 
                        if (RetryDelayMilliseconds > 0)
                        {
                            Thread.Sleep(RetryDelayMilliseconds);
                        }
                    }
                }
            }
            catch (AppNameTooLongException ex)
            {
                throw new BuildErrorException(Strings.FileNameIsTooLong, ex.LongName);
            }
            catch (AppHostSigningException ex)
            {
                throw new BuildErrorException(Strings.AppHostSigningFailed, ex.Message, ex.ExitCode.ToString());
            }
            catch (PlaceHolderNotFoundInAppHostException ex)
            {
                throw new BuildErrorException(Strings.AppHostHasBeenModified, AppHostSourcePath, BitConverter.ToString(ex.MissingPattern));
            }
        }
    }
}