Friday, January 8, 2010

The "Fancy Proxy" - having fun with WCF - 2-Simple MSMQ

This article is part of The "Fancy Proxy" tutorial - implementing a few advance ideas in WCF in one solution.

This is the 2nd step - Simple MSMQ

2st step, lets implement a simple MSMQ on WCF - so we understand the basics.

We'll start with the contract, since one of MSMQs benefits is support of disconnected enviroment, the interface it implements can be only "one-way" (we'll explore this later on...).

So we'll start with the same contract (except the "two-way" method):

[ServiceContract]
public interface ISampleContract
{
//[OperationContract]
//string GetData(Guid identifier);

[OperationContract(IsOneWay=true)]
void Execute(Guid identifier);
}


Next we'll implement this interface on server side - our "bussiness logic":

public class testFancyProxyService:ISampleContract
{
public void Execute(Guid identifier)
{
Console.WriteLine"recieved Execute request (id {0})", identifier);
}
}


Next, lets host the service, this host did not change from previous step which is super-cool, specially for those who experiment MSMQ before WCF existed:

class Program
{
private static ServiceHost serviceHost = null;

static void Main(string[] args)
{
try
{
startListening();

Console.WriteLine("Server is up, press any key to stop it...");
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error: {0}\n\n Stack:{1}", ex.Message, ex.StackTrace));
Console.Read();
}
finally
{
stopListening();
}
}

private static void startListening()
{
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
serviceHost = new ServiceHost(typeof(testFancyProxyServer.testFancyProxyService));

// Open the ServiceHostBase to create listeners and start
// listening for messages.
serviceHost.Open();
}

private static void stopListening()
{
if (serviceHost != null)
{
if (serviceHost.State == CommunicationState.Opened)
{
serviceHost.Close();
}
}
}
}


Configure the server's endpoint to listen to the private "testFancyProxy" queue.

<services>
<service name="testFancyProxyServer.testFancyProxyService">
<endpoint address="net.msmq://localhost/private/testFancyProxy"
binding="netMsmqBinding" bindingConfiguration="NoMSMQSecurity"
contract="testFancyProxyContracts.ISampleContract" />
</service>
</services>
<bindings>
<netMsmqBinding>
<binding name="NoMSMQSecurity" maxReceivedMessageSize="1073741824">
<readerQuotas maxArrayLength="1073741824" />
<security>
<transport msmqAuthenticationMode="None" msmqProtectionLevel="None" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netMsmqBinding>
</bindings>


Create the queue (Computer management->Services and Applications->Message Queuing->Private Queues):





Same thing on client side - we'll code a small proxy (yes, you can instead use "add service reference" on visual studio :-)) - again, this class is exactly as in previous sample since msmq stuff are in config file only:


public class testFancyProxyProxy:ISampleContract
{
ChannelFactory channelFactory;
ISampleContract proxy;

public testFancyProxyProxy()
{
channelFactory = new ChannelFactory("msmqEndPoint");
proxy = channelFactory.CreateChannel();
}

public void Execute(Guid identifier)
{
proxy.Execute(identifier);
}
}


Configure the client and test it:

<system.serviceModel>
<client>
<endpoint address="net.msmq://localhost/private/testFancyProxy"
binding="netMsmqBinding" bindingConfiguration="NoMSMQSecurity"
contract="testFancyProxyContracts.ISampleContract"
name="msmqEndPoint"/>
</client>
<bindings>
<netMsmqBinding>
<binding name="NoMSMQSecurity" maxReceivedMessageSize="1073741824">
<readerQuotas maxArrayLength="1073741824" />
<security>
<transport msmqAuthenticationMode="None" msmqProtectionLevel="None" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netMsmqBinding>
</bindings>
</system.serviceModel>


Testing...(same as previous sample...):

public class testFancyProxyConsumer
{
private testFancyProxyClient.testFancyProxyProxy proxy;

public void Run()
{
proxy = new testFancyProxyProxy();
Guid identifier = Guid.NewGuid();
proxy.Execute(identifier);

Console.WriteLine("Message {0} sent", identifier);
}
}





That's it!! 2nd step - nice & simple..

So you may ask..."if everything is the same except the config...what do I need MSMQ for??"

Well...there are a few..async processing, managing priority etc, we'll explore the relevant benefit - disconnected enviroment.

Lets add time stamp to the messages both on client & server.

Now lets start only the client.




After a few minutes, lets start the server.




As you can see the server recieved the message altough it was down when the message was sent - isn't that cool?


Till next step...
Diego

PS: source download

6 comments:

  1. Hi I downlaoded source code.
    set server as start up project.
    created private queue with name "testFancyProxy".
    When I ran, I got the following error.
    Any Thoughts? Thanks.

    "Binding validation failed because the binding's ExactlyOnce property is set to true while the destination queue is non-transactional. The service host cannot be opened. Resolve this conflict by setting the ExactlyOnce property to false or creating a transactional queue for this binding."

    ReplyDelete
  2. Exactly as the error suggests:
    "....or creating a transactional queue for this binding"

    When you create the queue you should check the "Transactional" checkbox.

    Good luck!
    Diego

    ReplyDelete
    Replies
    1. That's not the root cause. The problem is that IIS is not respecting the 'exactlyOnce="true"' in web.config.

      Delete
    2. IIS? could be in another example, this one does not use IIS as the host of the service.
      10x for the tip though

      Delete

  3. add exactly once in false;

    ReplyDelete
  4. you have missed ( in one of the lines:
    public class testFancyProxyService:ISampleContract,
    instead of
    Console.WriteLine("recieved Execute request (id {0})", identifier);

    you have

    Console.WriteLine"recieved Execute request (id {0})", identifier);

    ReplyDelete