Click here to Skip to main content
14,265,797 members

Dependency injection in "WCF Service Library" project with Self hosting

Rate this:
0.00 (No votes)
Please Sign up or sign in to vote.
0.00 (No votes)
30 Jul 2019CPOL
There are several contents available on internet that talks about injecting dependencies through .svc file's markup [in WCF service application] and it's easy when you've WCF service application. But,it is equally easy to do that even in your WCF Library project (without .svc).

Introduction

There are many ways to make your application loosely-coupled. Using Dependency injection is one such way.
Loosely coupled application helps you in making your application maintanable, extensible and it also helps in testing your code etc. This article will walk you through step by step into implementing IOC container into your WCF service library project. Finally we are going to add the self hosting component. Here, we are going to use Autofac as the IOC Container.

Background

For making application loosely couple it should adhere to the decorum of SOLID principles in object oriented programming.

Single responsibility principle : A class should only have a single responsibility, that is, only changes to one part of the software's specification should be able to affect the specification of the class.

Open–closed principle : "Software entities ... should be open for extension, but closed for modification."

Liskov substitution principle : "Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program." See also design by contract.

Interface segregation principle : "Many client-specific interfaces are better than one general-purpose interface."

Dependency inversion principle : One should "depend upon abstractions, [not] concretions."

Dependecy injection helps in attaining 'Dependency Inversion Principle' 
Source: https://en.wikipedia.org/wiki/SOLID

For IOC Container we are going to use Autofac and Autofac.WCF Source: https://autofaccn.readthedocs.io/en/latest/integration/wcf.html

Things you need

  1. Visual Studio (I am using VS Community Edition 2017)
  2. Autofac
  3. Autofac.WCF
  4. And an Open Mind :)

Using the code

I am going to use very simple code as an example. My focus is on making things simple to understand.

Step 1 : Create a solution and add WCF Library Project

We'll name the solution as "DependencyInjectionWcfWithSelfHosting" and the WCF service library project as "TestService"

Step 2 : Add scaffolding code in WCF Service Project

  • Remove app.config, and the system created IService1, Service1.cs file (You can rename these files but, I like to start with a clean slate)

                            

  • Right click on your TestService project and add new item as a WCF Service class and name it as "DisplayService"

It should look like this
IDisplayService.cs

[ServiceContract]
public interface IDisplayService
{
    [OperationContract]
    string DisplayInputValue(string input);
}

DisplayService.cs

public class DisplayService : IDisplayService
{
    public string DisplayInputValue(string input)
    {
        return input;
    }
}

As you can see, there is nothing fancy in code, just an input passed is return back as is.
But hold on a minute, we can do something that would decorate that input with some string message, say for an example

If I pass "Sunny" as an input, I can add some prefix string to it as "You've entered" to the passed input and return it as "You've entered Sunny".

Well, I can simply append input string with "You've entered"  and return it  from DisplayInputValue().

public string DisplayInputValue(string input)
{
    return "You've entered" + input;
}

But, to get aroung the topic of dependency injection in wcf service,  we will try to do the appending part from some utility classes. And then inject its instance through constructor injection. 

Step 3 : Add just enough code for utility class

  • Add folder name "Utilities" in TestService project and add a class in it with name as "StringMixer" with following code. 
public class StringMixer : IStringMixer
{
    /// <summary>
    /// This method deals with adding ""You've entered" before the passed input
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public string MixStringValue(string value)
    {
        return $"You've entered {value}";
    }
}
  • Extract interface from the "StringMixer" class. That would be "IStringMixer". This will help us during constructor injection into our "DisplayService"
public interface IStringMixer
{
    string MixStringValue(string value);
}

We are going to make use of this utilities in a moment.

Step 4 : Add Hosting support

  • Add the console application to the solution and name it as "Host"
  • Go to the program.cs in console application and add following code in Main() make sure you've added reference for "TestService" and "System.ServiceModel"
using System;
using System.ServiceModel;
using TestService;

namespace Host
{
    class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(typeof(DisplayService));
            host.Open();
            Console.WriteLine("Host has started");
            Console.ReadLine();
        }
    }
}

Now there might be a app.config file in the console application we've recently added. Add the following ServiceModel section in it.

<system.serviceModel>
        <services>
            <service name="TestService.DisplayService">
                <endpoint address="" 

                          binding="basicHttpBinding" 

                          contract="TestService.IDisplayService"

                          name="TestServiceEndPoint"  />

                <endpoint address="mex" 

                          binding="mexHttpBinding" 

                          contract="IMetadataExchange"

                          name="TestServiceMexEndPoint"/>

              <host>
                <baseAddresses>
                  <add baseAddress="http://localhost/TestService" />
                </baseAddresses>
              </host>
            </service>
        </services>
      <behaviors>
        <serviceBehaviors>
          <behavior>
            <serviceDebug includeExceptionDetailInFaults="true" />
            <serviceMetadata httpGetEnabled="true" />
          </behavior>
        </serviceBehaviors>
      </behaviors>
    </system.serviceModel>

OR

If you want you can manually create your own service model configuration by right click on app.config and click on  "Edit WCF Configuration" and do as shown in the wizard (make sure it will run).

  • Run your "Host" Application to make sure everything works
  • You might get the access permission error, simply run your visual studio in adminstrator mode and then run your Host application

If you managed to get so far, congratulations. you are halfway done !!

Step 5 : Verify what we did so far is working or not

  • Try to open the url "http://localhost/TestService" in your WCFTestClient and make sure it works

Step 6 : Complete unfinished business.

