4 minute read

In my last post I wrote about a WCF hang I caused because of a newbie mistake. I also wrote that I would post about how to create a simple WCF service. This tutorial is mostly for myself so that I’ll remember what I did, but hopefully it might benefit some other people too…

The WCF service I will create here (MyGameService) is one that will keep track of all the games for my game site.

Creating a WCF Service and hosting it in IIS

  1. In Visual Studio 2008, choose File/New/ Web Site…/WCF Service and put it in the location http://localhost/MyGameService.

    Note: You could have choose File / New / Project and Web / WCF Service Application as well but this would have created a file based one that you would later have to publish to IIS.

  2. Since we want to call our service MyGameService rather than Service we have to make the following changes

    • Rename Service.svc to MyGameService.svc
    • Rename App_Code/IService.cs to IMyGameService.cs
    • Rename APP_Code/Service.cs to MyGameService.cs
    • In IMyGameService.cs rename the interface IService to IMyGameService and press Shift+Alt+F10 to rename it throughout the project
    • Do the same to rename the class Service to MyGameService in MyGameService.cs
    • Change the markup in MyGameService.svc so that Service=”MyGameService” and CodeBehind=”~/App_Code/MyGameService.cs”
  3. Remove all the contents of IMyGameService.cs except for

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    [ServiceContract]
    public interface IMyGameService
    {
    }
    

    and all the contents of MyGameService.cs except for

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    
    public class MyGameService : IMyGameService
    {
    }
    

    now we have a clean slate to work with

  4. Add methods [OperationContract] and classes [DataContract] to the service

    The service will have 3 methods

    void AddGame(Game g);
    Game GetGameByID(int id);
    List<Game> GetAllGames();
    

    Since we are passing Games back and forth we will also have to create a DataContract for the type Game

    To do so, add the following code to IMyGameService.cs

       [ServiceContract]
       public interface IMyGameService
       {
          [OperationContract]
          void AddGame(Game g);
    
          [OperationContract]
          List<Game> GetAllGames();
    
          [OperationContract]
          Game GetGameByID(int id);
       }
    
       [DataContract]
       public class Game{
          [DataMember]
          public int ID { set; get; }
          [DataMember]
          public string Name { set; get; }
          [DataMember]
          public string Publisher { set; get; }
          public Game() { }
       }
    
  5. Implement the methods in MyGameService.cs

       public class MyGameService : IMyGameService
       {
          static List<Game> _games = new List<Game>();
          static object locker = new object();
    
          #region IMyGameService Members
    
          public void AddGame(Game g)
          {
             g.ID = GetNextID();
             lock (locker)
             {
                      _games.Add(g);
             }
          }
    
          public List<Game> GetAllGames()
          {
             return _games;
          }
    
          public Game GetGameByID(int id)
          {
             lock (locker)
             {
                   foreach (Game g in _games)
                   {
                      if (g.ID == id)
                         return g;
                   }
             }
             return null;
          }
    
          #endregion
    
          private int GetNextID()
          {
             int maxID = 0;
             lock (locker)
             {
                   foreach (Game g in _games)
                   {
                      if (g.ID > maxID)
                         maxID = g.ID;
                   }
             }
             return maxID + 1;
          }
       }
    

    Note: you can create stubs for the methods by marking IMyGameService and pressing shift+alt+f10

  6. Browse to MyGameService.svc

    Note: if there is no mapping for .svc you may get the following error

    A name was started with an invalid character. Error processing resource 'http://localhost/MyGameService/MyGameService.svc'....
    
    <%@ ServiceHost Language="C#" Debug="true" Service="MyGameService" CodeBehind="~/App_Code/MyGameService.cs" %>
    -^
    

    To fix this, add a mapping for .svc in inetmgr for the default website or for this particular vdir mapping to C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll. You may need to reset IIS for the mapping to take effect

Creating an ASP.NET Client that consumes the WCF service

  1. Add a new web site to the WCF service solution called http://localhost/MyGameSite
  2. Add a web reference to the WCF service (http://localhost/MyGameService/MyGameService.svc) and call the reference MyGameService
  3. In the browser, where you browsed to MyGameService.svc copy the svcutil.exe command

    svcutil.exe http://mymachine/MyGameService/MyGameService.svc?wsdl
    

    open up a Visual Studio 2008 command line and run this to generate the files MyGameService.cs and output.config.

  4. Add a new folder to your asp.net project called app_code and add the generated MyGameService.cs file to this directory

  5. Add everything between <system.ServiceModel>...</system.ServiceModel> including the <system.ServiceModel>...</system.ServiceModel> tags from output.config to your web.config file, right before the closing </configuration> tag.

    Now we are ready to call the WCF service from our ASP.NET application

  6. Add two text boxes (txtName, txtPublisher), a button (btnAddGame) and a data grid to display games (grdGames) to default.aspx
  7. Add the following code to default.aspx.cs

    protected void Page_Load(object sender, EventArgs e)
    {
       if (!Page.IsPostBack)
       {
          using (MyGameServiceClient gs = new MyGameServiceClient())
          {
             grdGames.DataSource = gs.GetAllGames();
             grdGames.DataBind();
          }
       }
    }
    protected void btnAddGame_Click(object sender, EventArgs e)
    {
       using (MyGameServiceClient gs = new MyGameServiceClient())
       {
          gs.AddGame(new Game() { Name = txtName.Text, Publisher = txtPublisher.Text });
    
             grdGames.DataSource = gs.GetAllGames();
          grdGames.DataBind();
       }
    }
    

Remember to use a using statement or to explicitly close the MyGameServiceClient, otherwise you will end up with the hang shown in my previous post.

And that is pretty much all there is to it.

A word of caution, you will be dealing with the same cross-domain/cross-application issues here as with normal web services, i.e. a potential for heavy serialization if you pass a lot of stuff back and forth, and other such issues, so be a bit careful when you design any apps that rely on sending data back and forth across domain or application boundaries.

Have fun, Tess

Tags:

Categories:

Updated: