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

dow*_*tch 16 configuration wcf autostart application-pool iis-7.5

为了从头开始测试IIS/WCF实现的许多令人头疼的问题,我构建了HelloWorld服务,客户端(非常好)在这里进行了操作.我为net.tcp添加了端点,并且该服务IIS 7.5在其自己的ApplicationPool名为HW的(在Windows 7上)下的两个绑定端到端地正常工作.

我正在努力工作的是宣布的AutoStart和Preload(或"pre-warm caching")功能.我已经按照这里这里列出的指示(非常相似,但总是很好地得到第二个意见)非常密切.这意味着我

1)设置应用程序池startMode...

<applicationPools> 
     <!-- ... -->
     <add name="HW" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" /> 
</applicationPools>
Run Code Online (Sandbox Code Playgroud)

2)...启用serviceAutoStart并设置指向我的指针serviceAutoStartProvider

<site name="HW" id="2">
    <application path="/" applicationPool="HW" serviceAutoStartEnabled="true" serviceAutoStartProvider="PreWarmMyCache" />
    <!-- ... -->
</site>
Run Code Online (Sandbox Code Playgroud)

3)...并且命名为所述提供者,以及GetType().AssemblyQualifiedName下面全部列出的类

<serviceAutoStartProviders> 
    <add name="PreWarmMyCache" type="MyWCFServices.Preloader, HelloWorldServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
</serviceAutoStartProviders>
Run Code Online (Sandbox Code Playgroud)
using System;

namespace MyWCFServices
{
    public class Preloader : System.Web.Hosting.IProcessHostPreloadClient
    {
        public void Preload(string[] parameters)
        {
            System.IO.StreamWriter sw = new System.IO.StreamWriter(@"C:\temp\PreloadTest.txt");
            sw.WriteLine("Preload executed {0:G}", DateTime.Now);
            sw.Close();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

唉,所有这些手动配置,加上几个iisreset电话,我一无所获.w3wp.exe任务管理器中没有进程启动(虽然如果我启动HelloWorldClient就得到它),没有文本文件,最重要的是,没有满足感.

关于这个功能的讨论数量令人沮丧,无论是在SO还是更广泛的网络上,这里几个类似的问题很少得到关注,所有这些问题都会响起一两个警钟.也许是不必要的 - 那些曾经在这条路上停留过一段时间或两次关心的专家会不会发出声音?(很高兴提供整个解决方案,如果你可以建议一个好的地方来举办它.)


编辑:我尝试将Preload方法中的路径重置为相对App_Data文件夹(另一个SO答案建议),没关系.此外,我w3wp.exe通过简单的浏览到本地主机来了解该过程.该过程消耗了令人印象深刻的17MB内存来提供其单个微小的OperationContract,而价格提供零预载值.17MB的ColdDeadCache.

mth*_*rba 4

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

  1. 使用Windows Server AppFabric进行服务自动启动
  2. 使用WCF基础设施执行自定义启动代码

回复 1:Appfabric AutoStart 功能应该开箱即用(如果您不使用 MVC 的 ServiceRoute 来注册您的服务,则必须在 Web.configserviceActivations部分或使用物理*.svc文件指定它们。

回复 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
    }
}
Run Code Online (Sandbox Code Playgroud)

..可以这样使用:

public static class ServiceActivation
{
    public static void OnServiceActivated()
    {
        // Your startup code here
    }
}

[ServiceActivator(typeof(ServiceActivation), "OnServiceActivated")]
public class YourService : IYourServiceContract
{

}
Run Code Online (Sandbox Code Playgroud)

这正是我们长期以来在大量服务上使用的方法。使用 WCFServiceBehavior进行自定义启动代码(而不是依赖 IIS 基础结构)的额外好处是它可以在任何托管环境(包括自托管)中工作,并且可以更轻松地进行测试。