Question

I'm self-hosting WebAPI on a Windows service with the goal of being able to communicate with the Windows service.

However, although I'm able to connect to my web service with no difficulty at a basic level, I'm very unclear on the relationship between the web service and it's host. If my ultimate goal is to expose information from the Windows service through the Web service, how can I share information and communicate between them? What does the web service code have access to that's in the windows service code?

EDIT: Hmmm, too broad... how to narrow this down?

Here is my code. What I want to do is to call "api/strings/0" and have it return "One". However, the List indexOfStrings lives in the Windows Service host. How does the web service controller access the information?

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();
    }
}
Était-ce utile?

La solution

You can do this by plugging in a Dependency Injection container framework like Unity, Ninject, Autofac, Structure Map, etc and registering a service in the container and then injecting that service into your controller. There are Nuget packages for most of these DI frameworks to support Web API.

There is an example using Autofac here

However, using the same basic principle you can expose a service level object to controllers methods without using a DI Framework.

The idea is that you use a MessageHandler to insert your object instances to the Request Properties collection and then in the controller method pull it back out.

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

In your configuration code you can add your message handler to the pipeline using,

        config.MessageHandlers.Add(new MyServiceHandler(new MyService()));

and in your controller you can access the service like this,

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

Ideally you should wrap up the access to your service in a helper method or a ApiController extension method, but those are just cosmetic details.

Now, you need to be careful, because MyService can now be called simultaneously on different threads. You need to ensure that you either use Concurrent collections for storing data or you use locks where necessary.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top