自动启动/预热功能在IIS 7.5/WCF服务中不起作用

自动启动/预热功能在IIS 7.5/WCF服务中不起作用,wcf,configuration,iis-7.5,application-pool,autostart,Wcf,Configuration,Iis 7.5,Application Pool,Autostart,为了从头开始测试IIS/WCF实现中的许多令人头痛的问题,我构建了HelloWorld服务,客户机也进行了演练(非常好)。我为net.tcp添加了端点,并且该服务在其自己的名为HW的应用程序池中的IIS 7.5(在Windows 7上)下的两个绑定端到端正常工作 我正在努力实现的是宣布的AutoStart和Preload(或“预热缓存”)功能。我已经非常仔细地遵循了列出的说明(彼此非常相似,但有第二个意见总是很好的)。也就是说我 1) 设置应用程序池startMode <applicati

为了从头开始测试IIS/WCF实现中的许多令人头痛的问题,我构建了HelloWorld服务,客户机也进行了演练(非常好)。我为net.tcp添加了端点,并且该服务在其自己的名为HW的
应用程序池中的
IIS 7.5(在Windows 7上)下的两个绑定端到端正常工作

我正在努力实现的是宣布的AutoStart和Preload(或“预热缓存”)功能。我已经非常仔细地遵循了列出的说明(彼此非常相似,但有第二个意见总是很好的)。也就是说我

1) 设置应用程序池
startMode

<applicationPools> 
     <!-- ... -->
     <add name="HW" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" /> 
</applicationPools>
3) …并命名为所述提供者,下面完整列出了类的
GetType().AssemblyQualifiedName

<serviceAutoStartProviders> 
    <add name="PreWarmMyCache" type="MyWCFServices.Preloader, HelloWorldServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
</serviceAutoStartProviders>
唉,所有这些手动配置,加上几个
iisreset
调用,我什么也得不到。没有
w3wp.exe
进程在任务管理器中启动(尽管我在启动HelloWorldClient时得到它),没有文本文件,最重要的是,没有满足感

令人沮丧的是,无论是在SO还是在更广泛的网络上,关于该功能的讨论都很少,这里的几个类似问题几乎没有得到关注,所有这些都敲响了警钟。也许是不必要的——有没有哪位专家在这条路上走过一两段时间,愿意插话?(如果您能建议一个好的托管地点,我们很乐意提供整个解决方案。)



EDIT:我尝试在
Preload
方法中将该路径重置为相对的
App\u Data
文件夹(另一个SO答案表明),这无关紧要。此外,我还通过简单的本地主机浏览了解了
w3wp.exe
进程。这个过程消耗了令人印象深刻的17MB内存来完成它的一个微小的操作契约,同时提供零预加载值的价格。17MB的ColdDeadCache。

