File: AspNetCompiler.cs
Web Access
Project: ..\..\..\src\Tasks\Microsoft.Build.Tasks.csproj (Microsoft.Build.Tasks.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#if NETFRAMEWORK
using Microsoft.Build.Utilities;
#endif
 
#nullable disable
 
namespace Microsoft.Build.Tasks
{
#if NETFRAMEWORK

    /// <summary>
    /// The AspNetCompiler task, which is a wrapper around aspnet_compiler.exe
    /// </summary>
    public class AspNetCompiler : ToolTaskExtension, IAspNetCompilerTaskContract
    {
        /*
            C:\WINDOWS\Microsoft.NET\Framework\v2.0.x86dbg>aspnet_compiler /?
            Utility to precompile an ASP.NET application
            Copyright (C) Microsoft Corporation. All rights reserved.
 
            Usage:
            aspnet_compiler [-?] [-m metabasePath | -v virtualPath [-p physicalDir]]
                            [[-u] [-f] [-d] targetDir] [-c] [-fixednames]
                            [-keyfile file | -keycontainer container [-aptca] [-delaySign]]
 
            -?            Prints this help text.
            -m            The full IIS metabase path of the application. This switch
                          cannot be combined with the -v or -p switches.
            -v            The virtual path of the application to be compiled (e.g.
                          "/MyApp"). If -p is specified, the physical path is used to
                          locate the application. Otherwise, the IIS metabase is used, and
                          the application is assumed to be in the default site (under
                          "/LM/W3SVC/1/Root"). This switch cannot be combined with the -m
                          switch.
            -p            The physical path of the application to be compiled. If -p is
                          missing, the IIS metabase is used to locate the app. This switch
                          must be combined with -v.
            -u            If specified, the precompiled application is updatable.
            -f            Overwrites the target directory if it already exists. Existing
                          contents are lost.
            -d            If specified, the debug information is emitted during
                          compilation.
            targetDir     The physical path to which the application is compiled. If not
                          specified, the application is precompiled in-place.
            -c            If specified, the precompiled application is fully rebuilt. Any
                          previously compiled components will be re-compiled. This option
                          is always enabled when targetDir is specified.
            -keyfile      The physical path to the strong name key file.
            -keycontainer Specifies a strong name key container.
            -aptca        If specified, the strong-name assembly will allow partially
                          trusted callers.
            -delaysign    If specified, the assemblly is not fully signed when created.
            -fixednames   If specified, the compiled assemblies will be given fixed names.
            -nologo       Suppress compiler copyright message.
 
            Examples:
 
            The following two commands are equivalent, and rely on the IIS metabase. The
            compiled application is deployed to c:\MyTarget:
                aspnet_compiler -m /LM/W3SVC/1/Root/MyApp c:\MyTarget
                aspnet_compiler -v /MyApp c:\MyTarget
 
            The following command compiles the application /MyApp in-place. The effect is
            that no more compilations will be needed when HTTP requests are sent to it:
                aspnet_compiler -v /MyApp
 
            The following command does *not* rely on the IIS metabase, as it explicitly
            specifies the physical source directory of the application:
                aspnet_compiler -v /MyApp -p c:\myapp c:\MyTarget
        */
 
        /// <summary>
        /// If specified, the strong-name assembly will allow partially
        /// trusted callers.
        /// </summary>
        public bool AllowPartiallyTrustedCallers { get; set; }
 
        /// <summary>
        /// If specified, the assemblly is not fully signed when created.
        /// </summary>
        public bool DelaySign { get; set; }
 
        /// <summary>
        /// If specified, the compiled assemblies will be given fixed names.
        /// </summary>
        public bool FixedNames { get; set; }
 
        /// <summary>
        /// Specifies a strong name key container.
        /// </summary>
        public string KeyContainer
        {
            get => (string)Bag[nameof(KeyContainer)];
            set => Bag[nameof(KeyContainer)] = value;
        }
 
        /// <summary>
        /// The physical path to the strong name key file.
        /// </summary>
        public string KeyFile
        {
            get => (string)Bag[nameof(KeyFile)];
            set => Bag[nameof(KeyFile)] = value;
        }
 
        /// <summary>
        /// The full IIS metabase path of the application. This switch
        /// cannot be combined with the virtualPath or PhysicalDir option.
        /// </summary>
        public string MetabasePath
        {
            get => (string)Bag[nameof(MetabasePath)];
            set => Bag[nameof(MetabasePath)] = value;
        }
 
        /// <summary>
        /// The physical path of the application to be compiled. If physicalDir
        /// is missing, the IIS metabase is used to locate the application.
        /// </summary>
        public string PhysicalPath
        {
            get => (string)Bag[nameof(PhysicalPath)];
            set => Bag[nameof(PhysicalPath)] = value;
        }
 
        /// <summary>
        /// The physical path to which the application is compiled. If not
        /// specified, the application is precompiled in-place.
        /// </summary>
        public string TargetPath
        {
            get => (string)Bag[nameof(TargetPath)];
            set => Bag[nameof(TargetPath)] = value;
        }
 
        /// <summary>
        /// The virtual path of the application to be compiled. If PhysicalDir is
        /// used to locate the application is specified. Otherwise, the IIS metabase
        /// is used, and the application is assumed to be in the default site (under
        /// "/LM/W3SVC/1/Root").
        /// </summary>
        public string VirtualPath
        {
            get => (string)Bag[nameof(VirtualPath)];
            set => Bag[nameof(VirtualPath)] = value;
        }
 
        /// <summary>
        /// If Updateable is true, then the web is compile with -u flag so that it
        /// can be updated after compilation
        /// </summary>
        public bool Updateable { get; set; }
 
        /// <summary>
        /// If Force is true, then the web is compile with -f flag overwriting
        /// files in the target location
        /// </summary>
        public bool Force { get; set; }
 
        /// <summary>
        /// If Debug is true, then the debug information will be emitted during
        /// compilation.
        /// </summary>
        public bool Debug { get; set; }
 
        /// <summary>
        /// If Clean is true, then the application will be built clean. Previously
        /// compiled components will be re-compiled.
        /// </summary>
        public bool Clean { get; set; }
 
        /// <summary>
        /// The TargetFrameworkMoniker indicating which .NET Framework version of
        /// aspnet_compiler.exe should be used.  Only accepts .NET Framework monikers.
        /// </summary>
        public string TargetFrameworkMoniker
        {
            get => (string)Bag[nameof(TargetFrameworkMoniker)];
            set => Bag[nameof(TargetFrameworkMoniker)] = value;
        }
 
        /// <summary>
        /// The name of the tool to execute
        /// </summary>
        protected override string ToolName => "aspnet_compiler.exe";
 
        /// <summary>
        /// Small helper property to get the "project name"
        /// </summary>
        private string ProjectName
        {
            get
            {
                if (PhysicalPath != null)
                {
                    return PhysicalPath;
                }
                return VirtualPath ?? MetabasePath;
            }
        }
 
        /// <summary>
        /// Small helper property for determining the "name of the target" that's currently being built
        /// </summary>
        private string TargetName
        {
            get
            {
                if (Clean)
                {
                    return "Clean";
                }
 
                // building the default target
                return null;
            }
        }
 
        /// <summary>
        /// Override the Execute method to be able to send ExternalProjectStarted/Finished events.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            Log.LogExternalProjectStarted(string.Empty, null, ProjectName, TargetName);
            bool succeeded = false;
 
            try
            {
                succeeded = base.Execute();
            }
            finally
            {
                Log.LogExternalProjectFinished(string.Empty, null, ProjectName, succeeded);
            }
 
            return succeeded;
        }
 
        /// <summary>
        /// Generates command line arguments for aspnet_compiler.exe
        /// </summary>
        /// <param name="commandLine">command line builder class to add arguments to</param>
        protected internal override void AddCommandLineCommands(CommandLineBuilderExtension commandLine)
        {
            commandLine.AppendSwitchIfNotNull("-m ", MetabasePath);
            commandLine.AppendSwitchIfNotNull("-v ", VirtualPath);
            commandLine.AppendSwitchIfNotNull("-p ", PhysicalPath);
 
            if (Updateable)
            {
                commandLine.AppendSwitch("-u");
            }
 
            if (Force)
            {
                commandLine.AppendSwitch("-f");
            }
 
            if (Clean)
            {
                commandLine.AppendSwitch("-c");
            }
 
            if (Debug)
            {
                commandLine.AppendSwitch("-d");
            }
 
            if (FixedNames)
            {
                commandLine.AppendSwitch("-fixednames");
            }
 
            commandLine.AppendSwitchIfNotNull("", TargetPath);
 
            if (AllowPartiallyTrustedCallers)
            {
                commandLine.AppendSwitch("-aptca");
            }
 
            if (DelaySign)
            {
                commandLine.AppendSwitch("-delaysign");
            }
 
            commandLine.AppendSwitchIfNotNull("-keyfile ", KeyFile);
            commandLine.AppendSwitchIfNotNull("-keycontainer ", KeyContainer);
        }
 
        /// <summary>
        /// Determine the path to aspnet_compiler.exe
        /// </summary>
        /// <returns>path to aspnet_compiler.exe, null if not found</returns>
        protected override string GenerateFullPathToTool()
        {
            // If ToolPath wasn't passed in, we want to default to the latest
            string pathToTool = ToolLocationHelper.GetPathToDotNetFrameworkFile(ToolExe, TargetDotNetFrameworkVersion.Latest);
 
            if (pathToTool == null)
            {
                Log.LogErrorWithCodeFromResources("General.FrameworksFileNotFound", ToolExe,
                    ToolLocationHelper.GetDotNetFrameworkVersionFolderPrefix(TargetDotNetFrameworkVersion.Latest));
            }
 
            return pathToTool;
        }
 
        /// <summary>
        /// Validate the task arguments, log any warnings/errors
        /// </summary>
        /// <returns>true if arguments are corrent enough to continue processing, false otherwise</returns>
        protected override bool ValidateParameters()
        {
            if (MetabasePath != null && (VirtualPath != null || PhysicalPath != null))
            {
                Log.LogErrorWithCodeFromResources("AspNetCompiler.CannotCombineMetabaseAndVirtualPathOrPhysicalPath");
                return false;
            }
 
            if (MetabasePath == null && VirtualPath == null)
            {
                Log.LogErrorWithCodeFromResources("AspNetCompiler.MissingMetabasePathAndVirtualPath");
                return false;
            }
 
            if (Updateable && TargetPath == null)
            {
                Log.LogErrorWithCodeFromResources("AspNetCompiler.MissingTargetPathForUpdatableApplication");
                return false;
            }
 
            if (Force && TargetPath == null)
            {
                Log.LogErrorWithCodeFromResources("AspNetCompiler.MissingTargetPathForOverwrittenApplication");
                return false;
            }
 
            return true;
        }
    }
 
#else
 
    public sealed class AspNetCompiler : TaskRequiresFramework, IAspNetCompilerTaskContract
    {
        public AspNetCompiler()
            : base(nameof(AspNetCompiler))
        {
        }
 
        #region Properties
 
        public bool AllowPartiallyTrustedCallers { get; set; }
 
        public bool DelaySign { get; set; }
 
        public bool FixedNames { get; set; }
 
        public string KeyContainer { get; set; }
 
        public string KeyFile { get; set; }
 
        public string MetabasePath { get; set; }
 
        public string PhysicalPath { get; set; }
 
        public string TargetPath { get; set; }
 
        public string VirtualPath { get; set; }
 
        public bool Updateable { get; set; }
 
        public bool Force { get; set; }
 
        public bool Debug { get; set; }
 
        public bool Clean { get; set; }
 
        public string TargetFrameworkMoniker { get; set; }
 
        #endregion
    }
 
#endif
 
    internal interface IAspNetCompilerTaskContract
    {
        #region Properties
 
        bool AllowPartiallyTrustedCallers { get; set; }
        bool DelaySign { get; set; }
        bool FixedNames { get; set; }
        string KeyContainer { get; set; }
        string KeyFile { get; set; }
        string MetabasePath { get; set; }
        string PhysicalPath { get; set; }
        string TargetPath { get; set; }
        string VirtualPath { get; set; }
        bool Updateable { get; set; }
        bool Force { get; set; }
        bool Debug { get; set; }
        bool Clean { get; set; }
        string TargetFrameworkMoniker { get; set; }
 
        #endregion
    }
}