Exemplo n.º 1
0
        /// <summary>
        /// This method gets called by the runtime. It is used to add services
        /// to the container. It uses the Extension pattern.
        /// </summary>
        /// <todo>
        ///   CORE TODO Remove initializing contextAccessor : See if over time we can refactor away the need for this?
        ///   It's kind of a quick hack/compatibility shim. Ideally you want to get the request context only from where
        ///   it's specifically provided to you (Request.HttpContext in a controller, or as an Invoke() parameter in
        ///   a middleware) and pass it wherever its needed.
        /// </todo>
        public void ConfigureServices(IServiceCollection services)
        {
            Console.WriteLine(@"Configure Services : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));

            services.Configure <FormOptions>(options =>
            {
                options.MultipartBodyLengthLimit = 52428800;
                options.ValueCountLimit          = 500000;
                options.KeyLengthLimit           = 500000;
            });

            services.AddRouteAnalyzer();

            // Kudu.Services contains all the Controllers
            var kuduServicesAssembly = Assembly.Load("Kudu.Services");

            services.AddMvcCore()
            .AddRazorPages()
            .AddAuthorization()
            .AddJsonFormatters()
            .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver())
            .AddApplicationPart(kuduServicesAssembly).AddControllersAsServices()
            .AddApiExplorer();


            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new Info {
                    Title = "Kudu API Docs"
                });
                // Setting the comments path for the Swagger JSON and UI.
                var xmlFile = $"Kudu.Services.xml";
                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                c.IncludeXmlComments(xmlPath);
            });

            services.AddGZipCompression();

            services.AddDirectoryBrowser();

            services.AddDataProtection();

            services.AddLogging(
                builder =>
            {
                builder.AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddConsole();
            });

            services.AddSingleton <IHttpContextAccessor>(new HttpContextAccessor());

            KuduWebUtil.EnsureHomeEnvironmentVariable();

            KuduWebUtil.EnsureSiteBitnessEnvironmentVariable();

            IEnvironment environment = KuduWebUtil.GetEnvironment(_hostingEnvironment);

            _webAppRuntimeEnvironment = environment;

            KuduWebUtil.EnsureDotNetCoreEnvironmentVariable(environment);

            // CORE TODO Check this
            // fix up invalid /home/site/deployments/settings.xml
            KuduWebUtil.EnsureValidDeploymentXmlSettings(environment);

            // Add various folders that never change to the process path. All child processes will inherit this
            KuduWebUtil.PrependFoldersToPath(environment);

            // General
            services.AddSingleton <IServerConfiguration>(ServerConfiguration);

            // CORE TODO Looks like this doesn't ever actually do anything, can refactor out?
            services.AddSingleton <IBuildPropertyProvider>(new BuildPropertyProvider());

            _noContextDeploymentsSettingsManager =
                new DeploymentSettingsManager(new XmlSettings.Settings(KuduWebUtil.GetSettingsPath(environment)));
            TraceServices.TraceLevel = _noContextDeploymentsSettingsManager.GetTraceLevel();

            // Per request environment
            services.AddScoped(sp =>
                               KuduWebUtil.GetEnvironment(_hostingEnvironment, sp.GetRequiredService <IDeploymentSettingsManager>()));

            services.AddDeploymentServices(environment);

            /*
             * CORE TODO Refactor ITracerFactory/ITracer/GetTracer()/
             * ILogger needs serious refactoring:
             * - Names should be changed to make it clearer that ILogger is for deployment
             *   logging and ITracer and friends are for Kudu tracing
             * - ILogger is a first-class citizen in .NET core and has it's own meaning. We should be using it
             *   where appropriate (and not name-colliding with it)
             * - ITracer vs. ITraceFactory is redundant and confusing.
             * - TraceServices only serves to confuse stuff now that we're avoiding
             */
            Func <IServiceProvider, ITracer> resolveTracer = KuduWebUtil.GetTracer;

            ITracer CreateTracerThunk() => resolveTracer(services.BuildServiceProvider());

            // First try to use the current request profiler if any, otherwise create a new one
            var traceFactory = new TracerFactory(() =>
            {
                var sp      = services.BuildServiceProvider();
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? resolveTracer(sp));
            });

            services.AddScoped <ITracer>(sp =>
            {
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? NullTracer.Instance);
            });

            services.AddSingleton <ITraceFactory>(traceFactory);

            TraceServices.SetTraceFactory(CreateTracerThunk);

            services.AddSingleton <IDictionary <string, IOperationLock> >(
                KuduWebUtil.GetNamedLocks(traceFactory, environment));

            // CORE TODO ShutdownDetector, used by LogStreamManager.
            //var shutdownDetector = new ShutdownDetector();
            //shutdownDetector.Initialize()

            var noContextTraceFactory = new TracerFactory(() =>
                                                          KuduWebUtil.GetTracerWithoutContext(environment, _noContextDeploymentsSettingsManager));

            services.AddTransient <IAnalytics>(sp => new Analytics(sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                                   sp.GetRequiredService <IServerConfiguration>(),
                                                                   noContextTraceFactory));

            // CORE TODO
            // Trace shutdown event
            // Cannot use shutdownDetector.Token.Register because of race condition
            // with NinjectServices.Stop via WebActivator.ApplicationShutdownMethodAttribute
            // Shutdown += () => TraceShutdown(environment, noContextDeploymentsSettingsManager);

            // LogStream service
            services.AddLogStreamService(_webAppRuntimeEnvironment, traceFactory);

            // Deployment Service
            services.AddWebJobsDependencies();

            services.AddScoped <ILogger>(KuduWebUtil.GetDeploymentLogger);

            services.AddScoped <IDeploymentManager, DeploymentManager>();

            services.AddScoped <IFetchDeploymentManager, FetchDeploymentManager>();

            services.AddScoped <ISSHKeyManager, SSHKeyManager>();

            services.AddScoped <IRepositoryFactory>(
                sp => KuduWebUtil.GetDeploymentLock(traceFactory, environment).RepositoryFactory =
                    new RepositoryFactory(
                        sp.GetRequiredService <IEnvironment>(), sp.GetRequiredService <IDeploymentSettingsManager>(),
                        sp.GetRequiredService <ITraceFactory>()));

            services.AddScoped <IApplicationLogsReader, ApplicationLogsReader>();

            // Git server
            services.AddGitServer(KuduWebUtil.GetDeploymentLock(traceFactory, environment));

            // Git Servicehook Parsers
            services.AddGitServiceHookParsers();

            services.AddScoped <ICommandExecutor, CommandExecutor>();

            // KuduWebUtil.MigrateSite(environment, noContextDeploymentsSettingsManager);
            // RemoveOldTracePath(environment);
            // RemoveTempFileFromUserDrive(environment);

            // CORE TODO Windows Fix: Temporary fix for https://github.com/npm/npm/issues/5905
            //EnsureNpmGlobalDirectory();
            //EnsureUserProfileDirectory();

            //// Skip SSL Certificate Validate
            //if (Environment.SkipSslValidation)
            //{
            //    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            //}

            //// Make sure webpages:Enabled is true. Even though we set it in web.config, it could be overwritten by
            //// an Azure AppSetting that's supposed to be for the site only but incidently affects Kudu as well.
            ConfigurationManager.AppSettings["webpages:Enabled"] = "true";

            //// Kudu does not rely owin:appStartup.  This is to avoid Azure AppSetting if set.
            if (ConfigurationManager.AppSettings?["owin:appStartup"] != null)
            {
                // Set the appSetting to null since we cannot use AppSettings.Remove(key) (ReadOnly exception!)
                ConfigurationManager.AppSettings["owin:appStartup"] = null;
            }

            //RegisterRoutes(kernel, RouteTable.Routes);

            //// Register the default hubs route: ~/signalr
            //GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(kernel);
            //GlobalConfiguration.Configuration.Filters.Add(
            //    new TraceDeprecatedActionAttribute(
            //        kernel.Get<IAnalytics>(),
            //        kernel.Get<ITraceFactory>()));
            //GlobalConfiguration.Configuration.Filters.Add(new EnsureRequestIdHandlerAttribute());

            //FileTarget target = LogManager.Configuration.FindTargetByName("file") as FileTarget;
            //String logfile = _webAppRuntimeEnvironment.LogFilesPath + "/.txt";
            //target.FileName = logfile;
        }
