---
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.