What design pattern to use in this situation? - c#

I have 40 suppliers that need to make an ftp connection, do something there and close the connection. So, all of those 40 suppliers have their own class and they all have the connection and disconnection of the ftp server, but they all have different processing methods.
So basically I have 40 classes with this method:
ftp.Connect();
//do something - this is different for all the classes
ftp.Close();
So the do something part is different for all, it does different things, it uses different variables, etc.
What I thought I would do is: create a new class that would be instantiated in all the 40 suppliers. This class will have one method that look something like this:
public void Connect(FTPCredentials credentials, Process process)
{
var ftp = new FtpConnection(credentials.Host, credentials.Username, credentials.Password);
ftp.Open();
ftp.Login();
process(ftp);
ftp.Close();
}
public delegate void Process(FtpConnection ftp/*, string name*/);
The problem I have here is that all the methods in all 40 suppliers have different input parameters so what would the input parameters of Process be? Also, I think I don't gain much because I still have the FtpConnection ftp parameter here which means that I will have to add the dll that has the class FtpConnection in every project that will use the Connect method.
For example, the process method in the suppliers would look like this:
process(string fileName) //and it would download fileName
process(string folderName) //create folder if it doesnt exist
Is there a design pattern I can use here that would be cleaner and would make things easier?

My impression is that such an object is used only shortly and for a single specific purpose. So I would accept specific parameters to be stored in a specific derived class. Similar to mybirthname's solution, I'd start with an abstract class, but define it differently:
public abstract class BaseSupplier
{
protected BaseSupplier(FtpCredentials credentials)
{
_Credentials = credentials;
}
private FtpCredentials _Credentials;
public void Run()
{
Connect();
Process();
Disconnect();
}
private void Connect() {/* your connection and login code */}
private void Disconnect() {/* your disconnect code */}
protected abstract void Process(); // to be filled in the derived class
}
public class ConcreteSupplier
{
public ConcreteSupplier(FtpCredentials credentials, SomeType parameter) : base(credentials)
{ /* store extra parameters */ }
override Process() {/*your concrete processing code */ }
}
If I remember correctly, That's called the Strategy Pattern.
Edit:
juunas is right, it's the Template Method pattern. In Gamma et al., Template Method is described directly after Strategy in the chapter on Behavioral Patterns.

Create abstract class
public abstract class BaseSupplier
{
public void Connect(FTPCredentials credentials, Process process, SupplierSettingClass settings)
{
var ftp = new FtpConnection(credentials.Host, credentials.Username, credentials.Password);
ftp.Open();
ftp.Login();
DoSomething(settings);
ftp.Close();
}
public virtual void DoSomething(SupplierSettingClass settings)
{
//define base case;
}
}
You need to create SupplierSettingClass in which you will implement every input parameter for DoSomething method as property (folderName, fieldName and so on)
public class SupplierSettingClass
{
public string FolderName {get; set;}
//and so on;
}
In the end in the SupplierA
public class SupplierA:BaseSupplier
{
public override void DoSomething(SupplierSettingClass settings)
{
//Do specific stuff for your class.
}
}

You can use some clever inheritance to contain pretty much all of the required behaviour in one base abstract class, like this:
public interface IProcessor
{
void Process(Credentials credentials);
}
public class Credentials
{
public string Host { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
public abstract class SupplierBase : IProcessor, IDisposable
{
protected FtpConnection _Connection;
private void Connect(Credentials credentials)
{
//Create the ftp connection
_Connection = new FtpConnection(credentials.Host, credentials.Username, credentials.Password);
_Connection.Open();
_Connection.Login();
}
private void Disconnect()
{
//Close and dispose the ftp connection
_Connection.Close();
_Connection.Dispose();
_Connection = null;
}
public void Process(Credentials credentials)
{
Connect(credentials);
Execute();
Disconnect();
}
protected abstract void Execute();
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_Connection != null)
{
_Connection.Dispose();
_Connection = null;
}
}
}
#endregion
}
public void MySupplier : SupplierBase
{
//You can add unique supplier properties here.
public string SomeProperty { get; set; }
protected override void Execute()
{
//Implementation here
Console.WriteLine(SomeProperty);
}
}
Here's an example of how you would call it:
Credentials creds = new Credentials()
{
Host = "127.0.0.1",
Username = "test",
Password = "test"
};
MySupplier sup1 = new MySupplier();
sup1.SomeProperty = "Hello";
sup1.Process(creds);
OR
using (MySupplier sup1 = new MySupplier())
{
sup1.SomeProperty = "Hello";
sup1.Process(creds);
}

Related

Which design pattern to use when we have classes that does similar high level functionality but the returns different types in methods?

I have an existing C# console application that takes arguments and based on the arguments
creates an instance of markets (UK, US, MX..) using dependency injection.
Each market class does a 'string GetData()', 'string ProcessData()' and 'bool ExportData()'.
The application was initially created for one eCommerce vendor's markets. Now I am told to modify it for a different vendor that does a different process. The high-level flow remains the same.
'GetData' to fetch records from DB,
'ProcessData' for any transformation or the likes
'ExportData'.
The difference is Getdata() pulls records from DB and maps to an object. I am planning to use Petapoco. 'ProcessData' might return a similar class. 'Exportdata' currently does an API call but for the new vendor, I have to write to a file.
I was reading up on patterns I am totally confused. At first, I thought I needed abstract factory pattern and now I think the factory method is what I should be using but I am not sure if I am doing it right. Need some guidance/review here. A sample cs file I created from my understanding of factory pattern. This code is based on the headfirst code samples.
using System;
using System.Collections.Generic;
using StatusExport.Models;
namespace factorymethod
{
class Program
{
static void Main(string[] args)
{
ClientFactory factory = null;
Console.WriteLine("Enter client code:");
string clientCode= Console.ReadLine();
switch (clientCode.ToLower())
{
case "costco":
factory = new CostcoFactory("accountname", "taskname");
break;
//NEw vendor might be added
//case "walmart"
//factory = new WalmartFactory("taskname", "type");
//break
default:
break;
}
bool status = factory.ProcessData();
Console.ReadKey();
}
}
abstract class Client
{
public abstract string AccountName { get; }
public abstract string Task { get; set; }
//More properties might be added. Some may not even be used by some of the new vendors. For example, Costco Might need accountname and task. Tomorrow if walmart comes, they might not need these two or may need task and a new property 'type'
public abstract List<T> GetData<T>();
public abstract List<T> ProcessData<T>();
public abstract bool ExportData();
}
class CostcoClient : Client
{
public override string AccountName { get; }
public override string Task { get; set; }
public CostcoClient(string accountName, string task)
{
AccountName = accountName;
Task = task;
}
public override List<DBRecord> GetData<DBRecord>() //DBRecord class is specific to Costco.
{
List<DBRecord> dbresult = new List<DBRecord>();
//dbresult = db return data mapped to an object DBRecord using petapoco. Another vendor might have a different class to which DB records are mapped. So the return type can be generic
return asn;
}
public override List<T> ProcessData<T>()
{
throw new NotImplementedException(); //Any data transformation or business logic. Return type might be DBRecord or a new class altogether
}
public override bool ExportData()
{
throw new NotImplementedException();//Call API or write data to file and if success send true else false
}
}
abstract class ClientFactory
{
public abstract bool ProcessData();
}
class CostcoFactory : ClientFactory
{
public string AccountName { get; }
public string Task { get; set; }
public CostcoFactory(string accountname, string task)
{
AccountName = accountname;
Task = task;
}
public override bool ProcessData()
{
CostcoClient gc = new CostcoClient(AccountName, Task);
var result = gc.GetData<DBRecord>();
return true;
}
}
}
Do you think this is the right design approach?
I also want to keep the console project independent of vendor project. So maybe 'StatusExport.Program' for the console application. DLL projects StatusExport.Common to hold the interface and abstract classes' and 'StatusExport.Client(ex:StatusExport.Costco)' for each vendor stuff.
You can create BaseClient class that will contains a basic group of properties, and if you need to add something new - just inherit it. You did right, but i think it's better to change public modifier to protected in your properties AccountName and Task, to give access to them only from child classes.
Actually, you can create a BaseClientModels (request/response) for each method if you are not sure that returning type List will be always actual.
Example:
public abstract class BaseClient
{
#region Properties : Protected
protected abstract string AccountName { get; }
protected abstract string Task { get; set; }
#endregion
#region Methods : Public
public abstract BaseGetDataResponseModel GetData(BaseGetDataRequestModel model);
public abstract BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model);
public abstract BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model);
#endregion
}
public class BaseGetDataResponseModel { }
public class BaseGetDataRequestModel { }
public class BaseProcessDataResponseModel { }
public class BaseProcessDataRequestModel { }
public class BaseExportDataResponseModel { }
public class BaseExportDataRequestModel { }
Then let's look on your class CostcoClient and how it can looks like:
public class CostcoClient : BaseClient
{
#region Properties : Protected
protected override string AccountName { get; }
protected override string Task { get; set; }
protected virtual IDataReader<BaseGetDataRequestModel, BaseGetDataResponseModel> DataReader { get; }
protected virtual IDataProcessor<CostcoClientProcessDataRequestModel, CostcoClientProcessDataResponseModel> DataProcessor { get; }
protected virtual IExportDataHandler<CostcoClientExportDataRequestModel, CostcoClientExportDataResponseModel> ExportDataHandler { get; }
#endregion
#region Constructors
public CostcoClient(string accountName, string task)
{
//set DataReader, DataProcessor, ExportDataHandler
AccountName = accountName;
Task = task;
}
#endregion
#region Methods : Public
public override BaseGetDataResponseModel GetData(BaseGetDataRequestModel model)
{
if (model is CostcoClientGetDataRequestModel clientGetDataRequestModel)
{
return DataReader.ReadData(clientGetDataRequestModel);
}
return null; //wrong type has passed
}
public override BaseProcessDataResponseModel ProcessData(BaseProcessDataRequestModel model)
{
if (model is CostcoClientProcessDataRequestModel clientProcessDataRequestModel)
{
return DataProcessor.ProcessData(clientProcessDataRequestModel);
}
return null;
}
public override BaseExportDataResponseModel ExportData(BaseExportDataRequestModel model)
{
if (model is CostcoClientExportDataRequestModel clientExportDataRequestModel)
{
return ExportDataHandler.Handle(clientExportDataRequestModel);
}
return null;
}
#endregion
}
public class CostcoClientGetDataRequestModel : BaseGetDataRequestModel { }
public class CostcoClientGetDataResponseModel : BaseGetDataResponseModel { }
public class CostcoClientProcessDataRequestModel : BaseProcessDataRequestModel { }
public class CostcoClientProcessDataResponseModel : BaseProcessDataResponseModel { }
public class CostcoClientExportDataRequestModel : BaseExportDataRequestModel { }
public class CostcoClientExportDataResponseModel : BaseExportDataResponseModel { }
public interface IDataReader<TIn, TOut>
{
public TOut ReadData(TIn model);
}
public interface IDataProcessor<TIn, TOut>
{
public TOut ProcessData(TIn model);
}
public interface IExportDataHandler<TIn, TOut>
{
public TOut Handle(TIn model);
}
public class CostcoClientDataReader : IDataReader<CostcoClientGetDataRequestModel, CostcoClientGetDataResponseModel>
{
public CostcoClientGetDataResponseModel ReadData(CostcoClientGetDataRequestModel model)
{
throw new NotImplementedException();
}
}
//and so on
You have to implement IDataReader, IDataProcessor, IExportDataHandler, make your logic and call it from GetData, ProcessData, ExportData methods, as an example, and get instances via dependency injection.
Then, we can change your factory to this:
public interface IClientFactory
{
BaseClient GetClientService(ClientServicesEnum value);
}
public class BaseClientFactory : IClientFactory
{
#region Propertied : Protected
protected virtual IEnumerable<BaseClient> Services { get; }
protected string AccountName { get; }
protected string Task { get; set; }
#endregion
#region Constructors
public BaseClientFactory(IEnumerable<BaseClient> services, string accountname, string task)
{
Services = services;
AccountName = accountname;
Task = task;
}
#endregion
public BaseClient GetClientService(ClientServicesEnum value)
=> Services.First(x => x.GetType().Equals(GetClientServiceByCode()[value]));
private Dictionary<ClientServicesEnum, Type> GetClientServiceByCode()
=> new Dictionary<ClientServicesEnum, Type>()
{
{ ClientServicesEnum.CostcoClient, typeof(CostcoClient) }
};
}
public enum ClientServicesEnum
{
CostcoClient = 1,
Another2 = 2,
Another3 = 3
}
Where
protected virtual IEnumerable<BaseClient> Services { get; }
you can get via DI too, and then get correct ServiceHandler by enum.
And your main function to call all this:
switch (clientCode)
{
case 1:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.CostcoClient);
break;
case 2:
baseClient = ClientFactory.GetClientService(ClientServicesEnum.Another2);
break;
default:
break;
}
bool status = baseClient.ProcessData(null); //your model
The main thing is - you can use more than one pattern, for example one from Creational patterns, and one from Structural.
If i need some help in code architecture i use this:
https://refactoring.guru/
I think, using this example you can remove properties AccountName and Task, because of request models in methods.

