Search code examples
c#asp.net-mvccastle-windsorhangfire

Castle.Windsor - why does the name needs to be similar to the interface?


I noticed this interesting scenario when trying to create a new HangFire job in my ASP.NET MVC application.

// this is the interface for the HangFire job.
public interface ICsvExportService
{
    void ExportCsvToEmail();
}

// this is the implementation of the above interface.
public class ExportService : ICsvExportService
{
// code goes here.
}


RecurringJob.RemoveIfExists("My CSV exports");
        RecurringJob.AddOrUpdate<ICsvExportService>(
            "Send CSV exports",
            x => x.ExportCsvToEmail(),
            Cron.Daily(8));

While I was trying to test this locally I got the error below:

Exception thrown: "Castle.MicroKernel.ComponentNotFoundException" in HangFire.Core.dll No component for supporting the service ICsvExportService was found.

After 30 minutes of trying different solutions I renamed the file: ExportService to CsvExportService and the magic happened! It worked!

Can someone explain why do I need to use the same name as the interface in order to make the DI container recognizes the actual implementation class?

Castle.Core version is 3.3.3 for .NET 4.5 Castle.Windsor version is 3.3.0 for .NET 4.5

The code for registration can be found below:

container.Register(
            Classes.FromThisAssembly()
                .Where(type => type.Name.EndsWith("Service"))
                .WithServiceDefaultInterfaces()
                .Configure(c => c.LifestyleTransient()));

Many thanks.


Solution

  • You don't show how you're registering your interfaces and classes, but it's likely you're using the DefaultInterfaces convention.

    This method performs matching based on type name and interface's name. Often you'll find that you have interface/implementation pairs like this: ICustomerRepository/CustomerRepository, IMessageSender/SmsMessageSender, INotificationService/DefaultNotificationService. This is scenario where you might want to use DefaultInterfaces method to match your services. It will look at all the interfaces implemented by selected types, and use as type's services these that have matching names. Matching names, means that the implementing class contains in its name the name of the interface (without the I on the front).

    There are a number of different conventions, but you may just be looking for AllInterfaces:

    When a component implements multiple interfaces and you want to use it as a service for all of them, use WithService.AllInterfaces() method.