Picking Up Repositories With Structuremap - interface

I am not sure how to use StructureMap to scan for all repositories in a particular namespace. Most repositories take the form:
namespace CPOP.Infrastructure.Repositories
{
public class PatientRepository : LinqRepository<Patient>, IPatientRepository
{
}
}
namespace CPOP.Infrastructure.Repositories
{
public class LinqRepository<T> : Repository<T>, ILinqRepository<T>
{
}
}
namespace CPOP.Domain.Contracts.Repositories
{
public interface IPatientRepository : ILinqRepository<Patient>
{
}
}
I tried:
x.Scan(scanner =>
{
scanner.Assembly(Assembly.GetExecutingAssembly());
scanner.ConnectImplementationsToTypesClosing(typeof(ILinqRepository<>));
})
But, it only picks up the LinqRepository class. What's the best way to pick up the various repositories I'll be dumping in there?
And, as per Joshua's reuest, here's an example of use:
namespace CPOP.ApplicationServices
{
public class PatientTasks : IPatientTasks
{
private readonly IPatientRepository _patientRepository;
public PatientTasks(IPatientRepository patientRepository)
{
_patientRepository = patientRepository;
}
public Patient GetPatientById(int patientId)
{
int userId; // get userId from authentication mechanism
return _patientRepository.FindOne(new PatientByIdSpecification(patientId));
}
public IEnumerable<Patient> GetAll()
{
int userId; // get userId from authentication mechanism
return _patientRepository.FindAll();
}
}
}

This can be done with just one line of code in your configuration. Assuming you have this:
Entities:
- Customer
- Order
And have a generic repository model like this:
Repository : IRepository
And have a app services that look like:
public AppService(IRepository<Customer> custRepo, IRepository<Order> orderRepo)
You would have something like this. Notice the bit about using the scanner to hook up your custom repositories.
public class SmRegistry : Registry
{
public SmRegistry()
{
For(typeof (IRepository<>))
.Use(typeof (Repository<>));
//using this will find any custom repos, like CustomerRepository : Repository<Customer>
//Scan(scanner =>
// {
// scanner.TheCallingAssembly();
// scanner.ConnectImplementationsToTypesClosing(typeof (IRepository<>));
// });
}
}
Assuming your Repositories are defined in some other assembly from your application, you can use Registries to hook it all together. Check out this post:
http://blog.coreycoogan.com/2010/05/24/using-structuremap-to-configure-applications-and-components/

