简体   繁体   中英

How to inject WCF services using interfaces in client?

currently my UI code is depend on business logic (binary dll) interface, where instance is injected using unity container.

Future plan is, business logic might be hosted as WCF services with same interfaces. as client code is depend on interface there should not be any changes. Instance should be injected from WCF. Is the below approach is right practice, or is there any best practice available?

public interface MyServiceContract
{
    string GetData(int value);
}

public class Service1 : MyServiceContract
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }
}

public class ServiceFactory
{
    //Get instance from WCF
    public T GetWCFService<T>()
    {
        ChannelFactory<T> factory = null;

        var binding = new BasicHttpBinding();
        var address = new EndpointAddress("uri");
        factory = new ChannelFactory<T>(binding, address);
        var channel = factory.CreateChannel();
        return channel;
    }

    //Get instance from Binary Reference
    public T GetService<T>()
    {
        return UnityContainer.Resolve<T>();
    }
}

public class Test
{
     //calls binary reference method
    private void Test()
    {
        var mysvc = new ServiceFactory().GetService<MyServiceContract>();

        var resturnmessage = mysvc.GetData(9);
        Console.WriteLine(resturnmessage);
    }

    //calls wcf  method
    private void Test2()
    {
        var mysvc = new ServiceFactory().GetWCFService<MyServiceContract>();

        var resturnmessage = mysvc.GetData(9);
        Console.WriteLine(resturnmessage);
    }
}

This approach will work but it is not perfect. You will never close your connections. You need a proxy class that conforms to your interface so you can inject it. That class can have a channel of your interface and pass through all calls. But it also needs to make sure that this channel is closed when it needs to be closed.

If you have a service factory (not a fan personally), you should have an interface IBusinessLogicFactory that has a single method public T GetService<T>() . Then you can derive a UnityInjectorFactory and a WCFServiceFactory from this interface. If your code knows what it gets because you need to call different methods then your abstraction is broken.

Your test case should look like this:

public class Test
{
    private void RunTests()
    {
        Test(new WcfFactory());

        Test(new UnityContainerFactory());
    }

    private void Test(IMyServiceFactory factory)
    {
        var mysvc = factory.GetService<MyServiceContract>();

        var returnmessage = mysvc.GetData(9);
        Console.WriteLine(returnmessage);
    }
}

Closing channels is more complex than it has to be. It's acknolegded to be a bug, but Microsoft said that now that people rely on this behaviour, they cannot fix it. Anyway:

Closing any CommunicationObject:

public static void DisposeCommunicationObject(ICommunicationObject communicationObject)
{
  if (communicationObject != null)
  {
    try
    {
      communicationObject.Close();
    }
    catch
    {
      communicationObject.Abort();
    }
    finally
    {
      ((IDisposable)communicationObject).Dispose();
    }
  }
}

The thing you get as channel can be cast to IClientChannel and then passed to this function. You will need to find out for yourself when this is appropriate in your program. If you no longer want to communicate and probably after it has faulted once.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM