Reputation: 157
I'm getting an error when i try to run some tests on my servicestack web service. I'm using ServiceStack 4.5.8 and Nunit 3.5. The solution was created initially from a ServiceStackVS template.
The error, which appears on a number of tests, is
System.IO.InvalidDataException : ServiceStackHost.Instance has already been set (BasicAppHost)</br>
TearDown : System.NullReferenceException : Object reference not set to an instance of an object.</br>
at ServiceStack.ServiceStackHost.Init()</br>
at MyApp.Tests.EchoServiceUnitTests.OneTimeSetup() in </br>
C:\Repos\MyApp\Myapp\MyApp.Tests\EchoServiceUnitTests.cs:line 45 </br>
--TearDown</br>
at MyApp.Tests.EchoServiceUnitTests.TestFixtureTearDown() in </br>C:\Repos\MyApp\MyApp\MyApp.Tests\EchoServiceUnitTests.cs:line 54
One of the tests that regularly generates this error is
namespace Tests
{
[TestFixture]
public class EchoServiceUnitTests
{
private ServiceStackHost appHost;
[OneTimeSetUp]
public void OneTimeSetup()
{
this.appHost = new BasicAppHost(typeof(EchoService).Assembly).Init();
}
[OneTimeTearDown]
public void TestFixtureTearDown()
{
this.appHost.Dispose();
}
[Test]
public void TestService()
{
const string Message = "Hello";
var service = this.appHost.Container.Resolve <EchoService>();
var response = (EchoResponse)service.Any(new Echo
{
Message = Message
});
Assert.That(response.Message,
Is.EqualTo(Message));
}
}
}
the service for this is
namespace ServiceInterface
{
public class EchoService : Service
{
public object Any(Echo request)
{
return new EchoResponse {Message = request.Message};
}
}
}
[Route("/Echo")]
[Route("/Echo/{Message}")]
public class Echo : IReturn<EchoResponse>
{
public string Message { get; set; }
}
public class EchoResponse : IHasResponseStatus
{
public EchoResponse()
{
this.ResponseStatus = new ResponseStatus();
}
public string Message { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
And finally my apphost
namespace MyApplication
{
using System;
using Funq;
using ServiceInterface;
using ServiceModel.Validators;
using ServiceStack;
using ServiceStack.Admin;
using ServiceStack.Api.Swagger;
using ServiceStack.Caching;
using ServiceStack.Configuration;
using ServiceStack.Logging;
using ServiceStack.Logging.NLogger;
using ServiceStack.MsgPack;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.SqlServer.Converters;
using ServiceStack.ProtoBuf;
using ServiceStack.Razor;
using ServiceStack.Validation;
using ServiceStack.VirtualPath;
using ServiceStack.Wire;
public class AppHost : AppHostBase
{
public static ILog Log = LogManager.GetLogger(typeof(AppHost));
public AppHost()
: base("MyApp",
typeof(HelloService).Assembly) { }
public override void Configure(Container container)
{
LogManager.LogFactory = new NLogFactory();
Log = LogManager.GetLogger(this.GetType());
this.Plugins.Add(new RazorFormat());
this.Plugins.Add(new PostmanFeature());
this.Plugins.Add(new SwaggerFeature());
this.Plugins.Add(new AdminFeature());
var ormSettings = new AppSettings();
container.Register <ICacheClient>(new MemoryCacheClient());
var dbFactory = new OrmLiteConnectionFactory(ormSettings.GetString("SqlDbConnection"),
SqlServerDialect.Provider);
dbFactory.RegisterConnection("Database2",
ormSettings.GetString("Sql2Connection"),
SqlServerDialect.Provider);
SqlServerDialect.Provider.RegisterConverter<DateTime?>(new SqlServerDateTimeConverter());
this.Plugins.Add(new RequestLogsFeature
{
RequestLogger = new CsvRequestLogger(files: new FileSystemVirtualPathProvider(this,
this.Config.WebHostPhysicalPath),
requestLogsPattern: "requestlogs/{year}-{month}/{year}-{month}-{day}.csv",
errorLogsPattern: "requestlogs/{year}-{month}/{year}-{month}-{day}-errors.csv",
appendEvery: TimeSpan.FromSeconds(1)),
EnableRequestBodyTracking = true,
EnableResponseTracking = true,
EnableErrorTracking = true,
});
this.Plugins.Add(new AutoQueryDataFeature
{
MaxLimit = 1000
});
this.Plugins.Add(new AutoQueryFeature());
var sse = new ServerEventsFeature
{
StreamPath = "/event-stream",
HeartbeatPath = "/event-heartbeat",
UnRegisterPath = "/event-unregister",
SubscribersPath = "/event-subscribers",
LimitToAuthenticatedUsers = false,
IdleTimeout = TimeSpan.FromSeconds(30),
HeartbeatInterval = TimeSpan.FromSeconds(10),
NotifyChannelOfSubscriptions = true,
};
this.Plugins.Add(sse);
Plugins.Add(new AdminFeature());
Plugins.Add(new WireFormat());
Plugins.Add(new MsgPackFormat());
Plugins.Add(new ProtoBufFormat());
}
}
}
I've tried a variety of suggestions including making the apphost in the test static, but nothing seems to work for me. I then tried the following test which also generated the same error which suggests to me that there is something in the apphost which is wrong but I can't see what.
[TestFixture(Category = "AppHost")]
public class AppHostTests
{
/// <summary>
/// The app host doesnt throw exception.
/// </summary>
[Test]
public void AppHostDoesntThrowException()
{
var apphost = new AppHost();
Assert.That(() => apphost.Init(),
Throws.Nothing);
}
}
The tests that generate this error whether I am using NCRUNCH (set to run one at a time) or if I use resharpers run all tests. It's generally the same tests that generate this error, though that seems to vary. In all cases, if I then run the tests manually they all pass.
Upvotes: 3
Views: 662
Reputation: 143369
You can only have 1 AppHost initialized and running at the same time where somehow NCrunch test is being run whilst there is another AppHost still in use. Maybe you can try debugging and setting a breakpoint that checks if ServiceStackHost.Instance
is not null before trying to initialize another AppHost.
Note the AppHostBase is an ASP.NET Web App which may be causing the interference if it's running in the same project as the unit tests. If you want an integration test use AppSelfHostBase instead which you would use in place of BasicAppHost where you'd want to run a full integration test.
Upvotes: 3