Something like:
Assembly ass = Assembly.GetCallingAssembly();
Container.Configure(x => x.Scan(scan =>
{
scan.Assembly(ass);
scan.LookForRegistries();
}));
Then the Registry class:
public sealed class MyRegistry : Registry
{
...

Related

Replacing CastleWindsor with Autofac in .NETCore3.1

I was using CastleWindsor in my ASP.NETCore2.2 WebAPI project and was working fine. I'm migrating to ASP.NETCore3.1 now and it doesn't look like CastleWindor has offical support for that so I decided to move to Autofac with minimal changes but having some issues resolving the dependencies.
In my project, I've maintained very loose coupling between different layers in the application namely, business layer, data layer, and translation layer. All of those layers are in their own assemblies. And then in my main project, I've a folder say "dependencies" which will hold all the DLLs of differnet layers. Additionally, I've a separate project that lists all the interfaces that are implemented by the different layers and which needs to be resolved by the IoC container.
The project having all the interfaces looks like this:
namespace Shared.Interfaces
{
public interface IBusinessLayer<T>
{
....
}
public interface IDataLayer<T>
{
....
}
public interface ITranslationLayer<T>
{
....
}
}
The implementing projects looks like this:
namespace POC.Person.BusinessLayer
{
public class BusinessLayer<T> : IBusinessLayer<T> where T : Models.Person
{
...
}
}
namespace POC.Person.DataLayer
{
public class DataLayer<T> : IDataLayer<T> where T : Models.Person
{
...
}
}
namespace POC.Person.TranslationLayer
{
public class TranslationLayer<T> : ITranslationLayer<T> where T : Models.Person
{
...
}
}
Using Autofac in my migrated .netcore3.1 project, Startup.cs looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//and other codes
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new DependencyResolver());
}
DependencyResolver is a class that inherits from Autofac.Module, which is again in a separate assembly in different project which looks like this:
namespace IOC.Autofac
{
public class DependencyResolver: Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
// get our path to dependencies folder in the main project
var path = Directory.GetCurrentDirectory() + "\\dependencies\\";
//get all the assemblies inside that folder
List<Assembly> assemblies = new List<Assembly>();
foreach (string assemblyPath in Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories))
{
var assembly = System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath);
assemblies.Add(assembly);
}
// Register and resolve the types with the container
builder
.RegisterAssemblyTypes(assemblies.ToArray())
.AsClosedTypesOf(typeof(IBusinessLayer<>))
.AsClosedTypesOf(typeof(IDataLayer<>))
.AsClosedTypesOf(typeof(ITranslationLayer<>))
.AsImplementedInterfaces()
.InstancePerRequest();
}
}
}
I'm getting this error and I've not been able to fix it:
":"Unable to resolve service for type 'Shared.Interfaces.IBusinessLayer`1[Models.Person]' while attempting to activate 'POC.Person.Controllers.PersonController'.","
Inside my controller I've injection which looks like this:
namespace POC.Person.Controllers
{
public class PersonController : ControllerBase
{
private readonly IBusinessLayer<Models.Person> _bl;
public PersonController(IBusinessLayer<Models.Person> bl)
{
_bl = bl;
}
//other codes
}
}
Program.cs looks like this:
namespace POC.Person
{
public class Program
{
public static void Main(string[] args)
{
var host = BuildWebHost(args);
host.Build().Run();
}
public static IHostBuilder BuildWebHost(string[] args)
{
return Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel()
.UseStartup<Startup>()
.UseIIS()
.UseIISIntegration();
;
}).ConfigureAppConfiguration((context, config) =>
{
var builtConfig = config.Build();
});
}
}
}
It looks like with autofac involving generics, registering and resolving the type is not that straight forward?
Autofac does not currently support registering open generics whilst assembly scanning. It's a long-running known issue. You can do assembly scanning, you can register open generics, you can't do both at the same time. There are some ideas in that linked issue on ways some folks have solved it.
Out of the box, the scanning logic would, thus, be reduced to:
builder
.RegisterAssemblyTypes(assemblies.ToArray())
.AsImplementedInterfaces()
.InstancePerRequest();
You need to register generics separately, like:
builder
.RegisterGeneric(typeof(TranslationLayer<>))
.As(typeof(ITranslationLayer<>));

Multiple registration configuration based on string info Autofac

Finally I found the answer, thanks #yeah-buddy
Autofac Resolve constructor instance from Container?
public class Car
{
public Car(IEngine engine) { }
}
public interface IEngine { }
public interface IRepository { }
public class Engine : IEngine
{
public Engine(IRepository repository) { }
}
public class GenericRepository : IRepository
{
public GenericRepository(string carName) { } // !!! Generic Repository write information to carName table, this dependency is keypoint)
}
I want to register:
"Ferrari": Use Engine with GenericRepository("Ferrari")
"Volvo": Use Engine with GenericRepository("Volvo")
I want to resolve:
Get "Ferrari" Car
Get "Ferrari" Repository
How can I achieve this requirement by Autofac?

Autofac wait for module to become available

