Critical Development

Language design, framework development, UI design, robotics and more.

Archive for the ‘ASP.NET’ Category

Hosted ADO.NET Data Services & Silverlight

Posted by Dan Vanderboom on January 7, 2009

I’ll be the first to admit I’m a novice in world of web development, so I expected a learning curve and my fair share of hurdles as I started a new project in Silverlight and ASP.NET to be hosted in the cloud.

After a brief stint writing ASP.NET 1.0 code years ago, I quickly learned to loathe web programming, and decided to do thick-client and mobile device development for the past five years.  But the technologies that have emerged since then–Silverlight 2.0, ADO.NET Data Services, LINQ to Entities–all accessible from within the browser, has forced me to take a second look.  The absolute coolness I’m witnessing suggests that my newest project should take advantage of this much richer Microsoft Interweb stack.

I spent the past month furiously studying WPF in all its gory detail.  I even wrote a 3D demo, using a hot racing car from Google’s 3D Warehouse, converting that model into XAML with 3DPaintBrush (15 day trial available), and animating it through code.  I plan to hook up my Wii remote code to translate twists and turns of the remote into RotateTransforms.

But now I’m learning the differences between Silverlight and WPF, and even the difference between hosting a Silverlight application in a development environment and hosting it with a provider like DiscountASP.net.

In short, I’m very impressed with everything so far, but I ran into a problem with ADO.NET Data Services.  I enjoyed watching the DNRTV episode by Sean Wildermuth on Silverlight data access, and I followed along to build my application just as he did.  When I published to my web host, however, I ran into problems.

"This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection."

Not being a web guy, I have no idea what this means.  Fortunately, a little bird told me that http://danvanderboom.com and http://www.danvanderboom.com, although they both point to the same place, provide multiple base addresses, and this is apparently too confusing for WCF services to handle.

When the ServiceHost is created, an array of base addresses are passed in.  If it gets more than one, it wigs out.  Rob Zelt posted a good article on resolving this issue on his blog, which involves changing the .svc file’s markup to something like this:

<%@ ServiceHost Language="C#" Factory="CustomHostFactory" 
    Service="devCatalyst.MyDataService" %>

And code like this:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;

class CustomHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return new CustomHost(serviceType, baseAddresses[0]);
    }
}

class CustomHost : ServiceHost
{
    public CustomHost(Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    { }
}

This is fine for regular WCF services, but when using ADO.NET Data Services, there’s already a factory defined.

<%@ ServiceHost Language="C#"
    Factory="System.Data.Services.DataServiceHostFactory, System.Data.Services, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
    Service="FunWithData.Web.MyDataService" %>

In order to supply your own custom host factory without losing any of the functionality of the Data Services host factory, you’ll need to inherit from that class like this:

public class CustomHostFactory : DataServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        return base.CreateServiceHost(serviceType, new Uri[] { baseAddresses[0] });
    }
}

In the CreateServiceHost method, note how I create a new Uri array, adding only a single Uri.  Rob Zelt’s code used an index of 1 erroneously, which will work fine so long as you always have at least two base addresses.  But in one of my tests, I only had one, and thereby found the bug.

I also eliminated the need to define CustomHost, instead simply calling base.CreateServiceHost from within CustomHostFactory, passing in my new Uri array.

Actually, the very first error I got was for having Windows authentication setup in my Web.config file, but removing that line was easy.  After writing the custom ServiceHost factory, that error went away and was replaced by this one:

"IIS specified authentication schemes ‘Basic, Anonymous’, but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used."

It took me a few minutes to find the appropriate area of my web host’s control panel to set authentication schemes, but once I did, I noticed that both Basic and Anonymous were enabled.  I disabled Basic authentication and then the application came to life.

Except there was no data actually displayed.  My relative Uri, copied from Mr. Wildermuth’s example, wasn’t cooperating.

var context = new MyEntities(
    new Uri("/TestDataService.svc", UriKind.Relative));

By changing it to an absolute Uri, it finally worked:

var context = new MyEntities(
    new Uri("http://danvanderboom.com/Test/TestDataService.svc", UriKind.Absolute));

As simple as 1-2-3?  Not quite.  After hours of researching the issues and surreptitiously talking to a web development guru, I was able to throw something together and get it working.  Hopefully these tips can save someone else the time and frustration that I encountered.

Advertisements

Posted in ADO.NET Data Services, ASP.NET, Silverlight | 4 Comments »