ServiceStack自托管应用程序重启

4
如何重新启动ServiceStack自托管AppHost?将我的AppHost实例设置为null并处置它无法正确工作,会抛出以下异常:
System.ArgumentException: An entry with the same key already exists.

我需要这样做以重新加载设置并启动AppHost,而无需重新启动托管AppHost的Windows服务。
编辑: Scott和Moo-Juice运行AppHost在不同的AppDomain中的建议是正确的解决方案。为了克服跨域调用以重启AppHost,我创建了第二个AppHost,在主AppDomain中运行,并从Scott的解决方案调用Restart方法。在两个AppHost实例上启用CORS允许一个简单的$ajax调用来重启服务并在服务启动和请求返回后重新加载页面。

我将我的服务堆栈实例托管在它们自己的AppDomain中,这使得启动/停止/删除/添加服务堆栈实例变得非常简单。 - Moo-Juice
@Moo-Juice 我其实没有想过那样做,谢谢你提醒我。 - cornelha
1个回答

5

使用AppDomain:

Moo-Juice建议使用AppDomain是正确的。我提供了一个简单的示例来说明如何使用AppDomain来隔离ServiceStack,并允许启动/重新启动/停止它。

using System;
using ServiceStack;
using System.Runtime.Remoting;

namespace Test
{
    public class ServiceStackConsoleHost : MarshalByRefObject
    {
        public static void Main()
        {
            Start();
        }

        static ObjectHandle Handle;
        static AppDomain ServiceStackAppDomain;

        public static void Start()
        {
            // Get the assembly of our host
            var assemblyName = typeof(ServiceStackConsoleHost).Assembly.FullName;

            // Create an AppDomain
            ServiceStackAppDomain = AppDomain.CreateDomain("ServiceStackAppDomain");

            // Load in our service assembly
            ServiceStackAppDomain.Load(assemblyName);

            // Create instance of our ServiceStack application
            Handle = ServiceStackAppDomain.CreateInstance(assemblyName, "Test.ServiceStackConsoleHost");

            // Show that the main application is in a separate AppDomain
            Console.WriteLine("Main Application is running in AppDomain '{0}'", AppDomain.CurrentDomain.FriendlyName);

            // Wait for input
            Console.ReadLine();

            // Restart the application
            Restart();
        }

        public static void Stop()
        {
            if(ServiceStackAppDomain == null)
                return;

            // Notify ServiceStack that the AppDomain is going to be unloaded
            var host = (ServiceStackConsoleHost)Handle.Unwrap();
            host.Shutdown();

            // Shutdown the ServiceStack application
            AppDomain.Unload(ServiceStackAppDomain);

            ServiceStackAppDomain = null;
        }

        public static void Restart()
        {
            Stop();
            Console.WriteLine("Restarting ...");
            Start();

        }

        readonly AppHost appHost;

        public ServiceStackConsoleHost()
        {
            appHost = new AppHost();
            appHost.Init();
            appHost.Start("http://*:8090/");
            Console.WriteLine("ServiceStack is running in AppDomain '{0}'", AppDomain.CurrentDomain.FriendlyName);
        }

        public void Shutdown()
        {
            if(appHost != null)
            {
                Console.WriteLine("Shutting down ServiceStack host");
                if(appHost.HasStarted)
                    appHost.Stop();
                appHost.Dispose();
            }
        }
    }

    public class AppHost : AppSelfHostBase
    {
        public AppHost(): base("My ServiceStack Service", typeof(AppHost).Assembly)
        {
        }

        public override void Configure(Funq.Container container)
        {
        }
    }
}

Screenshot

关于如何使用AppDomain的说明可以在这里找到(链接)


1
+1,我的代码不同,但是哲学基本相同 :) - Moo-Juice
这正好符合我的需求,我构建了一个小的测试项目,效果非常好。现在我只需要解决一些反射问题。非常感谢。 - cornelha
@Scott 我已经实现了你的建议,当我从控制台应用程序中调用该方法时,它运行得很好,但是当我从ServiceStack服务类中调用该方法时,我仍然会遇到之前关于端口已被注册的异常。有什么想法吗? - cornelha
@cornelha,这是因为如果您从ServiceStack服务中调用它,那么您就在ServiceStack应用程序域内。因此,您没有关闭它。您需要让您的ServiceStack服务通知控制台应用程序,该服务需要关闭/重新启动并终止实例,因为它超出了AppDomain。那里开始变得棘手。 - Scott
1
@Scott,我找到了一个很好的解决方案,感谢您的帮助。 - cornelha
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接