对于您的问题,这是一种稍微不同的方法:

  • 用于服务自动启动
  • 使用WCF基础结构执行自定义启动代码
  • Re 1:应该是开箱即用的(如果您没有使用MVC的ServiceRoute来注册您的服务,则必须在Web.config的
    serviceActivations
    部分或使用物理
    *.svc
    文件中指定它们

    Re 2:要将自定义启动代码注入WCF管道,可以使用如下属性:

    using System;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    
    namespace WCF.Extensions
    {
        /// <summary>
        /// Allows to specify a static activation method to be called one the ServiceHost for this service has been opened.
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
        public class ServiceActivatorAttribute : Attribute, IServiceBehavior
        {
            /// <summary>
            /// Initializes a new instance of the ServiceActivatorAttribute class.
            /// </summary>
            public ServiceActivatorAttribute(Type activatorType, string methodToCall)
            {
                if (activatorType == null) throw new ArgumentNullException("activatorType");
                if (String.IsNullOrEmpty(methodToCall)) throw new ArgumentNullException("methodToCall");
    
                ActivatorType = activatorType;
                MethodToCall = methodToCall;
            }
    
            /// <summary>
            /// The class containing the activation method.
            /// </summary>
            public Type ActivatorType { get; private set; }
    
            /// <summary>
            /// The name of the activation method. Must be 'public static void' and with no parameters.
            /// </summary>
            public string MethodToCall { get; private set; }
    
    
            private System.Reflection.MethodInfo activationMethod;
    
            #region IServiceBehavior
            void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
            {
            }
    
            void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                serviceHostBase.Opened += (sender, e) =>
                    {
                        this.activationMethod.Invoke(null, null);
                    };
            }
    
            void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                // Validation: can get method
                var method = ActivatorType.GetMethod(name: MethodToCall,
                                 bindingAttr: System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public,
                                 callConvention: System.Reflection.CallingConventions.Standard,
                                 types: Type.EmptyTypes,
                                 binder: null,
                                 modifiers: null);
                if (method == null)
                    throw new ServiceActivationException("The specified activation method does not exist or does not have a valid signature (must be public static).");
    
                this.activationMethod = method;
            }
            #endregion
        }
    }
    
    public static class ServiceActivation
    {
        public static void OnServiceActivated()
        {
            // Your startup code here
        }
    }
    
    [ServiceActivator(typeof(ServiceActivation), "OnServiceActivated")]
    public class YourService : IYourServiceContract
    {
    
    }
    

    这正是我们在大量服务上使用了相当长一段时间的方法。使用WCF
    ServiceBehavior
    定制启动代码(而不是依赖IIS基础设施)的额外好处是,它可以在任何托管环境中工作(包括自托管)而且更容易测试。

    我也这么做了。它很有效

    在预加载方法,我有一些代码从一个很好的白皮书复制可用

    预加载方法看起来像

     public void Preload(string[] parameters) 
     {     
            bool isServceActivated = false; 
            int attempts = 0; 
            while (!isServceActivated && (attempts <10)) 
            {
                Thread.Sleep(1 * 1000);
                try
                {
                    string virtualPath = "/Test1/Service1.svc";
                    ServiceHostingEnvironment.EnsureServiceAvailable(virtualPath);
                    isServceActivated = true;
                }
                catch (Exception exception)
                {
                    attempts++;
                    //continue on these exceptions, otherwise fail fast 
                    if (exception is EndpointNotFoundException ||
                        exception is ServiceActivationException || 
                        exception is ArgumentException) 
                    {
                        //log 
                    }
                    else
                    {
                        throw;
                    }
                }
            }
       }
    
    public void预加载(字符串[]参数)
    {     
    bool isServceActivated=假;
    int=0;
    
    虽然(!isServceActivated&&(尝试我知道这听起来很荒谬,但我遇到了同样的问题(w3wp.exe在进行配置更改后不会自动启动),这是因为我在编辑applicationHost.config文件时没有在管理模式下运行文本编辑器。我犯了一个愚蠢的错误


    在我的辩护中,我使用了记事本+,记事本告诉我它正在保存,而实际上它没有保存。

    也许你是在64位系统上?Windows中有一个已知的错误,保存会被重定向到32位文件夹,因此不会进行任何更改


    (我已经将我的答案转换为一个答案,因为答案可能更容易找到)

    有趣的是,我们已经朝着AppFabric的方向前进了,所以这是一个很好的衔接。我喜欢你的代码,即使没有经过测试,也可以看到它想要去哪里。Bounty是你的,但如果我在评论中有更多问题,你必须跟上;)@ServiceGuy我只是想澄清你的两点是相互依赖的,(即使用AppFabric并向WCF基础设施添加一个钩子)。换句话说,第2点并不能解决AutoStart IIS托管上下文中的问题。对吗?@小册子:是的,1和2是必要的,(1)实际自动启动你的服务,(2)执行自定义OnStart逻辑。也许您是在64位系统上?有一个已知的“功能”可以将存储重定向到32位文件夹:-)天哪,我刚刚因为同样的事情浪费了半天的时间。对您的支持:-)@康斯坦丁……事实上,这应该是正确的答案。这太糟糕了。谢谢你的提示,救了我一天。这帮助我解决了问题。谢谢克里斯。事件日志中有任何线索吗?抛出的任何异常都应该显示在那里。不,没有。不确定你为什么会期望异常,如果(如上所述)该服务运行良好。您可以检查以下几点:-站点2的id是否正确?-站点和应用程序池的名称是否相同?-您指定的属性比示例中的属性多,仅指定示例中的属性是否会有所不同?
    public static class ServiceActivation
    {
        public static void OnServiceActivated()
        {
            // Your startup code here
        }
    }
    
    [ServiceActivator(typeof(ServiceActivation), "OnServiceActivated")]
    public class YourService : IYourServiceContract
    {
    
    }
    
     public void Preload(string[] parameters) 
     {     
            bool isServceActivated = false; 
            int attempts = 0; 
            while (!isServceActivated && (attempts <10)) 
            {
                Thread.Sleep(1 * 1000);
                try
                {
                    string virtualPath = "/Test1/Service1.svc";
                    ServiceHostingEnvironment.EnsureServiceAvailable(virtualPath);
                    isServceActivated = true;
                }
                catch (Exception exception)
                {
                    attempts++;
                    //continue on these exceptions, otherwise fail fast 
                    if (exception is EndpointNotFoundException ||
                        exception is ServiceActivationException || 
                        exception is ArgumentException) 
                    {
                        //log 
                    }
                    else
                    {
                        throw;
                    }
                }
            }
       }