Because the order of modules being resolved is not guaranteed I'm having some problem achieving this:
I have a module which registers a ScheduleService this ScheduleService is responsible for trigger events at set intervals etc.
I'm able to load in different IScheduable items which i do so using the XML Configuration. The problem that i have, is the IScheduable items require the IScheduleService to be ready so it can register it's self.
So in my <autofac><modules> I have
<module type="Namespace.ScheduleServiceModule, Namespace" />
Then the idea was I could load in as many different ISchedulable items
<module type="SomeNamespace.ScheudleItem1, SomeNamespace />
<module type="SomeNamespace.ScheudleItem2, SomeNamespace />
<module type="SomeNamespace.ScheudleItem3, SomeNamespace />
<module type="SomeNamespace.ScheudleItem4, SomeNamespace />
This is currently how I do it in those scheduleitem modules:
protected override void Load(ContainerBuilder builder)
{
builder.RegisterCallback(registry =>
{
var scheduleService = new TypedService(typeof(IScheduleService));
var registrations = registry.RegistrationsFor(scheduleService);
if (registrations != null && registrations.Any())
{
IComponentRegistration componentRegistration = registrations.First();
componentRegistration.Activated += (sender, args) =>
{
IScheduleService scheduleService = args.Instance as IScheduleService;
if (scheduleService != null)
{
OnScheduleServiceAvailable(args.Context, scheduleService);
}
};
}
});
base.Load(builder);
}
This is the override in each of ScheduleItems
protected override void OnScheduleServiceAvailable(IComponentContext context,
IScheduleService scheduleService)
{
scheduleService.Add(
new SqlSyncSchedulable(Enabled, IntervalMS, ConnectionString, SqlSelect,
context.Resolve<ILoggerService>(),
context.Resolve<IPersonService>(),
context.Resolve<ILoggingEventService>(),
context.Resolve<ITemplateService>(),
context.Resolve<ITemplateLoggingEventService>(),
context.Resolve<IRuntimeSettingsService>()));
}
Which is quite intermittent. The ISchedule item should register itself but the problem is the Schedule service might be registered after those items.
There must be a way to achieve this?
I think your problem is not in the load order of the module, but is instead about dependency design.
You should design your modules and your dependencies in a way that they are not temporally coupled.
One of the many possible designs involves having the schedule service require a list of possible dependencies.
In this design, the responsibilitt of an ISchedule is in defining the parameters of a schedulable operation, you use Autofac Adapter pattern to wrap each schedule into a ISyncSchedulable operation, and the ScheduleService requires a List<ISyncSchedulable> in order to add them at initialization.
As an example (following your example, but not verbatim: I'm trying more to make a point than giving a complete solution):
using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using NUnit.Framework;
namespace Example
{
public interface ISchedule
{
bool Enabled { get; }
long IntervalMs { get; }
string ConnectionString { get; }
string SqlSelect { get; }
}
public class Schedule : ISchedule
{
public bool Enabled
{
get { return true; }
}
public long IntervalMs
{
get { return 100000; }
}
public string ConnectionString
{
get { return "localhost;blabla"; }
}
public string SqlSelect
{
get { return "select 1 as A"; }
}
}
// let's assume SqlSyncSchedulable inherits from a common
// ISyncSchedulable interface
public interface ISyncSchedulable
{
void RunSchedule(ScheduleService scheduleService);
}
public class SqlSyncSchedulable : ISyncSchedulable
{
public ISchedule Schedule { get; private set; }
public OtherService OtherService { get; private set; }
public SqlSyncSchedulable(ISchedule schedule,
OtherService otherService
/*,ILoggerService loggerService
IPersonService personService, */
)
{
Schedule = schedule;
OtherService = otherService;
// read interval and other data from schedule,
// store service references as usual.
}
public void RunSchedule(ScheduleService scheduleService)
{
throw new NotImplementedException();
}
}
public class OtherService
{
}
public class ScheduleService
{
public ScheduleService(IList<ISyncSchedulable> schedulables, OtherService otherService /*, ... other dependencies */)
{
// there is no ADD! Autofac gives you a list of all possible
// ISyncSchedulable components
SyncSchedulables = schedulables;
// ... other dependencies
}
public IList<ISyncSchedulable> SyncSchedulables { get; set; }
// this code is not a proper implementation, nor a scheduler,
// it's just a placeholder
public void RunSchedules()
{
foreach (var schedule in SyncSchedulables)
{
// do your operations, involving ...
schedule.RunSchedule(this);
}
}
}
public class TestModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<ScheduleService>().AsSelf();
builder.RegisterType<OtherService>().AsSelf();
// don't worry about which type should be registered,
// and register each type inheriting from ISchedule
// coming from the current assembly
// You can even use a single registration for all the
// possible implementations of ISchedule, using techniques
// explained in http://docs.autofac.org/en/latest/register/scanning.html
builder.RegisterAssemblyTypes(GetType().Assembly)
.Where(t => t.GetInterfaces().Contains(typeof(ISchedule)))
.AsImplementedInterfaces()
.InstancePerDependency();
// This registration is a partial, because
// SqlSyncChedulable requires a single parameter
// of type ISchedule
builder.RegisterType<SqlSyncSchedulable>()
.AsImplementedInterfaces();
// for each ISchedule class, we register automatically
// a corresponding ISyncSchedulable, which
builder.RegisterAdapter<ISchedule, ISyncSchedulable>(RegisterISyncSchedulableForEachISchedule)
.InstancePerDependency();
}
private ISyncSchedulable RegisterISyncSchedulableForEachISchedule(IComponentContext context, ISchedule schedule)
{
// the parameter of type ISchedule is the corresponding schedule
var scheduleParam = new TypedParameter(typeof(ISchedule), schedule);
// all the other params are resolved automatically by Autofac.
return context.Resolve<ISyncSchedulable>(scheduleParam);
}
}
[TestFixture]
public class AutofacTest
{
[Test]
public void TestServiceResolution()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new TestModule());
var container = builder.Build();
var service = container.Resolve<ScheduleService>();
Assert.That(service.SyncSchedulables[0].GetType(), Is.EqualTo(typeof(SqlSyncSchedulable)));
}
}
}
Please note that the module resolution order is now completely decoupled with the runtime resolution.

