Dependency Injection on SignalR
This article shows how to perform dependency injection on SignalR hubs.
Dependency injection is a way to remove hard-coded dependencies between objects, making it easier to replace an object’s dependencies, either for testing (using mock objects) or to change run-time behaviour.
What is Dependency Injection?
If you are already familiar with DI skip this section.
Dependency injection (DI) is a pattern where objects are not responsible for creating their own dependencies.
Here I given some examples to motivate DI. Suppose you have object that need to create Error log management. There two types of log management given below
- Text file viewer
- Event viewer
Now I’m going to create interface class first as a ILog that has one method to write the error log after that this method inherited by other log classes.
namespace DependencyInjection
{
public interface Ilog
{
void Messagelog(Exception ex);
}
}
Text file Viewer Class
Now create a class, Filelogger class that inherits the ILog interface. This class writes an error log into text file.
using System;
using System.Configuration;
using System.IO;
namespace DependencyInjection
{
public class Filelogger:Ilog
{
public void Messagelog(Exception ex)
{
string folderPath = @”D:/logs/”;
if (!(Directory.Exists(folderPath)))
{
Directory.CreateDirectory(folderPath);
}
FileStream objFileStrome = new FileStream(folderPath + “errlog.txt”, FileMode.Append, FileAccess.Write);
StreamWriter objStreamWriter = new StreamWriter(objFileStrome);
objStreamWriter.Write(“Message: “ + ex.Message + Environment.NewLine);
objStreamWriter.Write(“StackTrace: “ + ex.StackTrace + Environment.NewLine);
objStreamWriter.Write(“Date/Time: “ + DateTime.Now.ToString() + Environment.NewLine);
objStreamWriter.Write(“============================================”);
objStreamWriter.Close();
objFileStrome.Close();
}
}
}
Event Viewer Class
Now create one more class EventViewerLogger class that inherits ILog interface. This class write an error log message in the event viewer.
using System;
using System.Configuration;
using System.Diagnostics;
namespace DependencyInjection
{
public class EventViewerLogger:Ilog
{
public void Messagelog(Exception ex)
{
EventLog objEventLog = new EventLog();
string sourceName = “DependencyInjection”;
if (!(EventLog.SourceExists(sourceName)))
{
EventLog.CreateEventSource(sourceName, “ErrorLog”);
}
objEventLog.Source = sourceName;
string message = String.Format(“Message: {0} n StackTrace: {1} n Date/Time: {2} “, ex.Message, ex.StackTrace, DateTime.Now.ToString());
objEventLog.WriteEntry(message, EventLogEntryType.Error);
}
}
}
Operation Class:
Before understanding the concept of Dependency Injection (DI) you need to understand the two concepts of object oriented programming mentioned below
- Tightly coupling – Tightly coupling is when a group of class are highly depends on one another.
- Loosely coupling –Loosely coupling is achieved by means of design that promotes single-responsibility and separation of concern.
Now create a one more class to understand the concept of tightly coupling. The Operation class has Interface class ILog instance which has been create by Filelogger Class.
Here Operation class objects are tightly coupled with Filelogger class.
using System;
namespace DependencyInjection
{
public class Operation
{
Ilog logger = new Filelogger();
public void Division()
{
try
{
int AvgGain = 10000, AvgLoss = 0, rs;
rs = AvgGain / AvgLoss;
Console.WriteLine(“Result is :{0}”, rs);
}
catch (DivideByZeroException ex)
{
logger.Messagelog(ex);
}
}
}
}
The above code works perfectly but not the best design to do that because it is tightly coupled with Filelogger.supposing that a lot of other objects use Filelogger,you will need to change all of them.so you need to change throughout the application.
So this is not depending on the Open closed principle of object oriented programming.
Main Program (without dependency injection):
Now call your class method in your application start up class you get in the text file so you start up the class like below
using System;
namespace DependencyInjection
{
class Program
{
static void Main(string[] args)
{
Operation objOperation = new Operation();
objOperation.Division();
Console.Read();
}
}
}
Let run the application you will get an exception in the log file show below figure.
A better approach is to inject ILog into object by using constructor dependency injection.
With Constructor Dependency Injection
The Constructor Injection uses a parameter to inject dependencies so there is normally one parameterized constructor always. So in this constructor dependency, the object has no default constructor and you need to pass specified values at the time of creation to initiate the object.
Now your design is loosely coupled with use of constructor Dependency.
Let’s create OperationEvent class. This class constructor will be used to inject dependencies in the object is given below figure.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DependencyInjection
{
public class OperationEvent
{
Ilog logger;
public OperationEvent(Ilog logger)
{
this.logger = logger;
}
public void Division()
{
try
{
int AvgGain = 10000, AvgLoss = 0, rs;
rs = AvgGain / AvgLoss;
Console.WriteLine(“Result is :{0}”, rs);
}
catch (DivideByZeroException ex)
{
logger.Messagelog(ex);
}
}
}
}
Here you notice that OperationEvent object is neither dependent on an Filelogger object nor anEventViewerLogger object so you can bale to inject either Filelogger dependencies oeEventViewerLogger dependencies at runtime.
Let’s see the EventViewerLogger dependencies in an OperationEvent object using constructor dependency injection.
using System;
namespace DependencyInjection
{
class Program
{
static void Main(string[] args)
{
//Operation objOperation = new Operation();
//objOperation.Division();
//Console.Read();
OperationEvent objOperationEvent = new OperationEvent(new EventViewerLogger());
objOperationEvent.Division();
Console.Read();
}
}
}
Now run your application and you get the result as below figure.
Simple Dependency Injection with SignalR
Let’s consider the chat application with SignalR.
Here is the hub class from that application.
using Microsoft.AspNet.SignalR;
namespace SignalRChat
{
public void BroadCastMessage(string msgFrom,string msg)
{
Clients.All.receiveMessage(msgFrom,msg);
}
}
}
Now you want to store the chat messages on the server before sending them for those case, you might define an interface that abstracts this functionality, and use Dependency injection to inject the interface intoSignalRChatHub class.
namespace SignalRChat
{
public interface IChatRepository
{
void Add(string msgFrom, string msg);
}
}
using Microsoft.AspNet.SignalR;
namespace SignalRChat
{
public class SignalRChatHub : Hub
{
private IChatRepository _Ichatresp;
public SignalRChatHub(IChatRepository Ichatresp)
{
_Ichatresp = Ichatresp;
}
public void BroadCastMessage(string msgFrom,string msg)
{
_Ichatresp.Add(msgFrom, msg);
Clients.All.receiveMessage(msgFrom,msg);
}
}
}
Here the problem is that a SignalR application does not directly create hubs for you.
SignalR creates them for you.by default SignalR expects a hub class to have parameter less constructor.However,you can easily resigter a function to create hub instance and use thid function to perform DI.
To register the function by calling GlobalHost.DependencyResolver.Resister
using Microsoft.AspNet.SignalR;
[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
GlobalHost.DependencyResolver.Register(
typeof(SignalRChatHub),
()=> new SignalRChatHub(new IChatRepository()));
app.MapSignalR();
}
}
}
Now SignalR will invoke this anonymous function whenever it needs to create a SingalChatHub instance.
The pervious code is fine for simple cases. I hope this article helps you.Thanks for reading this article.