Extended ServiceHost class not getting Description object initialized
-
2008年3月4日 16:53I'm having a small problem, should be simple but I cant seemt o figure it out.
My console host:
Code Snippetclass Program {
static void Main(string[] args) {
using (ServiceHost<QueueManager> host = new ServiceHost<QueueManager>()) {
host.Open();
Console.ReadKey();
host.Close();
}
//using (ServiceHost host = new ServiceHost(typeof(QueueManager))) {
// host.Open();
// Console.ReadKey();
// host.Close();
//}
}
}
My derived class:
Code Snippetclass ServiceHost<T> : ServiceHost
{
protected override void OnOpening()
{
foreach (ServiceEndpoint p in Description.Endpoints) {
//check and create the queue mentioned in the endpoints if type msmq binding
QueuedServiceHelper.VerifyQueue(p);
}
base.OnOpening();
}
}
I get an invalidoperation exception when I open the host
after debugging I found that in the ServiceHost<T> class in the OnOpening implementation the Description object is null and does not get populated from the base ServiceHost
although if I create and host the base ServiceHost object directly, it works without any issues. Any suggestions ?
my config section is below is below:
Code Snippet<system.serviceModel>
<services>
<service name="xxx.QueueManager" behaviorConfiguration="xxx.QueueManagerBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/QueueManager/service"/>
</baseAddresses>
</host>
<!-- Service Endpoints -->
<endpoint address="" binding="wsHttpBinding" contract="xxx.IQueueManager">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="xxx.QueueManagerBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netMsmqBinding>
<binding name="noMSMQSecurity">
<security mode="None" />
</binding>
</netMsmqBinding>
</bindings>
</system.serviceModel>
全部回复
-
2008年3月4日 17:18版主This error is probably occuring in the Open() method. YOu should not be using a "using" statement here because of how the Dispose method is implemented. See this blog post for a full explaination and recommentations about what you should do:
http://www.danrigsby.com/blog/index.php/2008/02/26/dont-wrap-wcf-service-hosts-or-clients-in-a-using-statement/.
Have you looked at the stack trace for that exception or looked at the call stack? I bet under the invalidoperation you will find some other exception, quite possibly an exception that derives from CommunicationException, and could be about not being able to setup the channels correctly from the Open() method. In the OnOpening method, the endpoints probably arent set yet. -
2008年3月4日 17:23版主You probalby want to override the OnOpened method if you want to look at the endpoints after they have been added from the app.config file. OnOpening would occur right before it does the work of Open(), while OnOpened occurs after all of the work from Open().
-
2008年3月5日 7:55Thanks Dan,
Good blog post on not to use the using statement, I tried your suggestion of overriding the OnOpened method instead. But I'm getting the same InvalidOperationException, there is no inner exception with it.
my stack trace with the OnOpened implamentation:
at System.ServiceModel.ServiceHostBase.InitializeRuntime()
at System.ServiceModel.ServiceHostBase.OnOpen(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
at TestHost.Program.Main(String[] args) in D:\Projects\VTLS\Main\Source\VTLS\Source\Upload\WebClient\QueueManagerHost\TestHost.cs:line 19
stack trace with OnOpening implementation:
at Services.QueueManagerHost.ServiceHost`1.OnOpening() in D:\Projects\VTLS\Main\Source\VTLS\Source\Upload\WebClient\QueueManagerHost\GenericServiceHost.cs:line 14
at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
at System.ServiceModel.Channels.CommunicationObject.Open()
at TestHost.Program.Main(String[] args) in D:\Projects\VTLS\Main\Source\VTLS\Source\Upload\WebClient\QueueManagerHost\TestHost.cs:line 19
my implementation is based on the book :
Programming WCF Services By Juval Lowy ............................................... Publisher: O'Reilly Pub Date: February 20, 2007 ISBN-10: 0-596-52699-7 ISBN-13: 978-0-596-52699-3
section 9.2 "Queued Calls"
please note that it seems to work fine if I implement the base ServiceHost, It sems like a good pattern, but it doesnt work... , although it should. weird
following is my complete implementation of the code:
Code Snippetclass ServiceHost<T> : ServiceHost {
protected override void OnOpening() {
foreach (ServiceEndpoint p in Description.Endpoints) {
//check and create the queue mentioned in the endpoints if type msmq binding
QueuedServiceHelper.VerifyQueue(p);
}
base.OnOpened();
}
protected override void OnClosing() {
PurgeQueues();
base.OnClosing();
}
[Conditional("DEBUG")]
private void PurgeQueues() {
foreach (ServiceEndpoint p in Description.Endpoints) {
QueuedServiceHelper.PurgeQueue(p);
}
}
}
public static class QueuedServiceHelper {
public static void VerifyQueue(ServiceEndpoint endpoint) {
if (endpoint.Binding is NetMsmqBinding) {
string queue = GetQueueFromUri(endpoint.Address.Uri);
if (MessageQueue.Exists(queue) == false) {
MessageQueue.Create(queue, true);
}
}
}
public static void VerifyQueue<T>(string endpointName) where T : class {
ChannelFactory<T> factory = new ChannelFactory<T>(endpointName);
VerifyQueue(factory.Endpoint);
}
public static void VerifyQueue<T>() where T : class {
VerifyQueue<T>("");
}
//Parses the queue name out of the address
static string GetQueueFromUri(Uri uri) {
string[] pathFragments = uri.Segments;
//return the last uri segment, it would be the queue name
return pathFragments[pathFragments.Length - 1];
}
//purge the queue while in debug , otherwise it makes debugging difficult
public static void PurgeQueue(ServiceEndpoint endpoint) {
if (endpoint.Binding is NetMsmqBinding) {
string queueName = GetQueueFromUri(endpoint.Address.Uri);
if (MessageQueue.Exists(queueName) == true) {
MessageQueue queue = new MessageQueue(queueName);
queue.Purge();
}
}
}
} -
2012年3月16日 19:02
Sorry to reply to an old thread, but I ran into the exact same problem today. A search pulled up this thread, so I thought to post a solution for anyone else finding their way here. The problem is that you are not calling the base class's constructor. Add the following code:
public class ServiceHost<T> : ServiceHost { public ServiceHost() : base(typeof(T)) { } ... }
- 已建议为答案 EasySR20 2012年3月16日 19:05