class with a lot of methods

I have a class with a lot of functions in it:
MyClass.cs Methods:
Login
Upload file
Upload Folder
Upload large file
Download
and many more.
the problem is that the class grows and grows, and it's starting to be not comfortable to write the whole methods in the same class.
In one hand I want to invoke the functions like:
var myclass=new MyClass();
myclass.SomeMethod();
but the price is to put all the classes in the same file.
I there any design pattern for this? or any other ideas would be appreciated
What about using dependency inversion?
You can then define your main class such as this
public class MyClass
{
public IUserManagement UserManager { get; set; }
public IFileManagement FileManager { get; set; }
public IFolderManagement FolderManager { get; set; }
public MyClass()
{
}
}
With these interfaces
public interface IUserManagement
{
void Login(string username, string password);
void Logout();
}
public interface IFileManagement
{
void UploadFile(string path);
void UploadLargeFile(string path);
void DownloadFile(string filename, string savePath);
}
public interface IFolderManagement
{
void DownloadFolder(string path);
void UploadFolder(string path);
}
The Bulk of your code then goes into classes which perform a specific task such as this.
public class MyFileManager : IFileManagement
{
public void DownloadFile(string filename, string savePath)
{
//Add code here
}
public void UploadFile(string path)
{
//Add code here
}
public void UploadLargeFile(string path)
{
//Add code here
}
}
public class MyUserManager : IUserManagement
{
public void Login(string username, string password)
{
//Add code here
}
public void Logout()
{
//Add code here
}
}
public class MyFoldermanager : IFolderManagement
{
public void DownloadFolder(string path)
{
//Add code here
}
public void UploadFolder(string path)
{
//Add code here
}
}
You can then create your class and call methods likes this
MyClass myClass = new MyClass()
{
FileManager = new MyFileManager(),
FolderManager = new MyFoldermanager(),
UserManager = new MyUserManager()
};
myClass.FileManager.DownloadFile("myfilename", #"c:\path\to\file.txt");
If you wanted, then you could also add wrappers in your MyClass to hide some of the complexity such as this.
//Add in MyClass
public void UploadFile(string path)
{
this.FileManager.UploadFile(path);
}
//Called like this
myClass.UploadFile(#"c:\path\to\other\file.txt");
This way, you can delegate responsibility for each functional area to a specific class which is easier to manage.
Just extract the code inside the methods of your MyClass to other classes. In MyClass you just call/delegate to the other classes.
This way you can reduce the amount of code in MyClass without reducing its method list.

How to properly implement Xamarin NetworkServiceDiscovery via DependencyService?

I've got a Xamarin Cross-Platform App and want to use Android's NetworkServiceDiscovery API.
I tried to implement it according to https://developer.android.com/training/connect-devices-wirelessly/nsd.html
Now, I'm not sure if I did everything right, for example: The android documentation wants you to create a RegistrationListener like this:
Android:
public void initializeRegistrationListener() {
mRegistrationListener = new NsdManager.RegistrationListener() {
#Override
public void onServiceRegistered(NsdServiceInfo NsdServiceInfo) {
// Save the service name. Android may have changed it in order to
// resolve a conflict, so update the name you initially requested
// with the name Android actually used.
mServiceName = NsdServiceInfo.getServiceName();
}
#Override
public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Registration failed! Put debugging code here to determine why.
}
#Override
public void onServiceUnregistered(NsdServiceInfo arg0) {
// Service has been unregistered. This only happens when you call
// NsdManager.unregisterService() and pass in this listener.
}
#Override
public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Unregistration failed. Put debugging code here to determine why.
}
};
}
And I rebuilt it like this in C#:
public class RegistrationListener : NsdManager.IRegistrationListener
{
public string serviceName;
public void Dispose()
{
throw new NotImplementedException();
}
public IntPtr Handle { get; }
public void OnRegistrationFailed(NsdServiceInfo serviceInfo, NsdFailure errorCode)
{
// Registration failed! Put debugging code here to determine why.
}
public void OnServiceRegistered(NsdServiceInfo serviceInfo)
{
// Save the service name. Android may have changed it in order to
// resolve a conflict, so update the name you initially requested
// with the name Android actually used.
serviceName = serviceInfo.ServiceName;
}
public void OnServiceUnregistered(NsdServiceInfo serviceInfo)
{
// Service has been unregistered. This only happens when you call
// NsdManager.unregisterService() and pass in this listener.
}
public void OnUnregistrationFailed(NsdServiceInfo serviceInfo, NsdFailure errorCode)
{
// Unregistration failed. Put debugging code here to determine why.
}
}
I implemented the ResolveListener and DiscoveryListener in the same way.
Then I made a Helper Class with the functions I want to call via DependencyServices:
public class NsdHelper
{
public static readonly string SERVICE_TYPE = "chatTest._tcp";
public DiscoveryListener discoveryListener;
public NsdManager nsdManager;
public NsdServiceInfo nsdServiceInfo;
public RegistrationListener registrationListener;
public ResolveListener resolveListener;
public string SERVICE_NAME { get; set; }
public void InitializeNsd()
{
resolveListener = new ResolveListener();
discoveryListener = new DiscoveryListener();
registrationListener = new RegistrationListener();
resolveListener.ServiceName = SERVICE_NAME;
resolveListener.ServiceInfo = nsdServiceInfo;
discoveryListener.resolveListener = resolveListener;
discoveryListener.nsdManager = nsdManager;
}
public void RegisterService(string sessionName)
{
SERVICE_NAME = sessionName;
// Create the NsdServiceInfo object, and populate it.
nsdServiceInfo = new NsdServiceInfo
{
ServiceName = sessionName,
ServiceType = SERVICE_TYPE,
Port = GenerateFreePort()
};
InitializeNsd();
// The name is subject to change based on conflicts
// with other services advertised on the same network.
nsdManager = (NsdManager) Application.Context.GetSystemService(Context.NsdService);
nsdManager.RegisterService(
nsdServiceInfo, NsdProtocol.DnsSd, registrationListener);
}
private int GenerateFreePort()
{
//setting the ServerSocket to 0 will generate the next free port
var serverSocket = new ServerSocket(0);
return serverSocket.LocalPort;
}
public void DiscoverServices()
{
nsdManager.DiscoverServices(
SERVICE_TYPE, NsdProtocol.DnsSd, discoveryListener);
}
public void StopDiscovery()
{
nsdManager.StopServiceDiscovery(discoveryListener);
}
public NsdServiceInfo GetChosenServiceInfo()
{
return nsdServiceInfo;
}
public void TearDown()
{
nsdManager.UnregisterService(registrationListener);
}
}
And now when I call RegisterService I get the following Error:
I don't know where exactly I've gone wrong! The errors I get while debugging Xamarin Apps also don't help much :(
Inherit your RegistrationListener subclass from Java.Lang.Object
Remove the Handle property and the Dispose methods as those are implemented in the Java.Lang.Object.
public class RegistrationListener : Java.Lang.Object, NsdManager.IRegistrationListener
{
~~~
}
Once you do that a ACW (Android Callable Wrapper) that will be generated to bind your C# implementation so it can be instanced from Java VM.