Exemplo n.º 2
0
        /// <summary>
        /// This method gets called by the runtime. It is used to add services
        /// to the container. It uses the Extension pattern.
        /// </summary>
        /// <todo>
        ///   CORE TODO Remove initializing contextAccessor : This is new. See if over time we can refactor away the need for this?
        ///   It's kind of a quick hack/compatibility shim. Ideally you want to get the request context only from where
        ///   it's specifically provided to you (Request.HttpContext in a controller, or as an Invoke() parameter in
        ///   a middleware) and pass it wherever its needed.
        /// </todo>
        public void ConfigureServices(IServiceCollection services)
        {
            Console.WriteLine("\nConfigure Services : " + DateTime.Now.ToString("hh.mm.ss.ffffff"));

            services.Configure <FormOptions>(options =>
            {
                options.MultipartBodyLengthLimit = 52428800;
                options.ValueCountLimit          = 500000;
                options.KeyLengthLimit           = 500000;
            });


            services.AddMvcCore()
            .AddRazorPages()
            .AddAuthorization()
            .AddFormatterMappings()
            .AddJsonFormatters()
            .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());


            services.AddGZipCompression();

            services.AddDirectoryBrowser();

            services.AddDataProtection();

            var contextAccessor = new HttpContextAccessor();

            this._httpContextAccessor = contextAccessor;
            services.AddSingleton <IHttpContextAccessor>(contextAccessor);

            KuduWebUtil.EnsureHomeEnvironmentVariable();

            KuduWebUtil.EnsureSiteBitnessEnvironmentVariable();

            IEnvironment environment = KuduWebUtil.GetEnvironment(_hostingEnvironment);

            _webAppEnvironment = environment;

            KuduWebUtil.EnsureDotNetCoreEnvironmentVariable(environment);

            //CORE TODO Check this
            // fix up invalid /home/site/deployments/settings.xml
            KuduWebUtil.EnsureValidDeploymentXmlSettings(environment);

            // Add various folders that never change to the process path. All child processes will inherit this
            KuduWebUtil.PrependFoldersToPath(environment);

            // General
            services.AddSingleton <IServerConfiguration>(serverConfiguration);

            // CORE TODO Looks like this doesn't ever actually do anything, can refactor out?
            services.AddSingleton <IBuildPropertyProvider>(new BuildPropertyProvider());


            IDeploymentSettingsManager noContextDeploymentsSettingsManager =
                new DeploymentSettingsManager(new XmlSettings.Settings(KuduWebUtil.GetSettingsPath(environment)));

            TraceServices.TraceLevel = noContextDeploymentsSettingsManager.GetTraceLevel();

            // Per request environment
            services.AddScoped <IEnvironment>(sp => KuduWebUtil.GetEnvironment(_hostingEnvironment, sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                                               sp.GetRequiredService <IHttpContextAccessor>().HttpContext));

            services.AddDeployementServices(environment);


            /*
             * CORE TODO all this business around ITracerFactory/ITracer/GetTracer()/
             * ILogger needs serious refactoring:
             * - Names should be changed to make it clearer that ILogger is for deployment
             * logging and ITracer and friends are for Kudu tracing
             * - ILogger is a first-class citizen in .NET core and has it's own meaning. We should be using it
             *   where appropriate (and not name-colliding with it)
             * - ITracer vs. ITraceFactory is redundant and confusing.
             * - All this stuff with funcs and factories and TraceServices is overcomplicated.
             * TraceServices only serves to confuse stuff now that we're avoiding
             */
            Func <IServiceProvider, ITracer> resolveTracer = sp => KuduWebUtil.GetTracer(sp);

            ITracer CreateTracerThunk() => resolveTracer(services.BuildServiceProvider());

            // First try to use the current request profiler if any, otherwise create a new one
            var traceFactory = new TracerFactory(() => {
                var sp      = services.BuildServiceProvider();
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? resolveTracer(sp));
            });

            services.AddScoped <ITracer>(sp =>
            {
                var context = sp.GetRequiredService <IHttpContextAccessor>().HttpContext;
                return(TraceServices.GetRequestTracer(context) ?? NullTracer.Instance);
            });

            services.AddSingleton <ITraceFactory>(traceFactory);

            TraceServices.SetTraceFactory(CreateTracerThunk);

            services.AddSingleton <IDictionary <string, IOperationLock> >(KuduWebUtil.GetNamedLocks(traceFactory, environment));

            // CORE TODO ShutdownDetector, used by LogStreamManager.
            //var shutdownDetector = new ShutdownDetector();
            //shutdownDetector.Initialize()

            var noContextTraceFactory = new TracerFactory(() => KuduWebUtil.GetTracerWithoutContext(environment, noContextDeploymentsSettingsManager));
            var etwTraceFactory       = new TracerFactory(() => new ETWTracer(string.Empty, string.Empty));

            services.AddTransient <IAnalytics>(sp => new Analytics(sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                                   sp.GetRequiredService <IServerConfiguration>(),
                                                                   noContextTraceFactory));

            // CORE TODO Trace unhandled exceptions
            //AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
            //{
            //    var ex = args.ExceptionObject as Exception;
            //    if (ex != null)
            //    {
            //        kernel.Get<IAnalytics>().UnexpectedException(ex);
            //    }
            //};

            // CORE TODO
            // Trace shutdown event
            // Cannot use shutdownDetector.Token.Register because of race condition
            // with NinjectServices.Stop via WebActivator.ApplicationShutdownMethodAttribute
            //Shutdown += () => TraceShutdown(environment, noContextDeploymentsSettingsManager);

            // CORE TODO
            // LogStream service
            // The hooks and log stream start endpoint are low traffic end-points. Re-using it to avoid creating another lock
            var logStreamManagerLock = KuduWebUtil.GetNamedLocks(traceFactory, environment)["hooks"];

            //kernel.Bind<LogStreamManager>().ToMethod(context => new LogStreamManager(Path.Combine(environment.RootPath, Constants.LogFilesPath),
            //                                                                         context.Kernel.Get<IEnvironment>(),
            //                                                                         context.Kernel.Get<IDeploymentSettingsManager>(),
            //                                                                         context.Kernel.Get<ITracer>(),
            //                                                                         shutdownDetector,
            //                                                                         logStreamManagerLock));

            services.AddTransient(sp => new LogStreamManager(Path.Combine(environment.RootPath, Constants.LogFilesPath),
                                                             sp.GetRequiredService <IEnvironment>(),
                                                             sp.GetRequiredService <IDeploymentSettingsManager>(),
                                                             sp.GetRequiredService <ITracer>(),
                                                             logStreamManagerLock));

            // CORE TODO Need to implement this, and same comment as in InfoRefsController.cs (not sure why it needs the kernel/iserviceprovider as a
            // service locator, why does it need "delayed binding"?)
            //kernel.Bind<CustomGitRepositoryHandler>().ToMethod(context => new CustomGitRepositoryHandler(t => context.Kernel.Get(t)))
            //                                         .InRequestScope();

            // Deployment Service

            services.AddWebJobsDependencies();

            services.AddScoped <ILogger>(sp => KuduWebUtil.GetLogger(sp));

            services.AddScoped <IDeploymentManager, DeploymentManager>();
            services.AddScoped <IFetchDeploymentManager, FetchDeploymentManager>();
            services.AddScoped <ISSHKeyManager, SSHKeyManager>();

            services.AddScoped <IRepositoryFactory>(sp => KuduWebUtil.GetDeploymentLock(traceFactory, environment).RepositoryFactory = new RepositoryFactory(
                                                        sp.GetRequiredService <IEnvironment>(), sp.GetRequiredService <IDeploymentSettingsManager>(), sp.GetRequiredService <ITraceFactory>()));

            // CORE NOTE This was previously wired up in Ninject with .InSingletonScope. I'm not sure how that worked,
            // since it depends on an IEnvironment, which was set up with .PerRequestScope. I have made this per request.
            services.AddScoped <IApplicationLogsReader, ApplicationLogsReader>();

            // Git server
            services.AddGitServer(KuduWebUtil.GetDeploymentLock(traceFactory, environment));

            // Git Servicehook Parsers
            services.AddGitServiceHookParsers();

            // CORE TODO
            // SiteExtensions
            //kernel.Bind<ISiteExtensionManager>().To<SiteExtensionManager>().InRequestScope();

            // CORE TODO
            // Functions
            //kernel.Bind<IFunctionManager>().To<FunctionManager>().InRequestScope();

            services.AddScoped <ICommandExecutor, CommandExecutor>();

            // CORE TODO This stuff should probably go in a separate method
            // (they don't really fit into "ConfigureServices"), and much of it is probably no longer needed
            //MigrateSite(environment, noContextDeploymentsSettingsManager);
            //RemoveOldTracePath(environment);
            //RemoveTempFileFromUserDrive(environment);

            //// Temporary fix for https://github.com/npm/npm/issues/5905
            //EnsureNpmGlobalDirectory();
            //EnsureUserProfileDirectory();

            //// Skip SSL Certificate Validate
            //if (Kudu.Core.Environment.SkipSslValidation)
            //{
            //     ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            //}

            //// Make sure webpages:Enabled is true. Even though we set it in web.config, it could be overwritten by
            //// an Azure AppSetting that's supposed to be for the site only but incidently affects Kudu as well.
            ConfigurationManager.AppSettings["webpages:Enabled"] = "true";

            //// Kudu does not rely owin:appStartup.  This is to avoid Azure AppSetting if set.
            if (ConfigurationManager.AppSettings?["owin:appStartup"] != null)
            {
                // Set the appSetting to null since we cannot use AppSettings.Remove(key) (ReadOnly exception!)
                ConfigurationManager.AppSettings["owin:appStartup"] = null;
            }

            //RegisterRoutes(kernel, RouteTable.Routes);

            //// Register the default hubs route: ~/signalr
            //GlobalHost.DependencyResolver = new SignalRNinjectDependencyResolver(kernel);
            //GlobalConfiguration.Configuration.Filters.Add(
            //    new TraceDeprecatedActionAttribute(
            //        kernel.Get<IAnalytics>(),
            //        kernel.Get<ITraceFactory>()));
            //GlobalConfiguration.Configuration.Filters.Add(new EnsureRequestIdHandlerAttribute());

            //FileTarget target = LogManager.Configuration.FindTargetByName("file") as FileTarget;
            //String logfile = _webAppEnvironment.LogFilesPath + "/.txt";
            //target.FileName = logfile;
        }