3

The title sums up my issue. I have try-catch blocks around the service's OnStart method and the Main method in the service, and no exception is ever thrown. The service starts and immediately stops, with the following message:

The Foo service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs.

The same behavior can be observed on the test server, so it is not machine-dependent. I've verified that the configuration file is present and contains the appropriate settings.

I cannot see any obvious reason why this would be occurring. Can someone please take a look at this and shed some light on it? I've consulted other, similar questions and none of them shed any light on this particular service.

Startup.cs:

public class Startup
{
    // This code configures Web API. The Startup class is specified as a type
    // parameter in the WebApp.Start method.
    public void Configuration(IAppBuilder appBuilder)
    {
        // Configure Web API for self-host.
        var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();
        appBuilder.UseWebApi(config);
    }
}

WebApiService.cs:

public partial class WebApiService : ServiceBase
{
    private readonly IConfig config;
    private IDisposable webApp;

    public WebApiService()
    {
        try
        {
            InitializeComponent();
            this.config = UnityBootstrapper.Initialize().Resolve<IConfig>();
        }
        catch (Exception e)
        {
            new ApplicationEventLog(new Config()).WriteError(e);
        }
    }

    protected override void OnStart(string[] args)
    {
        try
        {
            var baseUrl = $"http://*:{this.config.WebApiHttpPort}";

            this.webApp = WebApp.Start<Startup>(baseUrl);
        }
        catch (Exception e)
        {
            new ApplicationEventLog(this.config).WriteError(e);
        }
    }

    protected override void OnStop()
    {
        this.webApp?.Dispose();
        this.webApp = null;
    }

    protected override void OnShutdown()
    {
        this.webApp?.Dispose();
        this.webApp = null;
    }
}

WebApiService.Designer.cs

partial class WebApiService
{
    /// <summary> 
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Component Designer generated code

    /// <summary> 
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
        this.ServiceName = "Foo";
    }

    #endregion
}

Program.cs:

public static class Program
{
    public static bool IsConsoleApp = false;
    public static bool LogRequests = false;

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    public static void Main(params string[] args)
    {
        try
        {
            if (args.Length > 0 && args.Any(a => a.ToLower().In("l", "-l", "/l")))
            {
                LogRequests = true;
            }

            if (args.Length > 0
                && args[0].ToLower().In("c", "-c", "/c"))
            {
                RunAsApp();
            }
            else
            {
                RunAsService();
            }
        }
        catch (Exception e)
        {
            new ApplicationEventLog(new Config()).WriteError(e);
        }
    }

    private static void RunAsService()
    {
        Program.IsConsoleApp = false;

        var servicesToRun = new ServiceBase[]
                                      {
                                          new WebApiService()
                                      };
        ServiceBase.Run(servicesToRun);
    }

    private static void RunAsApp()
    {
        Program.IsConsoleApp = true;

        var config = UnityBootstrapper.Initialize().Resolve<IConfig>();
        var url = $"http://*:{config.WebApiHttpPort}";

        Console.WriteLine($@"Running. Hosted at: {url}");
        Console.WriteLine(@"Press ENTER to exit.");

        using (WebApp.Start<Startup>(url))
        {
            while (Console.ReadKey().Key != ConsoleKey.Enter)
            {
                Thread.Sleep(0);
            }
        }

        Program.IsConsoleApp = false;
    }
}

LogController.cs:

[RoutePrefix("api/log")]
public class LogController : ApiController
{
    private readonly ILogger logger;
    private readonly IContextFactory contextFactory;
    private readonly IConfig config;

    public LogController() : base()
    {
        var container = UnityBootstrapper.Initialize();

        this.logger = container.Resolve<ILogger>();
        this.config = container.Resolve<IConfig>();
        this.contextFactory = container.Resolve<IContextFactory>();
    }

    [HttpGet]
    [Route("Status")]
    public string Status()
    {
    }

    [HttpPost]
    [Route("Message")]
    public string Write([FromBody] LogMessage logMessage)
    {
        // Elided for ... reasons
    }