What is the best way to move sql-linked methods of entities from a data context to entitiy class?

I like EntityFramework. Usually I create a service class (layout) to put there the logic of interaction with a database. It looks like this:
public class UserService
{
MyDbContext _context;
public UserService(MyDBContext context)
{
_context = context;
}
public void MoveUserToGroup(User user, Group group)) { ... }
}
And I use that so somewhere in my code:
userService.MoveUserToGroup(User user, Group group);
It's good, but I would like my classes to look like this:
public class User
{
// ...
public void AddTo(Group group) { ... }
}
public class Group
{
// ...
public void Add(User user) { ... }
}
And I want to use that so:
user.AddToGroup(group);
What is the best way to do it? DI? Extensions? How to keep database context across my classes?
You would usually map all the related navigational properties of an entity.
public class User
{
public virtual ICollection<Group> Groups { get; set; }
public void AddTo(Group group)
{
Groups.Add(group);
}
}

How to get Castle Windsor to call parameterless constructor?

Currently I have a class that looks like this:
public class MyClass : IMyClass
{
public MyClass()
{
//...
}
public MyClass(IMyRepository repository)
{
//...
}
}
In my config file I have IMyClass registered, but not IMyRepository. My intention is for Windsor to use the constructor that doesn't take any parameters, but I am getting this message:
Can't create component 'MyClass' as it
has dependencies to be satisified.
MyClass is waiting for the following
dependencies:
Services:
- Namespace.IMyRepository which was not registered.
I found another post that says that the container will call the constructor with the most arguments that it can satisfy. So why is it trying to call the constructor with an argument that it doesn't know how to satisfy?
Maybe you're using an old version of Windsor... this works just fine for me:
[TestFixture]
public class WindsorTests {
public interface ISomeInterface {}
public class AService {
public int Id { get; private set; }
public AService() {
Id = 1;
}
public AService(ISomeInterface s) {
Id = 2;
}
}
[Test]
public void Parameters() {
var container = new WindsorContainer();
container.AddComponent<AService>();
var service = container.Resolve<AService>();
Assert.AreEqual(1, service.Id);
}
}