问题
I have a windows service that reads my message queue through WCF. I want the service to process one message before another message (intensive memory actions per msg). I set the throttling configuration to 1, but it does not seem to do anything. If i have 6 messages in my queue, it takes 4 right after the start.
Am i missing something?
My web.config :
<system.serviceModel>
<client>
<endpoint
address="net.tcp://spserv30:9999/services/SPInterface"
binding="netTcpBinding" bindingConfiguration="tcpspbinding"
contract="Itineris.OPM.WCFSP.ActionContracts.ISPActions" >
</endpoint>
</client>
<services>
<service name="Itineris.OPM.MSMQProcessorV2.MSMQProcessor" behaviorConfiguration="Throttled" >
<endpoint address="msmq.formatname:DIRECT=OS:localhost\private$\documents" binding="msmqIntegrationBinding"
bindingConfiguration="MSMQProcessorBinding" contract="Itineris.OPM.MSMQProcessorV2.IMSMQProcessor" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="tcpspbinding" transferMode="StreamedRequest" />
</netTcpBinding>
<msmqIntegrationBinding>
<binding name="MSMQProcessorBinding" maxReceivedMessageSize="2147483647"
receiveRetryCount="0" retryCycleDelay="00:10:00" maxRetryCycles="0"
receiveErrorHandling="Move">
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Throttled">
<serviceThrottling
maxConcurrentCalls="1"
maxConcurrentSessions="1"
maxConcurrentInstances="1"
/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
My servicehost creation :
protected override void OnStart(string[] args)
{
if (_serviceHost != null)
{
if (_serviceHost.State != CommunicationState.Faulted)
_serviceHost.Close();
else
_serviceHost.Abort();
}
//create servicehost
_serviceHost = new ServiceHost(typeof(MSMQProcessor));
_serviceHost.Open();
_serviceHost.Faulted += serviceHost_Faulted;
// Already load configuration here so that service does not start if there is a configuration error.
new DocumentGeneratorV2.LoadGeneratorConfigurator().Load();
var startLog = new LogEntry {Message = "Itineris MSMQ Processor Service V2 has started"};
startLog.Categories.Add(CategoryGeneral);
startLog.Priority = PriorityNormal;
Logger.Write(startLog);
}
private void serviceHost_Faulted(object sender, EventArgs e)
{
if (!_isClosing)
{
_serviceHost.Abort();
_serviceHost = new ServiceHost(typeof(MSMQProcessor));
_serviceHost.Faulted += serviceHost_Faulted;
_serviceHost.Open();
}
}
Class with contract :
[ServiceContract(Namespace = "http://Itineris.DocxGenerator.MSMQProcessor")]
[ServiceKnownType(typeof(string))]
public interface IMSMQProcessor
{
[OperationContract(IsOneWay = true, Action = "*")]
void GenerateWordDocument(MsmqMessage<string> message);
}
public class MSMQProcessor : IMSMQProcessor
{
/// <summary>
/// Method that processed the message and generates a word document
/// </summary>
/// <param name="message">message from MSMQ to be processed</param>
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void GenerateWordDocument(MsmqMessage<string> message)
{
DocumentGeneration documentGenerator = null;
var state = new DocumentStatus();
var docGenerator = new DocumentGenerator(new LoadGeneratorConfigurator().Load());
var deserializer = new XmlSerializer(typeof(DocumentGeneration));
documentGenerator = deserializer.Deserialize(new StringReader(message.Body)) as DocumentGeneration;
if(documentGenerator == null)
throw new Exception("Deserializing of the message has failed");
docGenerator.MailQueue = appSettings["MAILQUEUE"];
docGenerator.GenerateDocument(documentGenerator);
var builder = new StringBuilder();
builder.Append("The documents have been saved to the following locations: \r\n");
}
}
回答1:
Your service as configured in the question should only process message at a time. Although you are not using the ServiceBehavior attribute for the service implementation class, the default value for the ConcurrencyMode is Single not Multiple (which could cause the behavior you are seeing). The default value of InstanceContextMode is Per Session but the maxConcurrentInstances and maxConcurrentSessions values force support for a single session at a time.
The only other option that I see is to force the ServiceHost to use only one service instance by using a different constructor. Here is the code:
// ... snipped ...
//force single service instance to be used by servicehost
var singleton = new MSMQProcessor();
_serviceHost = new ServiceHost(singleton);
_serviceHost.Open();
// ... snipped ...
来源:https://stackoverflow.com/questions/6112754/msmq-wcf-throttling