tags:

views:

1333

answers:

5

I've been following Miguel Castro's excellent article on WCF here and it's all working nicely, except that I have the following code

public AdminClient()
{
    ChannelFactory<IProductAdmin> factory = new ChannelFactory<IProductAdmin>();
    productAdminChannel = factory.CreateChannel();
}

In my app.config file, I have the following configuration:

<system.serviceModel>
    <client>
     <endpoint address="net.tcp://localhost:8002/ProductBrowser"
         binding="netTcpBinding"
         contract="Contracts.IProductAdmin" />
    </client>
</system.serviceModel>

But, when I run the constructor for AdminClient I get an exception saying that the endpoint isn't defined. However, if I change my configuration to give the endpoint a name, and then create the factory as follows, it works.

public AdminClient()
{
    var fac = new ChannelFactory<IProductAdmin>("admin");
    productAdminChannel = fac.CreateChannel();
}


<system.serviceModel>
    <client>
     <endpoint name="admin" 
         address="net.tcp://localhost:8002/ProductBrowser"
         binding="netTcpBinding"
         contract="Contracts.IProductAdmin" />
    </client>
</system.serviceModel>

I'd love an explanation for this. The documentation in MSDN isn't much help...

+2  A: 

You need to specify the endpoint name, because you can have many endpoints for the same type of contract. (For instance a service being deployed on one tcp and one http ws endpoint). Microsoft could have of course built something in WCF to check if there is only one client specified for the contract interface, but that wouldn't have been very consistent. (that it would work if there is only one endpoint specified for the contract). When you would add another endpoint for the same contract later, the code would break in that case.

Raymond Roestenburg
I was about to say that :)
Maxim
+1  A: 

You can get away without specifying endpoint name on service side. For client side, you need to specify the name, because you may be connecting to multiple services that have the same contract. How would WCF know then which one you want?

Krzysztof Koźmic
+2  A: 

This has been bugging me for a few days, so I went through the examples shown in the article you linked above. Everything works correctly except for the second client proxy example that you're having a problem with. As you noted and the other answerers creating a proxy in that way requires an endpoint name, coupling it with the client (which is where the endpoint is defined). I'm still not sure why it behaves the way it does, but I found no way to use that example without explicitly coupling the proxy to the endpoint.

On the other hand, the first example showing how to create the proxy requires no explicit coupling of endpoint address or binding:

 using System;
   using System.ServiceModel;

   namespace CoDeMagazine.ServiceArticle
   {
       public class ProductClient 
          : ClientBase<IProductBrowser>, 
            IProductBrowser
       {

           #region IProductBrowser Members

           public ProductData GetProduct(
              Guid productID)
           {
               return Channel.GetProduct(productID);
           }

           public ProductData[] GetAllProducts()
           {
               return Channel.GetAllProducts();
           }

           public ProductData[] FindProducts(
              string productNameWildcard)
           {
               return Channel.FindProducts(
                  productNameWildcard);
           }

           #endregion
       }

   }

That seems to work just fine. So, maybe the second proxy example is just a poor way to do things, or maybe we're missing something obvious...

Terry Donaghe
not missing anything. miguel's article is out of date. I am sure it ran when he wrote it. Now a asterisk wildcard will match the first qualifying endpoint. I wrote him about it but no reply...
Sky Sanders
A: 

If you don't want to specify endpoint Name explicity, you may write:

    public AdminClient()
    {
        ChannelFactory<IProductAdmin> factory =  
           new ChannelFactory<IProductAdmin>(string.Empty);
        productAdminChannel = factory.CreateChannel();
    }

Parameterless constructor unnecessary doesn't work.

Bartosz Pierzchlewicz
fail. need endpoint name.
Sky Sanders
+5  A: 

Use "*" to use the first qualifying endpoint.

public AdminClient()
{
    ChannelFactory<IProductAdmin> factory  
         = new ChannelFactory<IProductAdmin>("*");

    productAdminChannel = factory.CreateChannel();
}
Sky Sanders