--- slug: host-configuration title: AppHost Configuration --- ::: info YouTube [youtu.be/mOpx5mUGoqI](https://youtu.be/mOpx5mUGoqI) ::: ### Anatomy of a ServiceStack AppHost All ServiceStack App's are configured within an AppHost which typically consists of the following elements: ```csharp // Service Name in Metadata Pages public class AppHost() : AppHostBase("MyApp"), IHostingStartup { public void Configure(IWebHostBuilder builder) => builder .ConfigureServices((context, services) => { // Configure ASP.NET Core IOC Dependencies services.AddSingleton(c => new RedisManagerPool()); // Add Plugins to extend your App with additional functionality services.AddPlugin(new AutoQueryFeature { MaxLimit = 100 // Feature specific configuration }); }); // Configure your AppHost with the necessary configuration and dependencies your App needs public override void Configure() { // Set Global AppHost Configuration base.SetConfig(new HostConfig { }); } } ``` ::: info [DebugMode](/debugging#debugmode) should be not be `true` when deployed to production. ::: ### Physical Project Structure See [Physical Project Structure](/physical-project-structure) docs to learn about ServiceStack's Solution layout. ### Register AppHost in .NET Core In ASP.NET Core, ServiceStack's AppHost is registered as middleware: ```csharp // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { //Register your ServiceStack AppHost as a .NET Core module app.UseServiceStack(new AppHost { // Use ASP.NET Core configuration sources, e.g. **appsettings.json** AppSettings = new NetCoreAppSettings(Configuration) }); } ``` See [.NET Core docs](/netcore) for more info on using ServiceStack on .NET Core. ### ConfigureAppHost The same functionality used to configure your AppHost in [Modular Startup configurations](/modular-startup), also exists in the stand-alone `HostContext.ConfigureAppHost()` API which also lets you lazily configure your ServiceStack AppHost at any point before it's initialized: ```csharp HostContext.ConfigureAppHost( beforeConfigure: appHost => ..., afterConfigure: appHost => ..., afterPluginsLoaded: appHost => ..., afterAppHostInit: appHost => ...); ``` ### ConfigureOperation The `ConfigureOperation` method has the same benefits for configuring an APIs metadata which is especially useful for [AutoQuery AutoGen](/autoquery/autogen) services since its operation metadata only exists after its default implementation is generated by AutoGen: ```csharp appHost.ConfigureOperation(op => op.FormLayout = new() { Input.For(x => x.DisplayName, x => x.Help = "Your first and last name"), Input.For(x => x.Email, x => x.Type = Input.Types.Email), Input.For(x => x.Password, x => x.Type = Input.Types.Password), Input.For(x => x.ConfirmPassword, x => x.Type = Input.Types.Password), }); ``` Which overrides the default Auto UI Form to use its custom layout: ### Run AppHost in .NET Framework ```csharp new AppHost().Init(); ``` ### IOC Registration See [IOC docs](/ioc) for an overview of the APIs and behavior of ServiceStack's built-in Funq IOC. ### Modularizing Services See [Modularizing Services](/modularizing-services) for info on Modularizing functionality in your AppHost. ### Default HostConfig The default configuration for ServiceStack's `HostConfig`, for the most up to date version see [HostConfig.cs](https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack/HostConfig.cs): ```csharp SetConfig(new HostConfig { WsdlServiceNamespace = "http://schemas.servicestack.net/types", ApiVersion = "1.0", EmbeddedResourceSources = new List(), EmbeddedResourceBaseTypes = new[] { HostContext.AppHost.GetType(), typeof(Service) }.ToList(), EmbeddedResourceTreatAsFiles = new HashSet(), EnableAccessRestrictions = true, EnableAutoHtmlResponses = true, WebHostPhysicalPath = "~".MapServerPath(), HandlerFactoryPath = ServiceStackPath, MetadataRedirectPath = null, DefaultContentType = null, PreferredContentTypes = new List { MimeTypes.Html, MimeTypes.Json, MimeTypes.Xml, MimeTypes.Jsv }, AllowJsonpRequests = true, AllowRouteContentTypeExtensions = true, UseHttpOnlyCookies = true, //default ;HttpOnly UseSecureCookies = true, //default ;Secure (https) UseSameSiteCookies = false, //default ;SameSite=Lax DebugMode = false, StrictMode = Env.StrictMode, DefaultDocuments = new List { "default.htm", "default.html", "default.cshtml", "default.md", "index.htm", "index.html", "default.aspx", "default.ashx", }, GlobalResponseHeaders = new Dictionary { { "Vary", "Accept" }, { "X-Powered-By", Env.ServerUserAgent }, }, IsMobileRegex = new Regex("Mobile|iP(hone|od|ad)|Android|BlackBerry|IEMobile|Kindle|(hpw|web)OS|Fennec|" + "Minimo|Opera M(obi|ini)|Blazer|Dolfin|Dolphin|Skyfire|Zune", RegexOptions.Compiled), RequestRules = new Dictionary> { {"AcceptsHtml", req => req.Accept?.IndexOf(MimeTypes.Html, StringComparison.Ordinal) >= 0 }, {"AcceptsJson", req => req.Accept?.IndexOf(MimeTypes.Json, StringComparison.Ordinal) >= 0 }, {"AcceptsXml", req => req.Accept?.IndexOf(MimeTypes.Xml, StringComparison.Ordinal) >= 0 }, {"AcceptsJsv", req => req.Accept?.IndexOf(MimeTypes.Jsv, StringComparison.Ordinal) >= 0 }, {"AcceptsCsv", req => req.Accept?.IndexOf(MimeTypes.Csv, StringComparison.Ordinal) >= 0 }, {"IsAuthenticated", req => req.IsAuthenticated() }, {"IsMobile", req => Instance.IsMobileRegex.IsMatch(req.UserAgent) }, {"{int}/**", req => int.TryParse(req.PathInfo.Substring(1).LeftPart('/'), out _) }, {"path/{int}/**", req => { var afterFirst = req.PathInfo.Substring(1).RightPart('/'); return !string.IsNullOrEmpty(afterFirst) && int.TryParse(afterFirst.LeftPart('/'), out _); }}, {"**/{int}", req => int.TryParse(req.PathInfo.LastRightPart('/'), out _) }, {"**/{int}/path", req => { var beforeLast = req.PathInfo.LastLeftPart('/'); return !string.IsNullOrEmpty(beforeLast) && int.TryParse(beforeLast.LastRightPart('/'), out _); }}, }, IgnoreFormatsInMetadata = new HashSet(StringComparer.OrdinalIgnoreCase) {}, AllowFileExtensions = new HashSet(StringComparer.OrdinalIgnoreCase) { "js", "ts", "tsx", "jsx", "css", "htm", "html", "shtm", "txt", "xml", "rss", "csv", "pdf", "jpg", "jpeg", "gif", "png", "bmp", "ico", "tif", "tiff", "svg", "avi", "divx", "m3u", "mov", "mp3", "mpeg", "mpg", "qt", "vob", "wav", "wma", "wmv", "flv", "swf", "xap", "xaml", "ogg", "ogv", "mp4", "webm", "eot", "ttf", "woff", "woff2", "map", "xls", "xla", "xlsx", "xltx", "doc", "dot", "docx", "dotx", "ppt", "pps", "ppa", "pptx", "potx", "wasm" }, CompressFilesWithExtensions = new HashSet(), AllowFilePaths = new List { "jspm_packages/**/*.json", //JSPM ".well-known/**/*", //LetsEncrypt }, ForbiddenPaths = new List(), DebugAspNetHostEnvironment = Env.IsMono ? "FastCGI" : "IIS7", DebugHttpListenerHostEnvironment = Env.IsMono ? "XSP" : "WebServer20", EnableFeatures = Feature.All, WriteErrorsToResponse = true, ReturnsInnerException = true, DisposeDependenciesAfterUse = true, LogUnobservedTaskExceptions = true, HtmlReplaceTokens = new Dictionary(), AddMaxAgeForStaticMimeTypes = new Dictionary { { "image/gif", TimeSpan.FromHours(1) }, { "image/png", TimeSpan.FromHours(1) }, { "image/jpeg", TimeSpan.FromHours(1) }, }, AppendUtf8CharsetOnContentTypes = new HashSet { MimeTypes.Json, }, RouteNamingConventions = new List { RouteNamingConvention.WithRequestDtoName, RouteNamingConvention.WithMatchingAttributes, RouteNamingConvention.WithMatchingPropertyNames }, MapExceptionToStatusCode = new Dictionary(), UseSaltedHash = false, FallbackPasswordHashers = new List(), AllowSessionIdsInHttpParams = false, AllowSessionCookies = true, RestrictAllCookiesToDomain = null, DefaultJsonpCacheExpiration = new TimeSpan(0, 20, 0), MetadataVisibility = RequestAttributes.Any, Return204NoContentForEmptyResponse = true, AllowJsConfig = true, AllowPartialResponses = true, AllowAclUrlReservation = true, AddRedirectParamsToQueryString = false, RedirectToDefaultDocuments = false, RedirectDirectoriesToTrailingSlashes = true, StripApplicationVirtualPath = false, ScanSkipPaths = new List { "obj/", "bin/", "node_modules/", "jspm_packages/", "bower_components/", "wwwroot_build/", "wwwroot/", // only in .NET Framework }, RedirectPaths = new Dictionary { { "/metadata/", "/metadata" }, }, IgnoreWarningsOnPropertyNames = new List { Keywords.Format, Keywords.Callback, Keywords.Debug, Keywords.AuthSecret, Keywords.JsConfig, Keywords.IgnorePlaceHolder, Keywords.Version, Keywords.VersionAbbr, Keywords.Version.ToPascalCase(), Keywords.ApiKeyParam, Keywords.Code, Keywords.Redirect, Keywords.Continue, "s", "f" }, XmlWriterSettings = new XmlWriterSettings { Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), }, FallbackRestPath = null, UseHttpsLinks = false, UseJsObject = true, EnableOptimizations = true, UseCamelCase = true, // only in .NET Core; otherwise false }); ``` ## Configure Logging To ensure every ServiceStack service uses the same Global Logger it should be configured before ServiceStack's `AppHost` is initialized, e.g: ```csharp LogManager.LogFactory = new ConsoleLogFactory(); new AppHost().Init(); ``` See [Logging docs](/logging) for info on the various logging providers available. ## Testing See [Unit and Integration Testing](/testing) docs for testing with ServiceStack.