I have an existing Windows Service that starts up, reads some configs, spins up some threads and does some useful work. Currently I log that work (through TopShelf.Log4Net / Log4Net) to disk (or console).
I was thinking it would be nice to expose an API to allow people to query the service (and in the future maybe even config it on the fly)
I'm having difficulty figuring out an appropriate way to plumb the two together though. My existing windows service has a bunch of worker threads and it knows the context of what work is being done, stats and progress and things like that.
But in the context of an ApiController actually handling a request I can't see an obvious/easy means of getting at those stats. I tried passing some object references in the Properties of the IAppBuilder in my Startup class, but any time I explicitly do the config myself I seem to lose the default MVC routes that I had.
Anyone have any suggestions on integrating OWIN into/on top of an existing service?
EDIT: Added code:
So I have a very basic TopShelf runner;
HostFactory.Run(x =>
{
x.Service<MyService>(s =>
{
s.ConstructUsing(name => new MyService());
s.WhenStarted(lb => lb.Start());
s.WhenStopped(lb => lb.Stop());
});
x.RunAsLocalSystem();
And within MyService I had a method StartWorkers() that goes off, starts up a bunch of workers, and keeps track of them.
public class MyService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<Worker> workers { get; set; }
private List<Thread> _threads { get; set; }
public MyService()
{
StartWorkers();
}
Now, I want to be able to query for the status of those workers from API requests, so I was thinking I could do something like;
public class MyService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<Worker> workers { get; set; }
private List<Thread> _threads { get; set; }
private IDisposable _webServer { get; set; }
public MyService()
{
StartWorkers();
StartWebServer();
}
private void StartWebServer()
{
const string baseAddress = "http://localhost:10281/";
_webServer = WebApp.Start<Startup>(url: baseAddress);
log.DebugFormat("Loaded webserver at address={0}", baseAddress);
}
All of the OWIN code right now is vanilla from the samples. When I test this code, I can hit the /api/values sample endpoint which is served from the ValuesController, and all is well.
Now where I'm missing a piece of glue is how to access anything useful in my application from my controller. I can do something naive like making the Worker list public static;
public class MyService
{
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static List<Worker> workers { get; set; }
In which case from my controller I can do something like;
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
// nonsense/test code
return MyService.workers.Select(i => i.ErrorsEncountered.ToString()).ToArray();
}
There must be a better way of access the internals of my application without manipulation visbility. What I've seen is that I can pass objects into the Properties of the IAppBuilder when using WebApp.Start(). These are visible then from the route configuration, and I see to be able to access them from within my ApiController, e.g.;
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
var someWorker = base.ControllerContext.Configuration.Properties["someWorkerReference"];
The problem I have when I go down that route is that 'WebApp.Start(url: baseAddress);' works and my routes all function, but using the WebApp.Start() method and passing in an Action causes my routes to break
So instead of spending time fixing the routes, I wanted to see if there's an obvious/known/official means of passing "context" into the web server