Unload the AppDomain:
The only way to cleanly restart the ServiceStack host is to unload the application domain it is running in and start a fresh instance in a new application domain.
Your issue is related to this question & answer.
1: Create your AppHost (as per normal):
An example AppHost
which registers an object called MyTest
with the IoC container.
public class AppHost : AppSelfHostBase
{
public AppHost(): base("My ServiceStack Service", typeof(AppHost).Assembly)
{
}
public override void Configure(Funq.Container container)
{
container.Register<MyTest>(c => new MyTest());
}
}
public class MyTest
{
public string Name { get { return "Hello"; } }
}
2: Create an IsolatedAppHost
Class:
The IsolatedAppHost
class is used to start your application host, that will be run in the isolated AppDomain. You can start and configure whatever AppHost
you need here, such as your HttpTestableAppHost
.
public class IsolatedAppHost : MarshalByRefObject
{
readonly AppHost Host;
public IsolatedAppHost()
{
// Start your HttpTestableAppHost here
Host = new AppHost();
Host.Init();
Host.Start("http://*:8090/");
Console.WriteLine("ServiceStack is running in AppDomain '{0}'", AppDomain.CurrentDomain.FriendlyName);
}
public void RunTest(Action<AppHost> test)
{
test.Invoke(Host);
}
public void Teardown()
{
if(Host != null)
{
Console.WriteLine("Shutting down ServiceStack host");
if(Host.HasStarted)
Host.Stop();
Host.Dispose();
}
}
}
3: Create your TestFixture
:
Your TestFixureSetup
method will need to create an instanced of the IsolatedAppHost
in a new AppDomain
. And the TestFixtureTearDown
will ensure the AppHost
and the domain are correctly shutdown.
[TestFixture]
public class Test
{
AppDomain ServiceStackAppDomain;
IsolatedAppHost IsolatedAppHost;
[TestFixtureSetUp]
public void TestFixtureSetup()
{
// Get the assembly of our host
var assemblyName = typeof(IsolatedAppHost).Assembly.GetName();
// Create new AppDomain
ServiceStackAppDomain = AppDomain.CreateDomain("ServiceStackAppDomain");
// Load our assembly
ServiceStackAppDomain.Load(assemblyName);
// Create instance
var handle = ServiceStackAppDomain.CreateInstance(assemblyName.FullName, "MyApp.Tests.IsolatedAppHost");
// Unwrap so we can access methods
IsolatedAppHost = (IsolatedAppHost)handle.Unwrap();
}
[TestFixtureTearDown]
public void TestFixtureTearDown()
{
// Tell ServiceStack to stop the host
IsolatedAppHost.Teardown();
// Shutdown the ServiceStack application
AppDomain.Unload(ServiceStackAppDomain);
ServiceStackAppDomain = null;
}
// Tests go here
}
4: Running tests:
As the test runner AppDomain
and the AppHost
AppDomain
are now different, we cannot access the AppHost
from our tests directly. So we pass our test to the RunTest
method instance of our IsolatedAppHost
.
IsolatedAppHost.RunTest(appHost => {
// Your test goes here
});
For example:
[Test]
public void TestWillPass()
{
IsolatedAppHost.RunTest(appHost => {
var t = appHost.TryResolve<MyTest>();
Assert.That(t.Name, Is.EqualTo("Hello"));
});
}
[Test]
public void TestWillFail()
{
IsolatedAppHost.RunTest(appHost => {
var t = appHost.TryResolve<MyTest>();
Assert.That(t.Name, Is.EqualTo("World"));
});
}
The full source code is here. I hope that helps.