使用命名管道的 WCF 服务在从共享目录托管时导致阻塞线程
WCF Service using named pipes causes blocking thread when hosted from shared directory
我正在构建一个 Web 应用程序,其中包含一个带有命名管道端点的内部自托管 WCF 服务。这很好用,除非我想在 IIS 上托管此 Web 应用程序,使用共享的 UNC 虚拟路径('\server\share')结合物理路径凭据。
每当我尝试 运行 这种情况时,我都会收到错误消息:
Error: System.ServiceModel.EndpointNotFoundException: 'There was no endpoint listening at net.pipe://localhost/futurama/pid4988/instance2 that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.'
AddressAccessDeniedException: The pipe name could not be obtained for net.pipe://localhost/futurama/pid4988/instance2.
PipeException: The pipe name could not be obtained for the pipe URI: Unrecognized error 5 (0x5)
怀疑这是 credentials/rights-issue,但我不知道如何修复它。有人有想法吗?
我已经在一个示例中简化了问题,每当我启动这个示例时,线程就会阻塞,并且该进程使用了 25% 的处理器。
Global.asax 文件:
public class Global : System.Web.HttpApplication
{
public static ClientProvider<ITestService> Provider { get; set; }
protected void Application_Start(object sender, EventArgs e)
{
Provider = new ClientProvider<ITestService>(typeof(TestService));
using (var client = Provider.GetClient())
{
string result = client.Proxy.SayHello("world");
// this is never reached :(
}
}
protected void Application_End(object sender, EventArgs e)
{
Provider.Dispose();
}
}
内部服务:
[ServiceContract]
public interface ITestService
{
[OperationContract]
string SayHello(string name);
}
public class TestService : ITestService
{
public string SayHello(string name)
{
return string.Format("Hello, {0}", name);
}
}
自托管class:
public class ClientProvider<T> : IDisposable
{
protected ServiceHost ServiceHost { get; set; }
public string Address { get; protected set; } = "net.pipe://localhost/test/instance";
public ClientProvider(Type implementingType)
{
ServiceHost = new ServiceHost(implementingType);
System.ServiceModel.Channels.Binding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
ServiceHost.AddServiceEndpoint(typeof(T), binding, Address);
ServiceHost.Open();
}
internal Client<T> GetClient()
{
var client = new Client<T>(this, Address.ToString());
return client;
}
internal void Close()
{
ServiceHost.Close();
}
public void Dispose()
{
Close();
}
}
提供代理的客户端:
public class Client<T> : IDisposable
{
public T Proxy { get; protected set; }
protected ChannelFactory<T> Factory { get; set; }
protected ClientProvider<T> Provider { get; set; }
internal Client(ClientProvider<T> provider, string address)
{
Provider = provider;
System.ServiceModel.Channels.Binding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(address);
Factory = new ChannelFactory<T>(binding, endpointAddress);
Proxy = Factory.CreateChannel();
}
public void Dispose()
{
IClientChannel channel = Proxy as IClientChannel;
try { channel.Close(); }
catch { channel.Abort(); }
try { Factory.Close(); }
catch { Factory.Abort(); }
}
}
有人知道为什么带有 UNC 虚拟路径的 IIS 会搞砸吗?
最后,我们解决了这个问题 bij 设置 Impersonationcontext 以暂时撤消任何模拟:
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
if (!currentIdentity.IsSystem && currentIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation)
{
impersonationContext = WindowsIdentity.Impersonate(IntPtr.Zero); //revert to previous identity (apppool identity)
}
这似乎解决了我们的问题。
我正在构建一个 Web 应用程序,其中包含一个带有命名管道端点的内部自托管 WCF 服务。这很好用,除非我想在 IIS 上托管此 Web 应用程序,使用共享的 UNC 虚拟路径('\server\share')结合物理路径凭据。 每当我尝试 运行 这种情况时,我都会收到错误消息:
Error: System.ServiceModel.EndpointNotFoundException: 'There was no endpoint listening at net.pipe://localhost/futurama/pid4988/instance2 that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.'
AddressAccessDeniedException: The pipe name could not be obtained for net.pipe://localhost/futurama/pid4988/instance2.
PipeException: The pipe name could not be obtained for the pipe URI: Unrecognized error 5 (0x5)
怀疑这是 credentials/rights-issue,但我不知道如何修复它。有人有想法吗?
我已经在一个示例中简化了问题,每当我启动这个示例时,线程就会阻塞,并且该进程使用了 25% 的处理器。
Global.asax 文件:
public class Global : System.Web.HttpApplication
{
public static ClientProvider<ITestService> Provider { get; set; }
protected void Application_Start(object sender, EventArgs e)
{
Provider = new ClientProvider<ITestService>(typeof(TestService));
using (var client = Provider.GetClient())
{
string result = client.Proxy.SayHello("world");
// this is never reached :(
}
}
protected void Application_End(object sender, EventArgs e)
{
Provider.Dispose();
}
}
内部服务:
[ServiceContract]
public interface ITestService
{
[OperationContract]
string SayHello(string name);
}
public class TestService : ITestService
{
public string SayHello(string name)
{
return string.Format("Hello, {0}", name);
}
}
自托管class:
public class ClientProvider<T> : IDisposable
{
protected ServiceHost ServiceHost { get; set; }
public string Address { get; protected set; } = "net.pipe://localhost/test/instance";
public ClientProvider(Type implementingType)
{
ServiceHost = new ServiceHost(implementingType);
System.ServiceModel.Channels.Binding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
ServiceHost.AddServiceEndpoint(typeof(T), binding, Address);
ServiceHost.Open();
}
internal Client<T> GetClient()
{
var client = new Client<T>(this, Address.ToString());
return client;
}
internal void Close()
{
ServiceHost.Close();
}
public void Dispose()
{
Close();
}
}
提供代理的客户端:
public class Client<T> : IDisposable
{
public T Proxy { get; protected set; }
protected ChannelFactory<T> Factory { get; set; }
protected ClientProvider<T> Provider { get; set; }
internal Client(ClientProvider<T> provider, string address)
{
Provider = provider;
System.ServiceModel.Channels.Binding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
EndpointAddress endpointAddress = new EndpointAddress(address);
Factory = new ChannelFactory<T>(binding, endpointAddress);
Proxy = Factory.CreateChannel();
}
public void Dispose()
{
IClientChannel channel = Proxy as IClientChannel;
try { channel.Close(); }
catch { channel.Abort(); }
try { Factory.Close(); }
catch { Factory.Abort(); }
}
}
有人知道为什么带有 UNC 虚拟路径的 IIS 会搞砸吗?
最后,我们解决了这个问题 bij 设置 Impersonationcontext 以暂时撤消任何模拟:
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
if (!currentIdentity.IsSystem && currentIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation)
{
impersonationContext = WindowsIdentity.Impersonate(IntPtr.Zero); //revert to previous identity (apppool identity)
}
这似乎解决了我们的问题。