Just another tech site

oData v3 and DataServices 5.0


oData interception

One of the coolest thing with DataServices is that you can really quickly setup your oData Service.
Now if you wish to intercept the call and to perform specific operation it is of course possible.
In this small example we will see how to create the service and make the modification in order to have an end to end call.
The example uses oData version 3 and .NET DataService 5.0 (available under NuGet)

The Data Service

Here is the classic service definition

// Expose IQueryable properties as read-only Atom collections
public class CustomerDataService : DataService
{

#region Data Service Initialize Service

public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
#endregion

In this case “CustomerService” is an Iqueryable. For example a dbcontext.

WCF interception

In the service definition we need to add the interception of the call and the analysis of the URI.
The idea is to extract the custom elements in the querytring.
The key event is the “OnStartProcessingRequest” that will be called upon reception.

// Expose IQueryable properties as read-only Atom collections
public class CustomerDataService : DataService
{

     …
#region These elements will allow us to parse the query string for non oData elements

DataServiceOperationContext OpsContext;
Dictionary<string, string> QueryParameters;

///
/// GetQueryParameterBag
///
///
///
Dictionary<string, string> GetQueryParameterBag(DataServiceOperationContext serviceOperationContext)
{
Dictionary<string, string> ParameterBag = null;
string query = serviceOperationContext.AbsoluteRequestUri.Query;

if (!string.IsNullOrEmpty(query))
{
ParameterBag = new Dictionary<string, string>();
query = query.Remove(0, 1);
string[] param = query.Split('&');

string paramName;
string paramValue;

foreach (var item in param)
{
//Skip OData supported parameters
if (!item.StartsWith("$"))
{
paramName = item.Substring(0, item.IndexOf("="));
paramValue = item.Substring(item.IndexOf("=") + 1);
ParameterBag.Add(paramName, paramValue);
}
}
}
return ParameterBag;
}

#endregion

protected override void OnStartProcessingRequest(ProcessRequestArgs args)
{
OpsContext = args.OperationContext;
QueryParameters = GetQueryParameterBag(OpsContext);
logger.Log(LogLevels.Medium, String.Format("OnStartProcessingRequest: {0}", OpsContext.AbsoluteRequestUri));
base.OnStartProcessingRequest(args);
}

oData interception

Once we have intercepted the WCF call we can use the information in the more specific calls.
In our case we have one entity “customer” that we would like to alter

// Expose IQueryable properties as read-only Atom collections
public class CustomerDataService : DataService
{

     …

        public IQueryable Customers()
{
logger.Log(LogLevels.Medium, String.Format("IQueryable Customers called"));
return this.CurrentDataSource.Customers;
}

Start the Data Service


public void Start()
{

logger.Log(LogLevels.Information, "[Stating DataServiceTest] ****** ");
logger.Log(LogLevels.Information, "");

string serviceAddress = "http://localhost:998";
Uri[] uriArray = { new Uri(serviceAddress) };
Type serviceType = typeof(CustomerDataService);

using (var host = new DataServiceHost(serviceType, uriArray))
{
host.Open();

logger.Log(LogLevels.Information, "Press any key to stop service");
Console.ReadKey();
}

}

Service Logging

It can be interesting to show some logging. The following is from msdn WCF (Ref [1])


#region HOST INFORMATION
// svcDesc is a ServiceDescription.
var svcDesc = host.Description;
string configName = svcDesc.ConfigurationName;
logger.Log(LogLevels.Information, String.Format("Configuration name: {0}", configName));

// Iterate through the endpoints contained in the ServiceDescription
ServiceEndpointCollection sec = svcDesc.Endpoints;
foreach (ServiceEndpoint se in sec)
{
logger.Log(LogLevels.Information, "Endpoint:");
logger.Log(LogLevels.Information, String.Format("\tAddress: {0}", se.Address.ToString()));
logger.Log(LogLevels.Information, String.Format("\tBinding: {0}", se.Binding.ToString()));
logger.Log(LogLevels.Information, String.Format("\tContract: {0}", se.Contract.ToString()));
KeyedByTypeCollection behaviors = se.Behaviors;
foreach (IEndpointBehavior behavior in behaviors)
{
logger.Log(LogLevels.Information, String.Format("Behavior: {0}", behavior.ToString()));
}
}

string name = svcDesc.Name;
logger.Log(LogLevels.Information, String.Format("Service Description name: {0}", name));

string namespc = svcDesc.Namespace;
logger.Log(LogLevels.Information, String.Format("Service Description namespace: {0}", namespc));

Type serviceType2 = svcDesc.ServiceType;
logger.Log(LogLevels.Information, String.Format("Service Type: {0}", serviceType2.ToString()));

// The service can now be accessed.
logger.Log(LogLevels.Information, "The service is ready.");
#endregion

Service Queries

Now let’s start the service and check the results

Service MetaData

http://localhost:998/$metadata

oData00

oData01

Query all customers

http://localhost:998/Customers

oData02

oData03

Query only one customer

http://localhost:998/Customers/?$filter=Code%20eq%20'AAA'

oData05

oData05

Reference

[1] http://msdn.microsoft.com/en-us/library/system.servicemodel.description.servicedescription(v=vs.90).aspx
Recomended article on DataServices
[2] http://www.codeproject.com/Articles/514598/Understanding-OData-v3-and-WCF-Data-Services-5-x
[3] http://www.codeproject.com/Articles/393623/OData-Services

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Tag Cloud

%d bloggers like this: