This is a brief note on how to use Apache Cassandra’s user-defined types with C# WCF rest service

Steps

  • Create user-defined type(Udt)
  • Create a mapper object for Udt in C#
  • Register C# Udt object
  • Connect to Cassandra cluster and create session
  • Define WCF DataContract and OperationContract
  • Host in IIS

1. Create User Defined Type(Udt)

Create a user-defined type for address, fullname & users as mentioned in datastax tutorial for udt

2. Create a mapper object for Udt in ‘C#’

Create a cqlpoco in our case that will also be a Data Contract.

class for address

    public class Address
    {
        public string Street { get; set; }
        public string City { get; set; }
        public int ZipCode { get; set; }
        public IEnumerable<string> Phones { get; set; }
    }

class for fullname

public class FullName
 {
     public string FirstName { get; set; }
     public string LastName { get; set; }
 }

finally, a class which represent a row in cassandra users table

    public class User
    {
        public Guid Id { get; set; }
        public IDictionary<string, Address> Addresses { get; set; }
        public IEnumerable<FullName> DirectReport { get; set; }
        public FullName Name { get; set; }
    }

for other data type mapping refer CQL data types to C# types

3. Register C# Udt object

Configure poco object to the Apache Cassandra driver using Mapper Component.

Map user-defined type (FullName and Address)

session.UserDefinedTypes.Define(
          UdtMap.For<FullName>(),
          UdtMap.For<Address>()
             .Map(a => a.Street, "street")
             .Map(a => a.City, "city")
             .Map(a => a.ZipCode, "zip_code")
             .Map(a => a.Phones, "phones")
      );

In most of the cases, mapper will do the mapping for simple type like Fullname but a better controlled mapping is also possible like Address where we map field by field.

Map User class representing a row in a table

   Cassandra.Mapping.MappingConfiguration.Global.Define(new Map<User>().TableName("users")
                .Column(c => c.Id, cm => cm.WithName("id"))
                .Column(c => c.Addresses, cm => cm.WithName("addresses").WithFrozenKey())
                .Column(c => c.DirectReport, cm => cm.WithName("direct_reports").WithFrozenValue()));

4. Connect to Cassandra cluster and create session

We are done with the cassandra and C# setup, now connect to cluster and use.

          cluster = Cluster.Builder().AddContactPoint("127.0.0.1").Build();
          session = cluster.Connect("mykeyspace");

          var users = new Table<User>(session);
          var user = users.
              Where(u => u.Id == Guid.Parse(guid))
              .FirstOrDefault()
              .Execute();

5. Setting up a WCF

It is a trivial task, decorate poco we just created with the DataMember attribute, declare OperationContract and provide a definition. Register mapping (step 3) preferably with a memoization library. I leveraged service contructor to initialise the mapping.

    public class UserService : IUserService
    {
        static UserServiceLibrary.Data.DataService dataService;
        static UserService()
        {
            dataService = new UserServiceLibrary.Data.DataService();
        }
    }    

6. Hosting WCF service

WCF Rest service can be either self hosted using WebServiceHost

	WebServiceHost webhost =  new WebServiceHost(typeof(UserService));
            try
            {
                webhost.Open();
                Console.ReadLine();
                webhost.Close();

            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                webhost.Abort();
            }
        }	

or host it in IIS to take the advantage of on-demand loading and application pool using

<%@ ServiceHost Service="WcfWebService.UserService" 
Factory="System.ServiceModel.Activation.WebServiceHostFactory"%>

:point_right: Complete source code for the above demo can be found at github