If broken it is, fix it you should

Using the powers of the debugger to solve the problems of the world - and a bag of chips    by Tess Ferrandez, ASP.NET Escalation Engineer (Microsoft)

WCF 101 – Creating and consuming a basic WCF Service hosted in IIS

WCF 101 – Creating and consuming a basic WCF Service hosted in IIS

  • Comments 10

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

a) Rename Service.svc to MyGameService.svc

b) Rename App_Code/IService.cs to IMyGameService.cs

c) Rename APP_Code/Service.cs to MyGameService.cs

d) In IMyGameService.cs rename the interface IService to IMyGameService and press Shift+Alt+F10 to rename it throughout the project

e) Do the same to rename the class Service to MyGameService in MyGameService.cs

f) 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 textboxes (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

  • If you want to cut out 80% of the configuration necessary for a WCF service, check out the Castle Windsor WCF Facility.  This makes production services actually palatable to use in the real world.  You can do it with StructureMap too, but you've got to some legwork first :)

  • Hi, After adding the mapping for .svc I get this error message:

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

    Parameter name: item

    Do you happen to know how to fix this?

  • where do you get this message?  in inetmgr when you add the mapping between .svc and aspnet_isapi? or when you add the binding in web.config?

    You might want to check out this blog entry

    http://www.robzelt.com/blog/2007/01/24/WCF+This+Collection+Already+Contains+An+Address+With+Scheme+Http.aspx

    and there seems to be a lot of notes on the subject when searching for "There can be at most one address per scheme in this collection.".  I haven't ran into it myself though

  • Good post. But you may want to change the way how you consume a WCF service. It is recommended to use the try catch block instead of the using statement.

    Because the closing bracket of the using statement does a close on the service, but if a communication error happens when close is called then that is not handled properly.

    See this msdn post for more info http://msdn.microsoft.com/en-us/library/aa355056.aspx

  • Thanks for the tip,  you are absolutely correct

  • If you want to cut out 80% of the configuration necessary for a WCF service, check out the Castle Windsor WCF Facility.  This makes production services actually palatable to use in the real world.  You can do it with StructureMap too, but you've got to some legwork first :)

  • Hi TessFerrandez,

    i am vinoth. i am new to WCF. could u give any reference to create webservice in WCF and how to hosting the webservice and how to consuming the webservice in our Website.

    If u can please help me

  • am jst a beginner in WCF web service.., My Question is how to call a already created WCF web service from a java class?

    Pls help me out in this.., am so thankful to u

  • Do you know how to call the wcf service in the windows service, is the same like call the service in the asp.net?

    I try to call the same wcf service which is hosted in the IIS in the windows form and windoes service, the former is successful ,but in the windows service is failed~

    Thanks a lot ~

  • Easiest way to create and consume WCF Services in asp.net

    www.webcodeexpert.com/.../how-to-create-and-consume-wcf-services.html

Page 1 of 1 (10 items)
Leave a Comment
  • Please add 3 and 6 and type the answer here:
  • Post