How to Correctly Invoke WCF ServiceClient Proxy Extensions?

While troubleshooting a wcf client issue I came across some code from #marc-gravell here. I read the article a number of times and then decided to try and see if I could use the code for real so I created a console app and pulled it all in.
Wrapper:
public interface IDisposableWrapper<T> : IDisposable
{
T BaseObject { get; }
}
public class DisposableWrapper<T> : IDisposableWrapper<T> where T : class, IDisposable
{
public T BaseObject { get; private set; }
public DisposableWrapper(T baseObject) { BaseObject = baseObject; }
protected virtual void OnDispose()
{
BaseObject.Dispose();
}
public void Dispose()
{
if (BaseObject != null)
{
try
{
OnDispose();
}
catch
{
// swallow...
}
}
BaseObject = null;
}
}
Extensions:
public static class DisposableExtensions
{
// core "just dispose it without barfing"
public static IDisposableWrapper<T> Wrap<T>(this T baseObject)
where T : class, IDisposable
{
if (baseObject is IDisposableWrapper<T>) return (IDisposableWrapper<T>)baseObject;
return new DisposableWrapper<T>(baseObject);
}
// specific handling for service-model
public static IDisposableWrapper<TProxy> Wrap<TProxy, TChannel>(this TProxy proxy)
where TProxy : ClientBase<TChannel>
where TChannel : class
{
return new ClientWrapper<TProxy, TChannel>(proxy);
}
}
ClientWrapper:
public class ClientWrapper<TProxy, TChannel> : DisposableWrapper<TProxy>
where TProxy : ClientBase<TChannel>
where TChannel : class
{
public ClientWrapper(TProxy proxy) : base(proxy)
{
}
protected override void OnDispose()
{
// lots of code per state of BaseObject
//State != CommunicationState.Faulted;
}
}
Now, when I go to use it, I have this:
static void Main(string[] args)
{
using (var proxy = new PLPlacementServiceClient())
{
var result = proxy.GetDocumentClassForNewBusiness();
}
using (var proxy = new PLPlacementServiceClient().Wrap())
{
var result = proxy.BaseObject.GetDocumentClassForNewBusiness();
}
using (var proxy = new PLPlacementServiceClient().Wrap<>())//what goes here?
{
var result = proxy.BaseObject.GetDocumentClassForNewBusiness();
}
}
When I F-12 the PLPlacementServiceClient().Wrap() method , it takes me to the non-generic implementation in the extensions class
IDisposableWrapper<T> Wrap<T>(this T baseObject)
, but I was expecting to be taken to the other signature
IDisposableWrapper<TProxy> Wrap<TProxy, TChannel>(this TProxy proxy)
So here is my question(s), "How do I invoke the ClientBase version of the extension?"
Thank you,
Stephen
You must specify both type parameters for method Wrap. That is:
using (var proxy = new PLPlacementServiceClient().Wrap<PLPlacementServiceClient,/*type of the service contract PLPlacementServiceClient is implementing*/>())
{
var result = proxy.BaseObject.GetDocumentClassForNewBusiness();
}

