views:

62

answers:

1

I am developing a very simple Generic Host solution that will allow us to host assemblies as windows services (ala NServiceBus). I'm coming across the following exception (similar to the comments mentioned on Dru's blog post). I need this to work so I can host services in different AppDomains.

"Type 'MyProject.WindowsServices.GenericHost.Program+<>c__DisplayClass5' in Assembly 'MyProject.WindowsServices.GenericHost, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable."

I'm using the Topshelf 1.0 RC binaries available from the download link on the topshelf homepage (topshelf-project.com). I've tried the latest build (29/07/2010), and the builds avialable for download from google code and github! I can't get any of them to work for me!

This is working in the NServiceBus library with an older version of Topshelf (the dll is versioned 0.8.0.96). With some minor code changes to what I have below (use CreateServiceLocator in place of HowToBuildService) it works for me with these older binaries, but I'd rather stick to the latest code to take advantage of any planned fixes or enhancements.

Here is my code.

static void Main(string[] args)
{
    ArgumentParser arguments = new ArgumentParser(args);
    string configFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
        arguments.ServiceType.Assembly.ManifestModule.Name + ".config");

    RunConfiguration cfg = RunnerConfigurator.New(x =>
    {
        x.SetServiceName(arguments.ServiceName);
        x.SetDisplayName(arguments.DisplayName);
        x.SetDescription(arguments.Description);

        if (string.IsNullOrEmpty(arguments.UserName))
        {
            x.RunAsLocalSystem();
        }
        else
        {
            x.RunAs(arguments.UserName, arguments.Password);
        }

        x.ConfigureServiceInIsolation<GenericHost>(c =>
        {
            c.ConfigurationFile(configFile);
            c.Named(arguments.ServiceType.AssemblyQualifiedName);
            c.HowToBuildService(name => new GenericHost(arguments.ServiceType));
            c.WhenStarted(tc => tc.Start());
            c.WhenStopped(tc => tc.Stop());
        });
    });

    Runner.Host(cfg, args);
}

Also of note is that my GenericHost class and the class identified by arguments.ServiceType both implement MarshalByRefObject and I have also made these classes Serializable to see if that would help. It's not these classes that are causing the problem though, it appears to be complaining about an anonymous type generated by the C# compiler for one or more of the lambda's I have configured.

Is anyone else seeing this problem with using ConfigureServiceInIsolation()? If not, does anyone know what I'm missing here? Let me know if you need more info, e.g. stack trace or more code.

A: 

If you're only using one service inside the host, I would remove the "InIsolation". It doesn't work right but in a future version of TopShelf (we are currently working on it) I think we have a better answer for this issue. On top of the ability to just drop files in a host and have that spin up your service in a new AppDomain automagically.

I would say this falls under a know issue and unless there's a compelling reason to use the InIsolation avoid it for the moment. You can't marshal lambda expressions across app domain barriers, hence the issue you're seeing. If the InIsolation issue is important enough, I can look into the effort to fix that vs. the timeline before we plan on releasing the newest version. [You can grab the latest dev. bits from here: http://github.com/legomaster/Topshelf -- warning, we're still under active development but I think all the major bugs are now squashed].

If you want to discuss this further, it might be easiest to post on the MassTransit list where all the developers are watching: http://groups.google.com/group/masstransit-discuss

I hope this helps!

Travis
Thanks for you answer Travis! Sounds like future versions will have a kind of uber generic host. Dropping files in to get windows services running would be a very cool feature. For now I will see if I can set something up without the InIsolation part. I may just switch back to having a custom executable per service, this will be fine as a short term solution. Any idea when the next version might be ready?
Sam
I had it targeted for an Oct, 2010 release, to meet my internal release. I expect we'll still hit that timeline even though my deadline has been pushed back by our stakeholders.
Travis
Once we get this all released, we'll work Udi to get this into the mainline NServiceBus as well. So if you get it working without Isolation it might serve you just sitting on it until Udi gets all the new bits mixed in. But that's completely up to you. I know Udi is asking for a few more features from us that I hope we can deliver on this year.
Travis
I've simplified my implementation for now to just have an executable per service. Keeping it "on the topshelf" now will make it easier to upgrade later. Anyway, I'll keep an eye out for the next version around October and see if we can work it into an iteration around that time! Thanks again.
Sam