This is way cool. From time to time, I tend to screw around with stuff I enjoy that really has little productive value. A year ago this month, I recall wanting to continue writing about sharing your personal music without using IIS and hosting the music directly from a WCF standalone executable. Well it turns out this is a whole lot simpler than I originally thought.
Disclaimer: This probably isn’t best practice, and it’s ripe for enhancements. My hope is that it gets your imagination fired up and motivates you to continue where I left off.
Challenges:
How the heck do I stream an MP3 file to a media element via WCF (without having to download the whole file before playing it)?
Cross-site scripting policies are blocking my download requests. How can I serve these up via my self hosted WCF REST service?
Silverlight3 doesn’t support WCF REST yet. How do I deserialize the WCF REST contract messages?
Changes Since Last Release
My original design was very simple. I hosted the Silverlight files and used WCF with an IIS server at home. The player pulled a list of files and locations. The player’s media element source was set directly to a music file hosted in an IIS virtual directory. All that works great until you are on a machine without a web server. Ultimately, I wanted to figure out a way for the user to host their music repository from their desktop with a simple executable and port forwarding. Which means it would have to serve up all the resources necessary to run the Silverlight player. It would also have to serve up the WCF services and actual music files themselves.
Since the last post a year ago, I’ve made quite a few little tweaks to the player like: regular expression search, random songs, random play order, and a volume control. I also integrated a compact SQLite database for searching so the server-side doesn’t have to do a file system search for each request.
So recently, I was playing around with WCF, and I created a few classes that I wanted to expose in operations. Usually when I play with plain old objects, I tend to type them up pretty lazily and use any code shortcut I can. In this case I defined my properties using the 3.0 auto-generated field method, which looks like an interface property. The C# compiler automatically generates the backing field on the fly for me at compile time. Here is a sample class I’m using in the silverlight music project.
[Serializable]
public class FileBrowser
{
public string LocalMusicRoot { get; set; }
public string WebMusicRoot { get; set; }
public List<string> Files { get; set; }
}
The catch comes in when you expose it to WCF. When serializing these objects, the serializer will look at all FIELDS of the class no matter their scope: public, private, etc. This is because it uses System.Runtime.Serialization, not System.Xml.Serialization. It does not serialize properties since properties really are just accessor functions. So what you get is a funky looking proxy class with some properties you didn’t want and some cryptic naming. I.E. k__BackingField appended to your field names. The serializer simply takes what it has which is the auto-generated field name the C# compiler made for us.
So how do I clean this up?!?! Easy! Use a data contract. By defining your classes using the DataContract attribute from System.Runtime.Serialization, the serializer will interpret your DataMembers as fields on the class and use your naming. It will also ignore anything that’s not defined as a DataMember; so that hidden stuff will remain hidden and not be included in the proxy class. Take a look at this. We modified our original class with these attributes and the generated proxy class on the right now uses the names and fields we want! Easy peasy!
I’m sure this has been written about a ton, but why not repost some useful information.
When using Silverlight with WCF, you quickly learn about the cross-domain restrictions. It becomes a huge pain when deploying from dev to production because you have to deploy and configure your Silverlight using the prod endpoint address, which for me at least didn’t always work. So what I found was that quite a few people are setting their WCF client end points on the fly using the current host during runtime. It’s relatively easy to do, and since they both are typically deployed at the same time, it works out pretty well.
This snippet strips away the ClientBin/xxx.xap from the application source and retains the application root URL.
string full = Application.Current.Host.Source.AbsoluteUri;
full = full.Substring(0, full.LastIndexOf('/')) + "/../";
You can then put this functionality into a utility class for your application and make it very easy to consume when using WCF services. Using the music manager service from a previous post, we have:
MusicManagerService.MusicManagerServiceClient client;
client = new MusicPlayer.MusicManagerService.MusicManagerServiceClient();
//use dynamic endpoint
client.Endpoint.Address = new System.ServiceModel.EndpointAddress(full + "MusicManager.svc");
client.GetFilesCompleted +=new EventHandler<MusicPlayer.MusicManagerService.GetFilesCompletedEventArgs>(client_GetFilesCompleted);
client.GetFilesAsync(uxSearchString.Text.Trim());
For deployment, you just xcopy your published web app to the deployment directory and you’re done. No reconfiguring/recompiling necessary.
A buddy of mine recently had mentioned he wanted a web based program he could use to listen to his music from home. As a contractor, we move around a lot. At some locations, we can’t install any software; others, we have firewall issues. Our mobile devices couldn’t hold every song we stored at home, and copying our music around everywhere just didn’t seem like a great idea. So we thought… wouldn’t it be cool if we could have just a simple website that could stream our music from anywhere? It’s an easy install…
So I started digesting the idea and thought yeah, we could do that. At first we’ll have to just use something simple like streaming the files directly from IIS in a silverlight music player of sorts. But eventually, we can really take advantage of some cool WCF hosting features in windows and not require IIS at all, which would be great for most of us since everyone doesn’t have a windows server sitting around at home. After a tiny bit of research, I realize we could also take advantage of the Media Services component built into windows server and IIS, which from the sound of it are pretty comprehensive. But with our end goal in mind, we’ll want to find a way to stream it right out of a simple windows app available to any edition of Windows.
Having said all that, I decided to start writing about this little toy project. To begin, we have a simple Silverlight application with a music player, list manager, and an IIS server hosting a virtual directly to our mp3 repository.