为了从头开始测试IIS / WCF实现的许多麻烦,我构建了HelloWorld服务和客户端(非常好)here。我为net.tcp添加了端点,并且该服务在IIS 7.5
(在Windows 7上)的ApplicationPool
名为HW的<{1}}下进行端到端的正常工作。
我正在努力工作的是宣布的AutoStart和Preload(或“pre-warm caching”)功能。我已经按照here和here的指示(非常相似,但总是很好地得到第二个意见)非常密切。这意味着我
1)设置应用程序池startMode
...
<applicationPools>
<!-- ... -->
<add name="HW" managedRuntimeVersion="v4.0" startMode="AlwaysRunning" />
</applicationPools>
2)...已启用serviceAutoStart
并设置指向我的serviceAutoStartProvider
<site name="HW" id="2">
<application path="/" applicationPool="HW" serviceAutoStartEnabled="true" serviceAutoStartProvider="PreWarmMyCache" />
<!-- ... -->
</site>
3)...并命名为所述提供者,其中GetType().AssemblyQualifiedName
类完整列在下面
<serviceAutoStartProviders>
<add name="PreWarmMyCache" type="MyWCFServices.Preloader, HelloWorldServer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</serviceAutoStartProviders>
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();
}
}
}
唉,所有这些手动配置,加上几个iisreset
电话,我什么都没得到。在任务管理器中没有w3wp.exe
进程启动(虽然如果我启动HelloWorldClient,我会得到它),没有文本文件,最重要的是,没有满足感。
关于此功能的讨论数量令人沮丧,无论是在SO还是更广泛的网络上,这里几个类似的问题很少受到关注,所有这些问题都响起了一两声响亮。也许是不必要的 - 那些曾经在这条路上停留过一段时间或两次关心的专家会不会发出声音? (很高兴提供整个解决方案,如果你可以建议一个好的地方来举办它。)
编辑:我尝试将Preload
方法中的路径重置为相对App_Data
文件夹(另一个SO答案建议),无关紧要。此外,我通过简单的浏览到本地主机来了解w3wp.exe
进程。该过程消耗了令人印象深刻的17MB内存来提供其单个微小的OperationContract,而价格提供零预载值。 17MB的ColdDeadCache。
答案 0 :(得分:4)
对于您的问题,这是一种稍微不同的方法:
Re 1:Appfabric AutoStart feature应该只是开箱即用(如果你没有使用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基础结构)的额外好处是,它可以在任何托管环境中工作(包括自托管),并且可以更容易地进行测试。
答案 1 :(得分:3)
我知道这听起来很荒谬,但我遇到了同样的问题(w3wp.exe在配置更改后没有自动触发),这是因为我在编辑applicationHost.config时没有在管理模式下运行文本编辑器文件。我这个愚蠢的错误。
在我的辩护中,我使用的是Notepad ++,它告诉我它实际上并没有保存。
答案 2 :(得分:1)
我做了同样的事情。它有效...
在预加载方法中,我从一张漂亮的白皮书here中复制了一些代码!
预加载方法看起来像......
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;
}
}
}
}
答案 3 :(得分:1)