    [HttpPost]
    [Route("Performance")]
    public string Write([FromBody] PerformanceMessage performanceMessage)
    {
        // Elided for ... reasons
    }
}

Edit: Added WebApiService.Designer.cs, as the service shuts down when it returns from InitializeComponent.

Edit 2: I've traced it to WebApp.Start<Startup>(baseUrl) in WebApiService.cs. A TargetInvocationException is thrown, with an HttpListenerException as the inner exception. The message on the HttpListenerException is "Access is denied."

System.Reflection.TargetInvocationException occurred
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Owin.Hosting.ServerFactory.ServerFactoryAdapter.Create(IAppBuilder builder)
   at Microsoft.Owin.Hosting.Engine.HostingEngine.StartServer(StartContext context)
   at Microsoft.Owin.Hosting.Engine.HostingEngine.Start(StartContext context)
   at Microsoft.Owin.Hosting.Starter.DirectHostingStarter.Start(StartOptions options)
   at Microsoft.Owin.Hosting.Starter.HostingStarter.Start(StartOptions options)
   at Microsoft.Owin.Hosting.WebApp.StartImplementation(IServiceProvider services, StartOptions options)
   at Microsoft.Owin.Hosting.WebApp.Start(StartOptions options)
   at Microsoft.Owin.Hosting.WebApp.Start[TStartup](StartOptions options)
   at Microsoft.Owin.Hosting.WebApp.Start[TStartup](String url)
   at Foo.Logging.WebApi.WebApiService.OnStart(String[] args) in C:\Dev\Foo\Foo.WebApi\WebApiService.cs:line 45

Inner Exception 1:
HttpListenerException: Access is denied

I've researched possible causes for this, and it could be the URL or an ACL. I changed the URL to http://+:{this.config.WebApiHttpPort}, to no avail. I then created an ACL as follows:

netsh http add urlacl http://+:8089/ user=Everyone

The error still occurs.

Mike Hofer
  • 16,477
  • 11
  • 74
  • 110
  • 1
    What happens when you debug the service? – Camilo Terevinto Oct 12 '17 at 17:25
  • Since the service stops right away, I can't attach Visual Studio's debugger to it. I can run it as a console app, tho, and it works fine. Let me see what happens when I add Debugger.Launch() to the Main routine. – Mike Hofer Oct 12 '17 at 17:36
  • Nothing else in the windows application event log? What account is the service running under? See https://stackoverflow.com/questions/24976425/running-self-hosted-owin-web-api-under-non-admin-account – Peter Bons Oct 12 '17 at 17:38
  • @PeterBons It runs under a special service account reserved for applications. It has administrative privileges throughout the network. – Mike Hofer Oct 12 '17 at 17:44
  • @CamiloTerevinto I added a request for additional time (5 minutes worth!) to OnStart. That allowed me to attach a VS debugger to it. Oddly, it just stops running with no warning when InitializeComponent in WebApiService completes. It never gets to the call to initialize Unity. Puzzling. – Mike Hofer Oct 12 '17 at 17:45
  • @CamiloTerevinto I've observed that, while I'm stepping through the code, no errors are occurring or being thrown, but the service just stops mid-execution. It's very strange. – Mike Hofer Oct 12 '17 at 18:07
  • @MikeHofer Could it be that there is some unhandled exception of those that cannot be handled? – Camilo Terevinto Oct 12 '17 at 18:12
  • @CamiloTerevinto I turned on all exceptions, and discovered that the problem appears to be the call to `WebApp.Start(baseUrl)`. It throws a TargetInvocationException with an HttpListenerException as the inner exception. The message there is "Access is denied." I'm digging into that now. – Mike Hofer Oct 12 '17 at 19:13
  • Sounds like opening the port could be the problem. https://stackoverflow.com/a/21634519/6320217 – DotNetDev Oct 14 '17 at 06:02
  • @DotNetDev The port is open on the server. You can hit it from any other server in the intranet, and browse the root of the virtual directory. – Mike Hofer Oct 20 '17 at 16:38

0 Answers0