Two Interface and one concrete class in WCF
Asked Answered
G

2

6

please check the below example

namespace GServices
{
    [ServiceKnownType(typeof(SearchType))]
    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface ITest
    {
        [OperationContract]
        int subtract(int x, int y);
    }

    [ServiceKnownType(typeof(SearchType))]
    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface ITest2
    {
        [OperationContract]
        int add(int x, int y);

    }
    public class G : ITest2, ITest
    {
        public int add(int x, int y)
        {
            return x + y;
        }
        public int subtract(int x, int y)
        {
            return x + y;
        }
    }
}

ITest has subtract() method and Itest2 has add() method.

Both are implemented by one concrete class called G.

If i just want to expose the ITest through WCF, I have following endpoint config

  <service name="GQS1" behaviorConfiguration="GQwcfBehaviour">
    <endpoint address="DP2Svcs" binding="wsHttpContextBinding" bindingConfiguration="wsHttpEndpointBindingConfig" contract="GServices.itest">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
  </service>

when i run this service and check the wsdl, I can see that the methods which are in itest2 also appeared in wsdl. in this example case , subtract() method should only be exposed. But add() method is also exposed.

My requirement is to have methods in ITest Interface should only exposed. in this case , i want to expose only subtract() method which is declared in ITest. But both of their implementation resides in Only one concrete class "G". What am I missing here?

Edit : I have given my Service.svc file content :

<%@ ServiceHost Language="C#" Debug="true" Service="GServices.G"  %>

enter image description here

Glottic answered 5/7, 2012 at 7:41 Comment(6)
Whats the return type of your exposed method is it G or ITestMathieu
@abatishchev : ok, sorry, I copied from development code and changed the nameGlottic
Will it not be more handy for you to have a real names? Just wondering :)Baelbeer
@Baelbeer : I did the same. I have given "contract="GServices.itest" in the endpoint configurationGlottic
Shouldn't the contract in the bindings be GServices.ITest not GServices.itest ?Mathieu
@Bob you are correct, It should be GServices.ITest. but its not related our actual problem here. Its editing mistake done by me. The actual code is ok like you said.Glottic
A
4

Make sure that the value of the name attribute in the <service> element in the configuration is the fully-qualified name of the service class. In your config you have the endpoint contract name qualified by a namespace (GServices.itest), but the service is not (GQS1). If you don't have any service confugration for a specific service, WCF will add one default endpoint which wil expose the problem you have. For example, in the code below, where the line which adds one endpoint is commented out, the WSDL on the service shows both operations. But if you uncomment the line (which will make the service have only one endpoint of type ITest), only the "subtract" operation will be shown.

public class StackOverflow_11339853
{
    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface ITest
    {
        [OperationContract]
        int subtract(int x, int y);
    }

    [ServiceContract(SessionMode = SessionMode.Allowed)]
    public interface ITest2
    {
        [OperationContract]
        int add(int x, int y);

    }
    public class G : ITest2, ITest
    {
        public int add(int x, int y)
        {
            return x + y;
        }
        public int subtract(int x, int y)
        {
            return x + y;
        }
    }
    public static void Test()
    {
        string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
        ServiceHost host = new ServiceHost(typeof(G), new Uri(baseAddress));
        // host.AddServiceEndpoint(typeof(ITest), new BasicHttpBinding(), "");
        host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
        host.Open();
        Console.WriteLine("Host opened");

        Console.Write("Press ENTER to close the host");
        Console.ReadLine();
        host.Close();
    }
}
Allahabad answered 5/7, 2012 at 14:39 Comment(1)
Thanks a lot @carlosfigueira, You saved my life. !!! Thank you again. The actual problem is i have only one concrete class that implements both of the interfaces. If we specify fully qulified class name in the service tag, I got this error " A child element named 'service' with same key already exists at the same configuration scope." What i did, I have created new derived class named "G1" from the actual implementation class "G" and i refer this name in Service name, Its ok now !!!! thank a lot man !Glottic
M
1

If you don't need the ITest2 interface exposed as a service, simply remove the ServiceContract attribute from it.

If you need ITest2 in a different service, you can use interface inheritance to solve this issue:

interface ITest2
{ 
    [OperationContract]
    int Add(int x, int y);
}

[ServiceContract]
interface ITest2Service : ITest2 { }

Use ITest2 in the first service (that also implements ITest) and ITest2Service in the second service.

Manmade answered 5/7, 2012 at 7:58 Comment(4)
I think OP want to expose a service contract per endpoint. And implement all the contracts by a single class. Sounds reasonable.Baelbeer
@Baelbeer : I just need to have both ITest and ITest2 to be explosed via WCF. But its diffrent services. thats why i have put [ServiceContract] thereGlottic
@thya: So service1/endpoint1 exposes interface1, and service2/endpoint2 exposes interface2, correct?Baelbeer
@Baelbeer : yes, You are correct, service1/endpoint1 exposes interface1, and service2/endpoint2 exposes interface2Glottic

© 2022 - 2024 — McMap. All rights reserved.