As I mentioned at the end of point 3, we are going to inject those utility class "StringMixer" in the "DisplayService" as a constructor injection. 

  • Get to the "TestService" project, open your display service class and add a constuctor
  • Inject the depedency of StringMixer using its interface as an abstraction i.e. "IStringMixer"

DisplayService.cs now might look like this

public class DisplayService : IDisplayService
    {
        private readonly IStringMixer _mixer;

        public DisplayService(IStringMixer mixer)
        {
            _mixer = mixer;
        }

        public string DisplayInputValue(string input)
        {
            return _mixer.MixStringValue(input);
        }
    }

we are going to inject this dependency from the host application. Let get started for an exciting adventure.

Step 7 : Setup Autofac and Autofac.Wcf in "Host" project

  • Add "Autofac" and "Autofac.Wcf" as a nuget package in "Host" project

  • Add class in "Host" project with name "Bootstrapper". In this class we will register our depedencies in Autofac container.
public static ContainerBuilder RegisterContainerBuilder()
        {
            ContainerBuilder builder = new ContainerBuilder();
            builder.Register(c => new StringMixer()).As<IStringMixer>();
            builder.Register(c => new DisplayService(c.Resolve<IStringMixer>())).As<IDisplayService>();
            return builder;
        }

 

Quote:

It's like whenever Autofac sees the reference to those dependencies during contructor injection based upon their abstarction (interfaces), It will inject their registered class into it.

For example

"builder.Register(c => new StringMixer()).As<IStringMixer>();" 

means, wherever there is a reference about IStringMixer, Autofac will inject StringMixer as its implementation.

Step 8 : Tweak "Host" project - a little

  • Modify code in program.cs file by adding following code in it
static void Main(string[] args)
        {
            using (IContainer container = Bootstrapper.RegisterContainerBuilder().Build())
            {
                ServiceHost host = new ServiceHost(typeof(DisplayService));

                IComponentRegistration registration;
                if (!container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDisplayService)), out registration))
                {
                    Console.WriteLine("The service contract has not been registered in the container.");
                    Console.ReadLine();
                    Environment.Exit(-1);
                }

                host.AddDependencyInjectionBehavior<IDisplayService>(container);
                host.Open();
                Console.WriteLine("Host has started");
                Console.ReadLine();

                host.Close();
                Environment.Exit(0);
            }

 

Step 9 : Run the host application. This time you've got the powers of Dependecy Injection.

Thank you for your patience. We are done walking those steps !!

(Image Courtesy : daniel-cheung from unsplash)

Points of Interest

1. You can remove the app.config file from "Host" project and write the code related to EndPoint configuration in your host application instead. Just for info, I've added support for "http" and "netNamedPipe"

static void Main(string[] args)
            {
                using (IContainer container = Bootstrapper.RegisterContainerBuilder().Build())
                {
                    var httpLocation = "http://localhost/DisplayService";
                    Uri address = new Uri(httpLocation);

                    var netNamedPipeLocation = "net.pipe://localhost/DisplayService/";

                    ServiceHost host = new ServiceHost(typeof(DisplayService));

                    host.AddServiceEndpoint(typeof(IDisplayService), new BasicHttpBinding(), httpLocation);

                    host.AddServiceEndpoint(typeof(IDisplayService),
                        new NetNamedPipeBinding(NetNamedPipeSecurityMode.None),
                        netNamedPipeLocation);
 

                    IComponentRegistration registration;
                    if (!container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDisplayService)), out registration))
                    {
                        Console.WriteLine("The service contract has not been registered in the container.");
                        Console.ReadLine();
                        Environment.Exit(-1);
                    }

                    host.AddDependencyInjectionBehavior<IDisplayService>(container);
                    host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true, HttpGetUrl = address });

                    // Add MEX endpoint
                    host.AddServiceEndpoint(
                        ServiceMetadataBehavior.MexContractName,
                        MetadataExchangeBindings.CreateMexNamedPipeBinding(),
                        netNamedPipeLocation + "mex"
                    );

                    host.Open();

                    Console.WriteLine("The host has been opened.");
                    Console.ReadLine();

                    host.Close();
                    Environment.Exit(0);
                }
            }

2. You can also make use of the info provided in this article in WAS hosting as well. 

3. You can use any IOC container apart from Autofac or can make one of your own for depedency injection

4. It's not always necessary to have a interface for your class, But it gives better abstraction and composition over inheritance. Though, there are certain ways to Inject dependency for such class(I mean class without interface) using IOC Container.

Reference

Dependecy injection helps in attaining 'Dependency Inversion Principle' 
Source: https://en.wikipedia.org/wiki/SOLID

For IOC Container we are going to use Autofac and Autofac.WCF Source: https://autofaccn.readthedocs.io/en/latest/integration/wcf.html

(Image Courtesy : daniel-cheung from unsplash)

https://alexmg.com/posts/self-hosting-wcf-services-with-the-autofac-wcf-integration

History

29/07/2019

1. Format added for code snippet

2. Updated images

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sunny Makode
India India
No Biography provided

Comments and Discussions

 
Questionimages and snippets Pin
Nelek28-Jul-19 6:24
protectorNelek28-Jul-19 6:24 
AnswerRe: images and snippets Pin
Sunny Makode28-Jul-19 23:24
memberSunny Makode28-Jul-19 23:24 
GeneralRe: images and snippets Pin
Nelek29-Jul-19 1:26
protectorNelek29-Jul-19 1:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Tip/Trick
Posted 28 Jul 2019

Stats

1.5K views
38 downloads
6 bookmarked