views:

541

answers:

2

Can anyone advise of a good pattern for using a WCF Service from an ASP.net Page? It seems that if the lifetime of the Client(:ServiceModel.ClientBase) is not properly controlled that we get PipeException thrown. It currently exists as a field of the Page class, but is being reinstantiated upon each page request without being cleaned up (the .Close method).

I suspect this question could be rephrased "Managing limited resources in an ASP.net page", and is probably more related to the lifecycle of an ASP.net page. I'm new to ASP.net, so my understanding of this is a little thin.

TIA.

EDIT: Some code (there's not much to it!)

public partial class Default : Page
{
    //The WCF client... obviously, instantiating it here is bad,
    //but where to instantiate, and where to close?
    private readonly SearchClient client = new SearchClient();


    protected void Page_Load(object sender, EventArgs e)
    {

2nd Edit: Would the following be better?

public partial class Default : Page
{
    private SearchClient client;


    protected void Page_Unload(object sender, EventArgs e)
    {
        try
        {
            client.Close();
        }
        catch
        {
            //gobbled
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        client= new SearchClient();
        //.....
A: 

In general, you shouldn't call external services directly from your presentation tier. It creates two problems: first, performance (pooling, scaling, etc), and second, it creates a security risk if you need to authenticate (authentication code in your DMZ is bad.

Even if you don't have an application tier, you should consider refactoring your service call to a private service in your presentation tier. This will allow you to decouple the service's lifecycle from the page's lifecycle (which is problematic as you have stated).

Michael Meadows
What problem do you see with authentication? WCF will be doing the authentication, not the page.
John Saunders
The problem is that it places your authentication source (LDAP/AD/database, ect) too close to the internet. It makes it more easily hackable.
Michael Meadows
+1  A: 

I agree with Michael, abstract it out into another layer if possible.

However, if you are going to call it from your aspx page, I would just create a separate method to call it, return its results and cleanup. Keeps the code clean by having it all in one place. Just remember to dispose in your finally block, and that the wcf proxy will have to be cast to IDisposable in order to dispose.

for instance:

void Page_Load(object sender, EventArgs e)
{
  if(!IsPostBack)
  {
      RemoteCall();
  }
}

void RemoteCall()
{
 var client = new SearchClient();
 try
 {
     var results = client.Search(params);
     clients.Close();
 }
 catch(CommunicationException cex)
 {
   //handle
 }
 catch(Exception ex)
 {
   //handle
 }
 finally
 {
     ((IDisposable)client).Dispose();
 }

}
dcgartn