Search
« Proxy Data Provider with WCF – Client | Main | Proxy Data Provider with WCF – Contract »
Sunday
Aug022009

Proxy Data Provider with WCF – Service

This article is a continuation of a longer tutorial. If you haven’t done so already you should read it from the beginning.

Service

With the architecture and contract in place we are finally ready to build the service. For the most part WCF makes implementing the service extremely easy. We simply implement the IWcfDataProvider interface and have the various methods return the results generated by the underlying ADO.Net objects.

Base Class Definition

   10 public class WcfDataProviderService : IWcfDataProvider

   11     {

   12         private Dictionary<string, IDbConnection> _connections;

   13         private Dictionary<string, IDbCommand> _commands;

   14         private Dictionary<string, string> _commandConnections;

   15         private Dictionary<string, IDbDataParameter> _parameters;

   16         private Dictionary<string, IDataReader> _readers;

   17 

   18         public WcfDataProviderService()

   19         {

   20             _connections = new Dictionary<string, IDbConnection>();

   21             _commands = new Dictionary<string, IDbCommand>();

   22             _commandConnections = new Dictionary<string, string>();

   23             _parameters = new Dictionary<string, IDbDataParameter>();

   24             _readers = new Dictionary<string, IDataReader>();

   25         }

   26 

   27         private string GetToken()

   28         {

   29             return System.Guid.NewGuid().ToString("B");

   30         }

 

The class is quite simple. There is very little to the class other than the methods it has to implement as part of the contract. There are 5 dictionaries which are used to store the underlying ADO.Net objects. The key foe these dictionaries are the Tokens as discussed in the Contract section. Whenever one of the Contract methods is called the token passed in to the method is used to retrieve the underlying object.

There is also a GetToken method which simply returns a new GUID.

Hosting

For this service to function properly the Dictionaries containing the IDb* objects must persist across multiple calls. For this example, I use a Console Application which instantiates a single instance of the service and uses it for all calls. However, other hosts may choose to destroy and recreate instances of the services. Others may choose to create multiple instances simultaneously. Depending on your host you may have to make all the dictionaries Static and instantiate them in the classes static constructor.

Common Interface Implementation

The rest of the class simply implements the interface contract. Most methods follow the exact same pattern.

  1. Get underlying Ado.Net object from dictionary using the Token as the key.
  2. Execute the method on object
  3. Return results

Example:

   69 public int GetConnectionTimeout(string token)

   70         {

   71             return _connections[token].ConnectionTimeout;

   72         }

Very few methods deviate from this model. We’ll focus only on those methods that do.

Ado.Net Object Creation

Connection

   34 public string CreateConnection(string invariantName)

   35         {

   36             IDbConnection connection = System.Data.Common.DbProviderFactories.GetFactory(invariantName).CreateConnection();

   37             string token = GetToken();

   38 

   39             _connections.Add(token, connection);

   40 

   41             return token;

   42         }

 

Create Connection is the only contract method that doesn’t require a token. It accepts a single parameter, the invariantName. This is the invariant name of the Data Provider you wish to instantiate. The method is quite simple, it creates a new IDbConnection for that provider using the DbProviderFactory’s CreateConnection method. It then generates a new token, stores the connection and returns the token to the client.

Command

   75 public string CreateCommand(string token)

   76         {

   77             string commandToken = GetToken();

   78             IDbCommand command = _connections[token].CreateCommand();

   79             _commands.Add(commandToken, command);

   80 

   81             return commandToken;

   82         }

 

To create a command object the CreateCommand method uses a connection token to retrieve the connection for which the command will be created. It then calls the CreateCommand method on the IDbConnection object and stores the resulting command. The returned token points to the new Command object.

IDataReader

The GetCurrentReaderRecord is the only method that significantly deviates from the Common Interface Implementation. Rather than implement all the GetString, GetInt, etc. methods we return the entire row. Calls to these methods on the client will then pull the data from the cached DataTable.

  311 public DataTable GetCurrentReaderRecord(string token)

  312         {

  313             DataTable table = new DataTable("CurrentRecord");

  314 

  315             IDataReader reader = _readers[token];

  316 

  317             for (int i = 0; i < reader.FieldCount; i++)

  318             {

  319                 DataColumn column = new DataColumn(reader.GetName(i), reader.GetFieldType(i));

  320                 table.Columns.Add(column);

  321             }

  322 

  323             DataRow row = table.NewRow();

  324 

  325             for (int i = 0; i < reader.FieldCount; i++)

  326             {

  327                 row[i] = reader[i];

  328             }

  329 

  330             table.Rows.Add(row);

  331 

  332             return table;

  333         }

 

Service Host

The final piece of the Service is the hosting application. For this example I’ve kept it to a simple console application. I’ve also hard coded the endpoint to be NetTcpBindings rather than use App.Config for configuration.

   11 static void Main(string[] args)

   12         {

   13             using (ServiceHost serviceHost = new ServiceHost(typeof(WcfDataProviderService), new Uri("net.tcp://localhost:4200")))

   14             {               

   15                 serviceHost.AddServiceEndpoint(typeof(IWcfDataProvider), new NetTcpBinding(), "net.tcp://localhost:4200");

   16 

   17                 serviceHost.Open();

   18 

   19                 Console.WriteLine("Service Started. Press Enter to Exit.");

   20                 Console.ReadLine();

   21             }

   22         }

 

Source Code

Previous: Contract

Next: Client

 

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments

There are no comments for this journal entry. To create a new comment, use the form below.

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>