Ninject Factory Pattern and Bindings

I am trying to implement the Ninject.Extensions.Factory pattern and my program is telling me my bindings aren't right, but I can't figure out why. I keep getting an "Error activating IHashable. No matching bindings are available, and the type is not self-bindable" exception thrown. The relevant areas of my code are below:
public interface IHashable
{
FileInfo File { get; }
string ComputeHash();
}
public interface IHashableFactory
{
IHashable GetNew(FileInfo file);
}
public class MD5ChecksumProvider : IHashable
{
private FileInfo _file;
public FileInfo File
{
get { return _file; }
}
public MD5ChecksumProvider(FileInfo file)
{
if (file == null)
throw new ArgumentNullException("file");
_file = file;
}
public string ComputeHash()
{
// implementation
}
}
public class AppFileProvider : IAppFileProvider
{
private IHashableFactory _hashFactory;
public IHashableFactory HashProvider
{
get { return _hashFactory; }
}
public AppFileProvider(IHashableFactory hashProviderFactory)
{
_hashFactory = hashProviderFactory;
}
public string GetChecksum(FileInfo fileInfo)
{
var hasher = _hashFactory.GetNew(fileInfo);
return hasher.ComputeHash();
}
}
public class BindingProviders : NinjectModule
{
public override void Load()
{
Bind<IHashable>()
.To<MD5ChecksumProvider>();
}
}
public class BindingFactories : NinjectModule
{
public override void Load()
{
Bind<IHashableFactory>()
.ToFactory();
}
}
// my DI container
public sealed class Container : IDisposable
{
private bool _isDisposed;
private IKernel _kernel;
private BindingFactories _bindingFactories;
private BindingObjects _bindingObjects;
private BindingProviders _bindingProviders;
public Container()
{
_isDisposed = false;
_bindingFactories = new BindingFactories();
_bindingObjects = new BindingObjects();
_bindingProviders = new BindingProviders();
_kernel = new StandardKernel(_bindingObjects, _bindingProviders, _bindingFactories);
}
public T Get<T>()
{
return _kernel.Get<T>();
}
public void Dispose()
{
// nothing worth seeing
}
private void Dispose(bool disposing)
{
// nothing worth seeing
}
}
// the program (composition root)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
using (var container = new Container())
{
var fileProvider = container.Get<IAppFileProvider>();
foreach (var file in files)
{
string hash = fileProvider.GetChecksum(storePath, file); // this line throws "Error activating IHashable. No matching bindings are available, and the type is not self-bindable.""
}
}
}
}
I feel like my bindings are setup correctly but I must be missing something obvious. Any ideas why I'm getting the exception from the above code?
This is caused by a feature of Ninject.Extensions.Factory.
It treats methods which start with Get differently from those which don't.
If you rename IHashableFactory.GetNew to Create or Make everything works fine.
The "Get" feature is described here:
The default instace provider of the extension has the convention that it tries to return an instance using a named binding whenever a method starts with “Get”. E.g. IFoo GetMySpecialFoo() is equal to
resolutionRoot.Get<IFoo>("MySpecialFoo");
Since i think this is not obvious to the user and the exception isn't helpful at all in this regard, i have filed an issue report here

Categories