Visual Studio item template for WCF Data Services

Akos Nagy
Jun 6, 2018

If you are only interested in downloading the packages, go to the marketplace. But if you want to know how it was made, read on ;)

Back in the day we used WCF when it came to distributed software. Of course, the times have a-changed since and now in the pink fog of REST and JSON and HTTP WCF is all but forgotten (except if you are of course still have to work on a 5-6-or more-year old legacy system). But before the ASP.NET stack took over every web-related server side development project, Microsoft tried to seize the opportunity that the all-to-complicated WCF pipeline could offer and try to turn it into a solution that can be used for creating REST APIs. More specifically, OData APIs.

You might remember the feature (you probably do if you found this blog post) as WCF Data Services. And it was a good effort. The most unattractive aspect of WCF was without a doubt its complicated nature (there was a joke around that said WCF stood for Windows Complication Foundation). Creating a data service was easy: you just had to use the Wcf Data Service item template (of course, that version was incompatible with the new versions of Entity Framework, but whatever :) ).

The item template that is completely missing from Visual Studio 2017. I just found this out during a course that I had to teach about WCF. I wanted to add this new item template, but nothing. So I took to the internet and I found others with the same issue, but no solution. So I created my own :)

Creating the item template

Not "created" as much as "migrated". Since VS2015 had these templates (one for a web site and one for a web app both in C# and in VB), I installed the 2015 edition of VS in a cloud machine and just copied the templates from the right folder. Basically four zip files, and done, right? Wrong :)

Turns out that there is a wizard that is run when creating this item template (a "wizard" is just a special class compiled into a special dll that contains lifecycle methods to provide hooks into the creation process). So I went ahead and dug up that dll from the VS 2015 enabled machine, created a VSIX project, added the wizard to the VSIX project and referenced the item templates from the VSIX. This had the added benefit of being able to publish the templates as a Visual Studio Extension, so that's OK. It took me some time to track down the cause of the problem and dll, but I was familiar with custom templates and wizards, so it was not that big of a deal, right? Wrong again :)

Turns out that when you create an item template and want to specify Nuget packages that should be added, you have a number of options (which I had not known before). You can include them in the item template project, include them in the VSIX project, or specify a registry key that points to a folder in the file system. Needless to say, that the second option is probably the best (with the first option, I would have had to include the same packages in all four templates, and the third one, well, it uses the registry :) ). The limited documentation that is available also suggests this approach. And guess which one the original templates use? Of course the third one. With VS 2015, the installation process (probably) created the registry key and copied the Nuget packages to the right folder. But VS2017 doesn't do that. So instead of trying to add a registry key to the altered registry handling mechanism of VS2017, I simply went with the recommended best practice, and then, finally, the WCF Data Services template was born. Awesome, right? You might have guessed: wrong again.

What's the problem with this? Well, the generated template scaffolds this code:

//------------------------------------------------------------------------------
// <copyright file="WebDataService.svc.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace WebApp1
{
  public class WcfDataService1 : DataService< /* TODO: put your data source class name here */ >
  {
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService($dataserviceconfig$ config)
    {
      // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
      // Examples:
      // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
      // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
      config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
    }
  }
}

But this is not compatible with the current versions of EF. If you want to use WCF data services, you have to use a (still-in-beta-even-though-it's-under-development-for-5-years) Nuget package and a different base class for the service context:

//------------------------------------------------------------------------------
// <copyright file="WebDataService.svc.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Data.Services.Providers;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;

namespace WebApp1
{
  public class WcfDataService1 : EntityFrameworkDataService< /* TODO: put your data source class name here */ >
  {
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService($dataserviceconfig$ config)
    {
      // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
      // Examples:
      // config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
      // config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);
      config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
    }
  }
}

So I went ahead and added thi Nuget package to the VSIX and the templates as well, and modified the scaffolded code. And finally, the templates were ready to be published to the marketplace.

Check out the source at Github, or download the package from the marketplace. You can check out my other extensions as well.

And of course, needless to say, all rights belong to Microsoft. I kept every copyright notice there was, I hope that I am not infringing anything (especially since I'm not making any money off of this extension).

Akos Nagy
Posted in Visual Studio .NET WCF