File: AppDomainIsolatedTask.cs
Web Access
Project: ..\..\..\src\Utilities\Microsoft.Build.Utilities.csproj (Microsoft.Build.Utilities.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Resources;
using System.Security;
 
using Microsoft.Build.Framework;
 
#nullable disable
 
namespace Microsoft.Build.Utilities
{
    /// <summary>
    /// This class provides the same functionality as the Task class, but derives from MarshalByRefObject so that it can be
    /// instantiated in its own app domain.
    /// </summary>
    [LoadInSeparateAppDomain]
#if !FEATURE_APPDOMAIN
    [Obsolete("AppDomains are no longer supported in .NET Core or .NET 5.0 or higher.")]
#endif
    public abstract class AppDomainIsolatedTask : MarshalByRefObject, ITask
    {
        #region Constructors
 
        /// <summary>
        /// Default (family) constructor.
        /// </summary>
        protected AppDomainIsolatedTask()
        {
            Log = new TaskLoggingHelper(this);
        }
 
        /// <summary>
        /// This (family) constructor allows derived task classes to register their resources.
        /// </summary>
        /// <param name="taskResources">The task resources.</param>
        protected AppDomainIsolatedTask(ResourceManager taskResources)
            : this()
        {
            Log.TaskResources = taskResources;
        }
 
        /// <summary>
        /// This (family) constructor allows derived task classes to register their resources, as well as provide a prefix for
        /// composing help keywords from string resource names. If the prefix is an empty string, then string resource names will
        /// be used verbatim as help keywords. For an example of how the prefix is used, see the
        /// <see cref="TaskLoggingHelper.LogErrorWithCodeFromResources(string, object[])"/> method.
        /// </summary>
        /// <param name="taskResources">The task resources.</param>
        /// <param name="helpKeywordPrefix">The help keyword prefix.</param>
        protected AppDomainIsolatedTask(ResourceManager taskResources, string helpKeywordPrefix)
            : this(taskResources)
        {
            Log.HelpKeywordPrefix = helpKeywordPrefix;
        }
 
        #endregion
 
        #region Properties
 
        /// <summary>
        /// The build engine automatically sets this property to allow tasks to call back into it.
        /// </summary>
        /// <value>The build engine interface available to tasks.</value>
        public IBuildEngine BuildEngine { get; set; }
 
        /// <summary>
        /// The build engine sets this property if the host IDE has associated a host object with this particular task.
        /// </summary>
        /// <value>The host object instance (can be null).</value>
        public ITaskHost HostObject { get; set; }
 
        /// <summary>
        /// Gets an instance of a TaskLoggingHelper class containing task logging methods.
        /// </summary>
        /// <value>The logging helper object.</value>
        public TaskLoggingHelper Log { get; }
 
        /// <summary>
        /// Gets or sets the task's culture-specific resources. Derived classes should register their resources either during
        /// construction, or via this property, if they have localized strings.
        /// </summary>
        /// <value>The task's resources (can be null).</value>
        protected ResourceManager TaskResources
        {
            get => Log.TaskResources;
            set => Log.TaskResources = value;
        }
 
        /// <summary>
        /// Gets or sets the prefix used to compose help keywords from string resource names. If a task does not have help
        /// keywords associated with its messages, it can ignore this property or set it to null. If the prefix is set to an empty
        /// string, then string resource names will be used verbatim as help keywords. For an example of how this prefix is used,
        /// see the <see cref="TaskLoggingHelper.LogErrorWithCodeFromResources(string, object[])"/> method.
        /// </summary>
        /// <value>The help keyword prefix string (can be null).</value>
        protected string HelpKeywordPrefix
        {
            get => Log.HelpKeywordPrefix;
            set => Log.HelpKeywordPrefix = value;
        }
 
        #endregion
 
        #region Methods
 
        /// <summary>
        /// Must be implemented by derived class.
        /// </summary>
        /// <returns>true, if successful</returns>
        public abstract bool Execute();
 
        /// <summary>
        /// Overridden to give tasks deriving from this class infinite lease time. Otherwise we end up with a limited
        /// lease (5 minutes I think) and task instances can expire if they take long time processing.
        /// </summary>
        [SecurityCritical]
#pragma warning disable CS0809 // InitializeLifetimeService is not marked as obsolete in netstandard2.0
#if !FEATURE_APPDOMAIN
        // This Obsolete is redundant since the whole class is obsoleted, but required to guard the reference
        // to the obsolete MarshalByRefObject.InitializeLifetimeService.
        [Obsolete("AppDomains are no longer supported in .NET Core or .NET 5.0 or higher.")]
#endif
        public override object InitializeLifetimeService() => null; // null means infinite lease time
#pragma warning restore
 
        #endregion
    }
}