将ASP.Net OWIN引入现有的TopShelf Windows服务

时间:2015-02-18 11:18:37

标签: c# asp.net rest owin topshelf

我有一个现有的Windows服务启动,读取一些配置,旋转一些线程并做一些有用的工作。 目前我将该工作(通过TopShelf.Log4Net / Log4Net)记录到磁盘(或控制台)。

我认为公开API以允许人们查询服务(以及将来甚至可能即时配置)会很好。

我很难找到合适的方法将两者连接在一起。我现有的Windows服务有一堆工作线程,它知道正在完成的工作,统计和进度以及类似的事情。

但是在ApiController实际处理请求的情况下,我无法看到明显/简单的方法来获取这些统计数据。我尝试在我的Startup类中的IAppBuilder的属性中传递一些对象引用,但是当我自己显式地执行配置时,我似乎丢失了我的默认MVC路由。

任何人都有关于将OWIN集成到现有服务之上/之上的任何建议吗?

编辑:添加代码:

所以我有一个非常基本的TopShelf跑步者;

        HostFactory.Run(x =>
            {
                x.Service<MyService>(s =>
                {
                    s.ConstructUsing(name => new MyService());
                    s.WhenStarted(lb => lb.Start());
                    s.WhenStopped(lb => lb.Stop());
                });
                x.RunAsLocalSystem();

在MyService中,我有一个方法StartWorkers()关闭,启动一堆工作人员,并跟踪它们。

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();
    }

现在,我希望能够从API请求中查询这些工作者的状态,所以我想我可以做类似的事情;

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);
    }

现在所有的OWIN代码都是来自样本的香草。 当我测试这段代码时,我可以点击从ValuesController提供的/ api / values示例端点,一切都很好。

现在,我错过了一块胶水是如何从我的控制器访问我的应用程序中有用的东西。我可以做一些天真的事情,比如使工人列表公开静态;

public class MyService
{
    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    public static List<Worker> workers { get; set; }

在我的控制器的情况下,我可以做类似的事情;

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        // nonsense/test code
        return MyService.workers.Select(i => i.ErrorsEncountered.ToString()).ToArray();
    }

在没有操作可见性的情况下,必须有更好的方法来访问我的应用程序的内部。 我所看到的是,当使用WebApp.Start()时,我可以将对象传递给IAppBuilder的属性。然后从路由配置中可以看到它们,我看到能够从我的ApiController中访问它们,例如;

public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        var someWorker = base.ControllerContext.Configuration.Properties["someWorkerReference"];

当我走这条路时,我遇到的问题是&#39; WebApp.Start(url:baseAddress);&#39;工作和我的路线都运行,但使用WebApp.Start()方法并传入一个动作导致我的路线中断

因此,我没有花时间修理路线,而是想看看是否有明显的/已知的/官方的传递途径&#34; context&#34;进入网络服务器

1 个答案:

答案 0 :(得分:0)

所以这就是容器非常有用的地方。如果你有类似public class MyService : IStatusProvider {}的内容,那么你可以将MyServiceIStatusProvider注册到同一个实例中。 How to use DI container when OwinStartup谈到使用OWIN&amp;依赖注入。您可以将容器设置添加到程序的开头,将s.ConstructUsing(name => new MyService());更改为

s.ConstructUsing(name => {
    var container = new Container();
    // container setup
    return container.resolve<MyService>(); // method depends on your container
});