none
Wcf - creating connection with generic types RRS feed

  • Question

  • I am working on WCF and building a generic class.

    I am looking for a way (if possible) to define all possible things as generic :

    private ChannelFactory<IMessages> pipeFactory;
    
    pipeFactory =
                       new ChannelFactory<IMessages>(
                         new NetNamedPipeBinding(),
                         new EndpointAddress(uri));
                    IMessages pipeProxy = pipeFactory.CreateChannel();

    is there some way to make this more generic? to replace the IMessages (interface)?


    Tuesday, June 18, 2019 7:15 AM

All replies

  • Hi want 2 Learn,

    Thank you for posting here.

    Since this thread is related to WCF, I will move it to the forum Windows Communication Foundation, Serialization, and Networking to get professional support.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=wcf

    The Visual C# forum discusses and asks questions about the C# programming language, IDE, libraries, samples, and tools.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, June 18, 2019 8:06 AM
  • it's less related to WCF and more the C# language...
    Tuesday, June 18, 2019 8:28 AM
  • Hi,

    The ChannelFactory<T> is natively generic, what do you mean that make it more generic?  You want to encapsulate this and return a factory?  But you have to pass the IService interface and Uri, and binding type.
    To simplify this, we could return a factory by using a method to capsulate this.

    Best Regards

    Abraham

    Tuesday, June 18, 2019 10:07 AM
    Moderator
  • I will explain, in my constructor I want to pass the typeof(class) and typeof(interface)

    and uses this types in the code instead of writing IMessages for example

     
    Tuesday, June 18, 2019 10:42 AM
  • this is the full code of the class

    class Connector2 : Connector
        {
            private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger();
            private ChannelFactory<IMessages> pipeFactory;
            private IMessages pipeProxy;
    
            public Connector2(string ip, string port, string serviceName) : base(ip, port, serviceName) {
            }
    
    
    
            public override void OpenConnector()
            {
                try
                {
                    if (pipeFactory != null && pipeFactory.State == CommunicationState.Opened)
                    {
                        pipeFactory.Close();
                    }
                    pipeFactory =
                       new ChannelFactory<IMessages>(
                         new NetNamedPipeBinding(),
                         new EndpointAddress(NetPipeUri));
                    pipeProxy = pipeFactory.CreateChannel();
                }
                catch (Exception ex)
                {
                    Logger.Error(string.Format("failed creating Connector2->{0},error={1}", NetPipeUri, ex.Message));
                }
            }
    
            public override void SendMessage(BsonDocument bsonDocument)
            {
                DTOMessages dTOMessage = new DTOMessages(bsonDocument);
                pipeProxy.SendMessage(dTOMessage);
            }
           
    

    Tuesday, June 18, 2019 10:47 AM
  • Hi buddy,
    Does the below code could meet your requirement?

    class Program
        {
            static void Main(string[] args)
            {
                Connector<IService> connector = new Connector<IService>("10.157.13.69", "3336");
                connector.OpenConnectort();
                connector.SendMessage("SayHello",null);
            }
    
        }
        
        [ServiceContract]
        public interface IService
        {
            [OperationContract]
            string SayHello();
        }
        public class Connector<T>
        {
            private ChannelFactory<T> factory;
            private T Proxy;
            private string _ip;
            private string _port;
            public Connector(string ip, string port)
            {
                _ip = ip;
                _port = port;
            }
            public void OpenConnectort()
            {
                try
                {
                    if (factory != null && factory.State == CommunicationState.Opened)
                    {
                        factory.Close();
                    }
                    factory = new ChannelFactory<T>(new BasicHttpBinding(), new EndpointAddress(new Uri("http://" + _ip + ":" + _port)));
                    Proxy = factory.CreateChannel();
                }
                catch (Exception)
                {
                    throw;
                }
            }
            public void SendMessage(string methodname,object[] parameters)
            {
                if (Proxy==null)
                {
                    Console.WriteLine("Please Open the connector first");
                }
                else
                {
                    Type t = typeof(T);
                    Object o = t.GetMethod(methodname).Invoke(Proxy, parameters);
                    Console.WriteLine(o.ToString());
                }
                
            }
    }
    

    Best Regards
    Abraham
    Wednesday, June 19, 2019 3:03 AM
    Moderator
  • thanks @Abraham, this moved me forward, but I am stuck with this :

    inside the class I run a thread which activated a ping every 10 seconds

    once I do the changes you wrote I get error that 

    public override void Ping()
            {
                bool isPingFailed = false;
                while (true)
                {
                    try
                    {
                        if (pipeFactory == null || pipeFactory.State != CommunicationState.Opened)
                        {
                            SetTimerForReconnect();
                            continue;
                        }
    
                        pipeProxy.Ping(MessagesManager.PING);
                        Thread.Sleep(10000);
                    }
                    catch (CommunicationObjectFaultedException ex)
                    {
                        isPingFailed = true;
                        SetTimerForReconnect();
                        Logger.Error("failed to ping on1 " + base.NetPipeUri + "," + ex.Message);
                        System.Diagnostics.Debug.WriteLine("failed to ping on1 " + base.NetPipeUri + "," + ex.Message);
                        Thread.Sleep(10000);
                    }
                    catch (Exception ex)
                    {
                        isPingFailed = true;
                        
                        Logger.Error("failed to ping on2 " + base.NetPipeUri);
                        System.Diagnostics.Debug.WriteLine(DateTime.Now+ "failed to ping on " + base.NetPipeUri);
                        Thread.Sleep(10000);
                    }
                    finally
                    {
                        if (isPingFailed) OpenConnector();
                    }
    
                }
            }

    this is the error

    Severity	Code	Description	Project	File	Line	Suppression State
    Error	CS1061	'T' does not contain a definition for 'Ping' and no accessible extension method 'Ping' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)	UnitTestProject	C:\Pulseem\SMPP-ClientServer\UnitTestProject\UnitTestProject\Connector2.cs	78	Active
    

    Thursday, June 20, 2019 4:34 PM
  • also when i try to pass 

     Type t = typeof(T);
                Object o = t.GetMethod("SendDlr").Invoke(pipeProxy, dTODlr);
                Console.WriteLine(o.ToString());
    
    
    where 
    
    [DataContract]
        public class DTODlr
        {
            public DTODlr(DLR Dlr)
            {
                this.Dlr = Dlr;
            }
            [DataMember]
            public DLR Dlr { get; set; }
        }

    i get error

    Severity	Code	Description	Project	File	Line	Suppression State
    Error	CS1503	Argument 2: cannot convert from 'Entities.DTODlr' to 'object[]'	UnitTestProject	C:\Pulseem\SMPP-ClientServer\UnitTestProject\UnitTestProject\Connector2.cs	92	Active
    

    Thursday, June 20, 2019 4:37 PM
  • Hi,

    Does your service interface contain the Ping method? we are supposed to add the method to the service interface.  The second question is caused by something wrong with the serialization and deserialization, just add the namespace to DataContract class to ensure the namespace between the server and client is consistent.
    Like below.

        [ServiceContract]
        public interface IService
        {
            [OperationContract]
            
            string SayHello(Product p);
        }
        [DataContract(Namespace = "mynamespace")]
        public class Product
        {
            [DataMember]
            public int Id { get; set; }
            [DataMember]
            public string Name { get; set; }
        }
    


    Invokation.

    Product p = new Product()
                {
                    Id = 1,
                    Name = "Apple"
            };
                connector.SendMessage("SayHello", new object[] { p });
    


    The connector class encapsulate the ChannelFactory and invoke the service by using reflection. I use the SendMessage method to pass the parameters and the name of the service method. So I think the code snippets could complete your requirement.
    Best Regards
    Abraham

    Friday, June 21, 2019 9:44 AM
    Moderator
  • Hi @Abraham, first thanks a lot you realy moved me forward.

    one last question, how do I handle exceptions?

    I have a method that I do ping to test if the connection is ok, if not then reconnect?

    public  void Ping()
            {
                while (true)
                {
                    try
                    {
                        if (pipeFactory == null || pipeFactory.State != CommunicationState.Opened)
                        {
                            OpenConnector();
                            Thread.Sleep(3000);
                            continue;
                        }
                        //pipeProxy.Ping(MessagesManager.PING);
                        Thread.Sleep(10000);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("failed to ping on {0}" + NetPipeUri);
                    }
    
                }
            }

    as you can see i commented out the line 

    //pipeProxy.Ping(MessagesManager.PING);

    so I can use your solution.

    how can I add a Faulted event, based on your solution (to use with the Invoke method)?

    thanks for all your help

    Friday, June 21, 2019 1:06 PM
  • Hi,

    I think your solution is good, if errors occur, we could reconnect. we could add the below event handler before opening the service host/creating the client proxy.

                   factory.Faulted += delegate
                    {
                        Console.WriteLine("faulted is occuring");
                    };
                    Proxy = factory.CreateChannel();

    Please do not expand the problem. Try to discuss a question in a post to help people who have similar problems later instead of turning the current post into a tutorial.

    You can only rely on yourself for many problems. Thanks for your undestanding.

    Best Regards

    Abraham

    Monday, June 24, 2019 8:49 AM
    Moderator