Channels ▼
RSS

.NET

Working with Protobuf WCF Services


Implementing the Service Contract

Now, let's authenticate a user, based on the supplied credentials. I use one operation contract, called AuthenticateUser, that accepts an instance of AuthenticateUserRequest class and returns an instance of AuthenticateUserResponse.

[ServiceContract,ProtoBuf.ProtoContract]
    public interface ISecurity
    {
        /// <summary>
        /// AuthenticateUser operation contract
        /// </summary>
        /// <param name="userRequestObj">userRequestObj as an instance of AuthenticateUserRequest</param>
        /// <returns>An instance of AuthenticateUserResponse</returns>
        [OperationContract]
        AuthenticateUserResponse AuthenticateUser(AuthenticateUserRequest userRequestObj);
    }

And here's the complete implementation of the AuthenticateUser operation contract:

/// <summary>
        /// Opearion contract AuthenticateUser to authenticate an user
        /// </summary>
        /// <param name="userRequestObj">userRequestObj as an instance of AuthenticateUserRequest</param>
        /// <returns>An instance of AuthenticateUserResponse</returns>
        public AuthenticateUserResponse AuthenticateUser(AuthenticateUserRequest userRequestObj)
        {
            AuthenticateUserResponse responseObj = new AuthenticateUserResponse();

            if ((userRequestObj.UserID == 1) && (userRequestObj.Password == "Joydip1@3"))
            {
                responseObj.StatusCode = 1;
                responseObj.StatusMessage = "Success";
                responseObj.IsAuthenticated = true;
            }
            else
            {
                responseObj.StatusCode = 2;
                responseObj.StatusMessage = "Not authenticated";
                responseObj.IsAuthenticated = false;
            }

            return responseObj;
        }

Specifying Binding Information

To consume the WCF protobuf-net service, I need to specify protoEndpointBehavior as shown below:

<client>
      <endpoint
                    address=""
                    binding="wsHttpBinding"
                    contract="DDJ.Services.ISecurity"
                    behaviorConfiguration="protoEndpointBehavior">
        <identity>
          <dns value="localhost"/>
        </identity>      
      </endpoint>
    </client>
    
    <extensions>
      <behaviorExtensions>
        <add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.480, Culture=neutral, PublicKeyToken=257b51d87d2e4d67"/>
      </behaviorExtensions>
    </extensions>

Here's the complete binding information to specify in tje configuration file to ensure that the WCF service uses Protobuf technology.

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="protoEndpointBehavior">
          <!--<protobuf/>-->
        </behavior>
      </endpointBehaviors>
      
      <serviceBehaviors>
        <behavior name="DDJ.SecurityServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>   
      </serviceBehaviors>     
    </behaviors>

    <services>
      <service name="DDJ.Services.Security" behaviorConfiguration="DDJ.SecurityServiceBehavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="wsHttpBinding" contract="DDJ.Services.ISecurity" behaviorConfiguration="protoEndpointBehavior">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <client>
      <endpoint
                    address=""
                    binding="wsHttpBinding"
                    contract="DDJ.Services.ISecurity"
                    behaviorConfiguration="protoEndpointBehavior">
        <identity>
          <dns value="localhost"/>
        </identity>      
      </endpoint>
    </client>
    
    <extensions>
      <behaviorExtensions>
        <add name="protobuf" type="ProtoBuf.ServiceModel.ProtoBehaviorExtension, protobuf-net, Version=2.0.0.480, Culture=neutral, PublicKeyToken=257b51d87d2e4d67"/>
      </behaviorExtensions>
    </extensions>
    
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
</configuration>

Consuming the WCF Service

To consume the service, I need to create a WCF service client and include the service reference; much the same way you include service references for any other WCF service. Follow these simple steps:

  • In the Solution Explorer, select Add | New Project
  • Select an ASP.NET Empty Web application from the list of the project templates
  • Save this Web project with a name
  • Add a WebForm to this project and save it with a name

The AuthenticateUser operation contract validates the user's credentials and returns an instance of the AuthenticateUserResponse class. Note the use of the StatusCode, StatusMessage, and IsAuthenticate properties.

The following method illustrates how the Protobuf service we created earlier can be called.

private void ExecuteWCFProtobufService()
        {
            SecurityServiceReference.SecurityClient proxy = new SecurityServiceReference.SecurityClient();
            SecurityServiceReference.AuthenticateUserRequest requestObj = new SecurityServiceReference.AuthenticateUserRequest();
            SecurityServiceReference.AuthenticateUserResponse responseObj = new SecurityServiceReference.AuthenticateUserResponse();

            requestObj.UserID = 1;
            requestObj.Password = "Joydip1@3";

            DateTime startTime = DateTime.Now;

            for (Int32 x = 0; x < 1000; x++)
            {
                responseObj = proxy.AuthenticateUser(requestObj);
            }

            DateTime endTime = DateTime.Now;
            TimeSpan difference = endTime - startTime;
            int millisceonds = (int)difference.TotalMilliseconds;

            Response.Write("<BR><BR>Status: " + responseObj.StatusMessage + " ---  Time elasped (WCF Protobuf Service Call): " + millisceonds.ToString() + "  milliseconds...");
        }

The following method calls the other WCF service, which doesn't use Protobuf technology.

private void ExecuteWCFService()
        {
            TestServiceReference.SecurityClient proxy = new TestServiceReference.SecurityClient();
            TestServiceReference.AuthenticateUserRequest requestObj = new TestServiceReference.AuthenticateUserRequest();
            TestServiceReference.AuthenticateUserResponse responseObj = new TestServiceReference.AuthenticateUserResponse();

            requestObj.UserID = 1;
            requestObj.Password = "Joydip1@3";

            DateTime startTime = DateTime.Now;

            for (Int32 x = 0; x < 1000; x++)
            {
                responseObj = proxy.AuthenticateUser(requestObj);
            }

            DateTime endTime = DateTime.Now;
            TimeSpan difference = endTime - startTime;
            int millisceonds = (int)difference.TotalMilliseconds;

            Response.Write("<BR>Status: "+ responseObj.StatusMessage + " ---  Time elasped (WCF Service Call): " + millisceonds.ToString() + "  milliseconds...");
        }

If you run both options, you'll find that the Protobuf implementation is consistently faster. In this example, it'll be just a few percent, but in other applications the difference can be an order of magnitude faster. The Protobuf performance page for this project shows the speed benefits for a variety of data loads compared with non-Protobuf solutions. In general, Protobuf exceeds the performance of all non-Protobuf alternatives. And it does so portably with an easily coded interface.

Conclusion

Because of its advantages, Protobuf is quickly becoming the technology of choice as a serialization format in REST-based WCF services. In other words, Protocol Buffers are a great way of encoding structured data in an extensible format for rapid communication.

References

http://code.google.com/p/protobuf-net/

https://code.google.com/p/protobuf/

http://en.wikipedia.org/wiki/Protocol_Buffers

https://code.google.com/p/protobuf-csharp-port/

https://code.google.com/p/protobuf-csharp-port/wiki/GettingStarted


Joydip Kanjilal is an occasional contributor to Dr. Dobb's on Microsoft technologies.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video