Web API自托管:如何与主机通信?

时间:2014-01-07 18:57:47

标签: c# asp.net-web-api self-hosting

我在Windows服务上自托管WebAPI,目标是能够与Windows服务进行通信。

然而,尽管我能够在基本级别上毫无困难地连接到我的Web服务,但我很清楚Web服务与它的主机之间的关系。如果我的最终目标是通过Web服务从Windows服务公开信息,我如何共享信息并在它们之间进行通信? Web服务代码可以访问Windows服务代码中的内容吗?

编辑:嗯,太广了......如何缩小范围?

这是我的代码。我想要做的是调用“api / strings / 0”并让它返回“One”。但是,List indexOfStrings位于Windows服务主机中。 Web服务控制器如何访问信息?

public class StringsController : ApiController
{
    /// <summary>
    /// Get one entry from indexOfStrings
    /// </summary>
    public string Get(int listIndex)
    {
        // How to return indexOfStrings[listIndex]?
        return "";
    }
}

public class TestWindowsService : ServiceBase
{
    public const string ServiceAddress = "Address and port number"; 
    private HttpSelfHostServer _server;     // This is the server you're hosting WebAPI on
    private HttpSelfHostConfiguration _config;  // WebAPI config

    private List<string> indexOfStrings = new List<string>();

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        TestWindowsService service = new TestWindowsService() { AutoLog = false };
        ServiceBase.Run(service);
    }

    public TestWindowsService()
    {
        indexOfStrings.Add("One");
        indexOfStrings.Add("Two");
        indexOfStrings.Add("Three");

        //Create a host configuration 
        _config = new HttpSelfHostConfiguration(ServiceAddress);

        //Setup the routes 
        _config.Routes.MapHttpRoute(
            name: "DefaultGetApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });
        // Create the server
        _server = new HttpSelfHostServer(_config);
    }

    protected override void OnStart(string[] args)
    {
        _server.OpenAsync();
    }

    protected override void OnStop()
    {
        _server.CloseAsync().Wait();
        _server.Dispose();
    }
}

1 个答案:

答案 0 :(得分:2)

您可以通过插入依赖注入容器框架(如Unity,Ninject,Autofac,Structure Map等)并在容器中注册服务然后将该服务注入控制器来完成此操作。大多数DI框架都有Nuget包来支持Web API。

有一个使用Autofac here

的例子

但是,使用相同的基本原则,您可以在不使用DI框架的情况下将服务级别对象公开给控制器方法。

我们的想法是使用MessageHandler将对象实例插入Request Properties集合,然后在控制器方法中将其拉回。

 public class MyServiceHandler : DelegatingHandler
    {
        private readonly MyService _service;

        public MyServiceHandler(MyService service)
        {
            _service = service;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request.Properties["MyService_Key"] = _service;
            return base.SendAsync(request, cancellationToken);
        }
    }

在配置代码中,您可以使用

将消息处理程序添加到管道
        config.MessageHandlers.Add(new MyServiceHandler(new MyService()));

在您的控制器中,您可以访问此类服务

 public class StringsController : ApiController
 {
    /// <summary>
    /// Get one entry from indexOfStrings
    /// </summary>
    public string Get(int listIndex)
    {
        var myService = Request.Properties["MyService_Key"] as MyService;

        // How to return indexOfStrings[listIndex]?
        var mystring = myService.GetMyString(99);
        return "";
    }
}

理想情况下,您应该使用辅助方法或ApiController扩展方法来包装对服务的访问,但这些只是装饰性细节。

现在,您需要小心,因为现在可以在不同的线程上同时调用MyService。您需要确保使用并发集合来存储数据,或者在必要时使用锁。