Kirk Evans Blog

.NET From a Markup Perspective

WCF and LINQ


Jim Wooley posted an article about how to decorate LINQ datatypes with DataContractAttribute and DataMemberAttribute so that they can be serialized by WCF.  Sadly, this approach doesn’t work anymore with Visual Studio 2008 Beta 2 and the LINQ to SQL classes designer since the custom attributes property Jim demonstrates is removed in Beta 2.


After banging my head against the keyboard for awhile, I fired off an email to the LINQ team and asked if it is possible to return LINQ classes from WCF services.  It is possible, it just sucks.  You need to click on the designer surface in your .dbml file and change the Serialization property to “Unidirectional”. That will decorate the generated classes with DataContract and DataMember attributes appropriately. 

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Linq;

public class Service : IService
{
public IEnumerable<TroubleTicket> GetTroubleTickets(Ani tn)
{
TroubleTicketsDataContext db = new TroubleTicketsDataContext(@”Server=(local);Integrated Security=true;Initial Catalog=tickets”);
var tickets = from t in db.GetTroubleTickets(tn.NPA, tn.NXX, tn.Line)
select t;
return tickets;
}
}


You can do this from command line as well.  There is a /serialization switch for sqlmetal.exe that will let you specify a value of “unidirectional”.


This sucks.  The custom attributes approach is better because you can control the output, and is much simpler than diving into some funky XML mapping file to influence the serialization.  Since that feature has been removed, you are S.O.L. if you want to do things like remove a type from the serialization output or change its serialized name.  If you need any type of control over the serialization format, it seems better to just create the contracts and data transfer objects by hand, and programmatically map from one type to another:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Linq;

public class Service : IService
{
public IEnumerable<TroubleTicket> GetTroubleTickets(Ani tn)
{
TroubleTicketsDataContext db = new TroubleTicketsDataContext(@”Server=(local);Integrated Security=true;Initial Catalog=tickets”);
var tickets = from t in db.GetTroubleTickets(tn.NPA, tn.NXX, tn.Line)
select t;
List<Ticket> returnTickets = new List<Ticket>();
foreach (var t in tickets)
{
returnTickets.Add(new Ticket{ID=t.TicketID,Description=t.Description};
}
return returnTickets;
}
}

[DataContract]
public class Ticket
{
[DataMember] public Guid ID { get; set; }
[DataMember] public string Description { get; set; }
[DataMember] public string NPA { get; set; }
[DataMember] public string NXX { get; set; }
[DataMember] public string Line { get; set; }
}


Looks like a great opportunity for a VSIP partner to step up and provide some excellent tooling for creating services with WCF and LINQ.