// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddThreaxProgressiveWebApp(o => Configuration.Bind("DisplayConfig", o));

            //Add the client side configuration object
            services.AddClientConfig(clientConfig, o =>
            {
                o.RouteArgsToClear = new List <string>()
                {
                    "inPagePath"
                };
            });

            services.AddAssetBundle(o =>
            {
                o.UseBundles = appConfig.UseAssetBundles;
            });

            ApiExplorerController.Allow = appConfig.AllowApiExplorer;

            services.AddTimeTracking();

            services.AddHalClientGen(new HalClientGenOptions()
            {
                SourceAssemblies = new Assembly[] { this.GetType().GetTypeInfo().Assembly, typeof(UserSearchController).Assembly },
                CSharp           = new CSharpOptions()
                {
                    Namespace = "AppTemplate.Client"
                }
            });

            services.AddConventionalIdServerAuthentication(o =>
            {
                o.AppOptions             = authConfig;
                o.CookiePath             = appConfig.PathBase;
                o.AccessDeniedPath       = "/Account/AccessDenied";
                o.EnableIdServerMetadata = appConfig.EnableIdServerMetadata;
            });

            services.AddAppDatabase(appConfig.ConnectionString);
            services.AddAppMapper();
            services.AddAppRepositories();

            var halOptions = new HalcyonConventionOptions()
            {
                BaseUrl              = appConfig.BaseUrl,
                HalDocEndpointInfo   = new HalDocEndpointInfo(typeof(EndpointDocController), appConfig.CacheToken),
                EnableValueProviders = appConfig.EnableValueProviders
            };

            services.AddConventionalHalcyon(halOptions);
            services.AddHalcyonClient();

            services.AddExceptionErrorFilters(new ExceptionFilterOptions()
            {
                DetailedErrors = appConfig.DetailedErrors
            });

            services.AddThreaxIdServerClient(o =>
            {
                Configuration.Bind("IdServerClient", o);
            })
            .SetupHttpClientFactoryWithClientCredentials(o =>
            {
                Configuration.Bind("IdServerClient", o);
                o.GetSharedClientCredentials = s => Configuration.Bind("SharedClientCredentials", s);
            });

            // Add framework services.
            services.AddMvc(o =>
            {
                o.UseExceptionErrorFilters();
                o.UseConventionalHalcyon(halOptions);
            })
            .AddNewtonsoftJson(o =>
            {
                o.SerializerSettings.SetToHalcyonDefault();
                o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            })
            .AddRazorRuntimeCompilation()
            .AddConventionalIdServerMvc()
            .AddThreaxUserLookup(o =>
            {
                o.UseIdServer();
            })
            .AddThreaxCacheUi(appConfig.CacheToken, o =>
            {
                o.CacheControlHeader = appConfig.CacheControlHeaderString;
            });

            services.ConfigureHtmlRapierTagHelpers(o =>
            {
                o.FrontEndLibrary = HtmlRapier.TagHelpers.FrontEndLibrary.Bootstrap4;
            });

            services.AddScoped <IToolRunner>(s =>
            {
                var runner = new ToolRunner()
                             .AddTool("migrate", new ToolCommand("Migrate database to newest version. Run anytime new migrations have been added.", async a =>
                {
                    await a.Migrate();
                }))
                             .AddTool("seed", new ToolCommand("Seed database data. Only needed for an empty database.", async a =>
                {
                    await a.Seed();
                }))
                             .AddTool("addadmin", new ToolCommand("Add given guids as a user with permissions to all roles in the database.", async a =>
                {
                    await a.AddAdmin();
                }));
#if DEBUG
                runner.AddTool("updateConfigSchema", new ToolCommand("Update the schema file for this application's configuration.", async a =>
                {
                    var json = await Configuration.CreateSchema();
                    await File.WriteAllTextAsync("appsettings.schema.json", json);
                }))
                .AddTool("createModel", new ToolCommand("Create a model from a model schema using Threax.ModelGen.", a => Threax.ModelGen.ModelGenerator.RunGenerate(a.Args[0])))
                .AddTool("deleteModel", new ToolCommand("Delete a model from a model schema using Threax.ModelGen.", a => Threax.ModelGen.ModelGenerator.RunDelete(a.Args[0])))
                .UseClientGenTools();
#endif
                return(runner);
            });

            services.AddUserBuilderForUserWhitelistWithRoles();

            services.AddThreaxCSP(o =>
            {
                o.AddDefault().AddNone();
                o.AddImg().AddSelf().AddData();
                o.AddConnect().AddSelf();
                o.AddManifest().AddSelf();
                o.AddFont().AddSelf();
                o.AddFrame().AddSelf().AddEntries(new String[] { authConfig.Authority });
                o.AddScript().AddSelf().AddNonce();
                o.AddStyle().AddSelf().AddNonce();
                o.AddFrameAncestors().AddSelf();
            });

            services.AddLogging(o =>
            {
                o.AddConfiguration(Configuration.GetSection("Logging"))
                .AddConsole()
                .AddDebug();
            });

            services.AddEntryPointRenderer <EntryPointController>(e => e.Get());
            services.AddSingleton <AppConfig>(appConfig);

            if (appConfig.EnableResponseCompression)
            {
                services.AddResponseCompression();
            }

            IdentityModelEventSource.ShowPII = appConfig.ShowPII;
        }