My Startup.cs contains 40 repositories:
services.AddScoped<IUserRepository, UserRepository>();
services.AddScoped<IXRepository, XRepository>();
... 40 more lines ...
I'm trying to find a way to have this mess in a single line, but I'm failing miserably to put my head around this, I have several methods that are not available in the interface. Can someone provide some help? I understand why it is not working, it does not have a concrete repository, but I'm no closer to making this work.
InvalidOperationException: Unable to resolve service for type...
// IRepository.cs
public interface IRepository
{
}
// IUserRepository.cs
public interface IUserRepository : IRepository
{
User ReadToken(string email, string password);
}
// BaseRepository.cs
public class BaseRepository : IDisposable
{
protected IDbConnection PostgreSQL;
public BaseRepository(IDbConnection postgreSQL)
{
PostgreSQL = postgreSQL;
}
public void Dispose()
{
}
}
// UserRepository.cs
public class UserRepository : BaseRepository, IUserRepository
{
public UserRepository(IDbConnection postgreSQL) : base(postgreSQL)
{
}
public User ReadToken(string email, string password)
{
object parameters;
string sql;
parameters = new
{
email,
password
};
sql =
#"
SELECT
user_id AS id,
token
FROM users
WHERE
email = #email AND
password = CRYPT(#password, password) AND
active = TRUE;
";
var user = base.PostgreSQL.Query<User>(sql, parameters).SingleOrDefault();
if (user == null)
throw new UnauthorizedException("User", "User not found.");
return user;
}
}
// UsersController.cs
public class UsersController : ControllerBase
{
protected IUserRepository UserRepository;
public UsersController(IUserRepository userRepository)
{
UserRepository = userRepository;
}
}
// Startup.cs
services.AddTransient<IRepository, BaseRepository>();
You can do that with Scrutor
It offers assembly scanning and decoration extensions for Microsoft.Extensions.DependencyInjection
All those repositories can be summed up to something like this:
services.Scan(x => x.FromAssemblyOf<IAnAssemblyRegistrationMarker>()
.AddClasses(filter => filter.AssignableTo(typeof(IRepository)))
.AsImplementedInterfaces()
.WithScopedLifetime());
IAnAssemblyRegistrationMarker is an empty interface to point at the assembly (project) you want to scan
AddClasses Adds all public, non-abstract classes from the selected assemblies that matches the requirements specified in the
AsImplementedInterfaces Registers each matching concrete type as all of its implemented interfaces
WithScopedLifetime Registers each matching concrete type with Scoped Lifetime (You also have WithSingletonLifetime and WithTransientLifetime)
The only requirement in the code example above is that the repositories implement IRepository in order for you to target only the necessary items.
Disclaimer: I am not associated with Scrutor in any way. I just like the thing.
What you are looking for is called convention based registration. This gives you ability register all types which for example ends with Repository as the interfaces they implement. However the built-in ASP.NET Core IOC is very lightweight and doesn't provide such functionality. So you can either wrap it up with your code which scans all referenced assemblies, look for types by a pattern and then add them to ServiceCollection or you can use different IOC implementation that provides this functionality and supports .Net Core e.g. Autofac, StructureMap etc.
Related
In my onion architecture I've my PresentationLayer who contains a class named LogRabbitMQFilters with differents properties to filter search.
I pass LogRabbitMQFilters in ApplicationLayer by mapper :
public RabbitMQController(IELKService iELKService, IMapper mapper)
{
_iELKService = iELKService;
_mapper = mapper;
}
public async Task<IActionResult> Index(int? id, LogRabbitMQFilters filters)
{
var filtersMapped = _mapper.Map<LogRabbitMQFilters>(filters);
var response = await _iELKService.GetLog(filtersMapped);
/*some code.....*/
}
In ApplicationLayer I map my logRabbitMQFilters to RabbitMQFilters which is declare in Persistance layer and I call my repository like this :
public ELKService(IELKRepository iELKRepository, IMapper mapper)
{
_iELKRepository = iELKRepository;
_mapper = mapper;
}
public async Task<LogResult> GetLog(LogRabbitMQFilters logRabbitMQFilters)
{
var filterMapped = _mapper.Map<RabbitMQFilters>(logRabbitMQFilters);
return await _iELKRepository.GetLogs(filterMapped);
}
It's best approch to do this ? Is there another way to pass my filters class to the repository ? I thought of specification pattern but I don't now if it's a good solution.
DDD and onion architecture share common principles (e.g. domain isolation), however they also draw some different aspects regarding development techniques. It should be pointed out that architectures and designs should serve our goals rather than be the goals themselves.
From your description it seems you have a CRUD-style system. I see no business rules, no domain concepts, no specifications. And that is, of course, not a bad thing.
Isolating domain from other layers (presentation, infrastructure) is beneficial in particular when sophisticated validations are to be applied and business rules are to be enforced within complex entity objects. In your case, however, you map plain object LogRabbitMQFilters (presentation layer) to "itself" (application layer) then to plain object RabbitMQFilters (infrastructure layer). Passing an object as is from presentation layer to application layer is OK in cases like yours (even from a DDD/onion perspective), however:
The second mapping should not exist, since infrastructure layer knows domain and therefore should receive your (presumably) domain entity LogRabbitMQFilters.
LogRabbitMQFilters is actually not a true domain entity since, as mentioned before, it does not apply any business rule.
Flatly mapping objects from one layer to another seems pointless.
I thought of specification pattern but I don't now if it's a good solution
Specification pattern is very useful when we want to pack expressions as business invariants, e.g. having a class named ShortMessage (business invariant) encapsulating an expression such as Message.Length < 42. But with your case I see no use for that, due to the CRUD nature of your application: you simply receive some user properties to function as operands in the context of an ORM object representing a database table, in order to do something like that:
myORMManager
.FetchAll<MyTableObject>()
.Filter(record =>
record.DateDebut == filter.DateDebut &&
record.DateFin == filter.DateFin &&
.
.
record.Message == filter.Message
.
.
.
);
Each of the predicates separated by 'and' operator can be considered as specification, however such specifications are just technical, as they do not convey any business invariant. The object filter can actually be a client request.
To conclude, it is acceptable to develop a single-layer application directly using client properties as operands for database filter expressions, as long as business invariants are out of picture (or at least with low complexity). If you would still like to have a DDD framework, i.e. having an application service (where you may apply simple validations such as DateFin > DateDebut) and a repository object together with the controller object, then I would recommend to have a single class "walking through" all three objects
In regards of complexity it always great to break up the application
according to its responsibilities or concerns.
Considering your code, it seems you are following the industry specified standard. For better clarity I am also adding here a sample code snippet of a standard project architecture.
Controller:
[Route("api/User")]
[ApiController]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet]
[Authorize]
[Route("users")]
public async Task<ActionResult> Users()
{
var users = await _userService.GetAllUsers();
return Ok(new ResponseViewModel { output = "success", msg = "request successful", returnvalue = users });
}
}
Service Interface:
public interface IUserService
{
Task<List<UserViewModel>> GetAllUsers();
}
Service Implementation:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task<List<UserViewModel>> GetAllUsers()
{
return await _userRepository.GetAllUsers();
}
}
Repository Interface:
public interface IUserRepository
{
Task<List<UserViewModel>> GetAllUsers();
}
Repository Implementation:
public class UserRepository : IUserRepository
{
private readonly AppDbContext _dbContext;
private readonly IMapper _mapper;
public UserRepository(AppDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<List<UserViewModel>> GetAllUsers()
{
var users = await _dbContext.Users.ToListAsync();
var userViewModel = _mapper.Map<List<UserViewModel>>(users);
return userViewModel;
}
}
Model:
public class UserViewModel
{
public long user_id { get; set; }
public string full_name { get; set; }
}
Note: Hope above steps guided you accordingly. Additionally, you could also have a look our official document for more information
regarding industry practices.
I'm trying to create the unit test for a class which uses my EF Core DbContext:
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
public DbSet<SomeTable> SomeTables { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
}
}
the class which is consuming that context is simple:
public class MyClass
{
public MyClass(MyContext db)
{
}
}
so, when I try to create
var fakeContext = Substitute.For<MyContext>();
which ends with the error:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: MyContext.
Could not find a parameterless constructor.
which is being raised by base(options) constructor. So, the net approach was to extend the code:
var dbContextOptions = Substitute.For<DbContextOptions<MyContext>>();
dbContextOptions.ContextType.Returns(typeof(MyContext));
var dbContextOptionsExtension = Substitute.For<IEnumerable<IDbContextOptionsExtension>>();
dbContextOptions.Extensions.Returns(dbContextOptionsExtension);
var myFakeContext = Substitute.For<MyContext>(dbContextOptions);
but it generates more and errors. So, how to fix it ?
You haven't elaborated on the additional errors so I can't provide a specific answer, however trying to mock a DbContext properly is difficult. IMO there are two options.
1) Use the Microsoft in-memory provider.
2) If you want to use a mocked DbContext using NSubstitute, use a pre-existing library that does the mocking for you. There are a few around such as EntityFrameworkCore.Testing.NSubstitute (disclaimer - I am the author).
The in-memory provider is not a complete implementation, it can't do relational operations and there are a swag of LINQ operations it doesn't support, so depending on your use cases the latter may be a better solution.
If you have a specific error/use case in mind pop it up and I may be able to provide a better answer.
Ok, I've used the InMemory provider:
var options = new DbContextOptionsBuilder<AgreementContext>()
.UseInMemoryDatabase("fakeDb")
.Options;
var agreementContext = Substitute.For<MyContext>(options);
I've not worked with .Net Core before but have a lot of experience with MVC and Entity Framework. My project has four distinct folders, API, DTO, Repository and WEB. The DTO folder has many model files which fits the data model. The API folder has a Controller file called ReferenceDataController and looks like this
[Route("api/[controller]")]
[ApiController]
public class ReferenceDataController : ControllerBase
{
private readonly IReferenceDataRepository _repository;
public ReferenceDataController(IReferenceDataRepository repository)
{
_repository = repository;
}
// GET api/values
[HttpGet]
public ActionResult<ReferenceData> GetReferenceData()
{
return _repository.GetReferenceData();
}
I'm told that if I call this GET method it will return a data object. How do I call this method in the API folder from my HomeController in my WEB folder?
First, in your web project, you need to do a little setup. Add a class like the following:
public class ReferenceDataService
{
private readonly HttpClient _httpClient;
public ReferenceDataService(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public async Task<List<ReferenceData>> GetReferenceDataAsync(CancellationToken cancellationToken = default)
{
using (var response = await _httpClient.GetAsync("/api/referencedata", cancellationToken))
{
if (response.IsSuccessStatusCode())
{
return await response.Content.ReadAsAsync<List<ReferenceData>>();
}
return null;
}
}
}
Then, in ConfigureServices in Startup.cs:
services.AddHttpClient<ReferenceDataService>(c =>
{
c.BaseAddress = new Uri("https://api.example.com");
// Use the actual URL for your API here. You also probably want to get this
// from `Configuration` rather than hard-coding it.
});
Finally, inject ReferenceDataService into your HomeController:
public class HomeController : Controller
{
private readonly ReferenceDataService _referenceDataService;
public HomeController(ReferenceDataService referenceDataService)
{
_referenceDataService = referenceDataService ?? throw new ArgumentNullException(nameof(referenceDataService));
}
// In your action(s):
// var data = await _referenceDataService.GetReferenceDataAsync(HttpContext.RequestAborted);
}
This is the quick and dirty code here. Things you should consider for improvement:
Use an interface for your service class(es), i.e. IReferenceDataService. That will make testing easier. In ConfigureServices:
services.AddHttpClient<IReferenceDataService, ReferenceDataService>(...);
Then, inject IReferenceDataService instead.
You can and should use the Polly extensions with AddHttpClient to support retry and exception handling polices. At the very least, you'd definitely want to add AddTransientHttpErrorPolicy:
services.AddHttpClient<ReferenceDataService>(...)
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}));
That will handle transient errors like temporarily being unable to connect to the API because it was restarted or something. You can find more info and more advanced configuration possibilities at the docs.
You should be using separate DTO classes. For brevity, I just used your (presumed) entity class ReferenceData. Instead, you should always use customized DTO classes that hold just the pieces of the data that you need to be available via the API. This way, you can control things like serialization as well as custom validation schemes, without conflicting with what's going on with your entity class. Additionally, the web project would only need to know about ReferenceDataDTO (or whatever), meaning you can share a library with your DTOs between the API and web projects and keep your DAL completely out of your web project.
at this moment we are migrating from Entityspaces(Tiraggo) into Servicestack Ormlite.
One point is the way to open and close the DBConnection.
I apologize for the comparission but it is useful for the question. In Tiraggo, inside my wep application, in the global.asax.cs I put this:
protected void Application_Start(object sender, EventArgs e)
{
Tiraggo.Interfaces.tgProviderFactory.Factory = new Tiraggo.Loader.tgDataProviderFactory();
}
In web.config exists the section for Tiraggo, the connectionstring and the ORM does the rest.
During the use of the classes we just do this:
User user = new User(); user.Name="some"; user.Comment = "some"; user.Save();
I dont open, close a DBConnection. It is transparent for the programmer. Just create the instance classes and use them.
I define a class, a repository and that's all. No DB definition or interaction. Everything happens in a webforms app, with the datalayer inside the same app.
When we are migrating to Servicestack ORMLite, I see the open of the DBConnection is too inside the globlal.asax.cs, but it references a Service no a class or repository.
public class AppHost : AppHostBase
{
public AppHost() : base("Hello ServiceStack", typeof(HelloService).Assembly) {}
public override void Configure(Container container) {}
}
So my first question is: how can I use it if I dont have a Service (HelloService), I have just classes or repositories. So I cant use this technique for DBConnection my DB.
I also see that accesing the Db, I need a open connection. I try to do this:
using (var Db = DbFactory.Conn.OpenDbConnection())
{
return Db.SingleById<Anio>(id);
}
Later, I found a sample like I was looking for, the Pluralsight video ".NET Micro ORMs" Steve Mihcelotti, and he just open the connection, but never Close it, never use the "using" syntax.
So my 2 questions are:
1) Is there a way for open the DbFactory(dbConnection) like all the samples using servicestack ormlite, but without using a Services ( I dont use Services, I want to use Ormlite but just with classes and repositories)
2) Is there a way for connnect to the database in each trip to the class or repository without using the "using" syntax, or
3) the only way is the one showed in the Pluralsight video, ie. open the connection throw the using syntax in each Method (trip to the class)
I hope I was clear.
The nice thing about IDbConnectionFactory is that it's a ThreadSafe Singleton which can be safely passed around and referenced as it doesn't hold any resources open itself (i.e. DB Connections).
A lazy pattern which provides a nice call-site API is the RepositoryBase class:
public abstract class RepositoryBase : IDisposable, IRepository
{
public virtual IDbConnectionFactory DbFactory { get; set; }
IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = DbFactory.OpenDbConnection()); }
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
This is the same pattern ServiceStack's Service class uses to provide a nice API that only gets opened when it's used in Services, e.g:
public class MyRepository : RepositoryBase
{
public Foo GetFooById(int id)
{
return Db.SingleById<Foo>(id);
}
}
Note: This pattern does expect that your dependencies will be disposed after use.
Another alternative is to leverage your IOC to inject an Open IDbConnection with a managed lifetime scope, e.g:
container.Register<IDbConnection>(c =>
c.Resolve<IDbConnectionFactory>().OpenDbConnection())
.ReusedWithin(ReuseScope.Request);
The life-cycle of the connection is then up to your preferred IOC.
Without Using an IOC
Whilst it's typically good practice to use an IOC to manage your Apps dependencies and provide loose-coupling, if you don't want to use an IOC you can also make DbFactory a static property, e.g:
public abstract class RepositoryBase : IDisposable
{
public static IDbConnectionFactory DbFactory { get; set; }
IDbConnection db;
public virtual IDbConnection Db
{
get { return db ?? (db = DbFactory.OpenDbConnection()); }
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
Which you can just initialize directly on startup, e.g:
protected void Application_Start(object sender, EventArgs e)
{
RepositoryBase.DbFactory = new OrmLiteConnectionFactory(
connectionString, SqlServer.Provider);
}
Note: If you're not using an IOC then you want to make sure that instances of your repository classes (e.g. MyRepository) are disposed of after use.
I think this falls under the concept of contextual binding, but the Ninject documentation, while very thorough, does not have any examples close enough to my current situation for me to really be certain. I'm still pretty confused.
I basically have classes that represent parameter structures for queries. For instance..
class CurrentUser {
string Email { get; set; }
}
And then an interface that represents its database retrieval (in the data layer)
class CurrentUserQuery : IQueryFor<CurrentUser> {
public CurrentUserQuery(ISession session) {
this.session = session;
}
public Member ExecuteQuery(CurrentUser parameters) {
var member = session.Query<Member>().Where(n => n.Email == CurrentUser.Email);
// validation logic
return member;
}
}
Now then, what I want to do is to establish a simple class that can take a given object and from it get the IQueryFor<T> class, construct it from my Ninject.IKernel (constructor parameter), and perform the ExecuteQuery method on it, passing through the given object.
The only way I have been able to do this was to basically do the following...
Bind<IQueryFor<CurrentUser>>().To<CurrentUserQuery>();
This solves the problem for that one query. But I anticipate there will be a great number of queries... so this method will become not only tedious, but also very prone to redundancy.
I was wondering if there is an inherit way in Ninject to incorporate this kind of behavior.
:-
In the end, my (ideal) way of using this would be ...
class HomeController : Controller {
public HomeController(ITransit transit) {
// injection of the transit service
}
public ActionResult CurrentMember() {
var member = transit.Send(new CurrentUser{ Email = User.Identity.Name });
}
}
Obviously that's not going to work right, since the Send method has no way of knowing the return type.
I've been dissecting Rhino Service Bus extensively and project Alexandria to try and make my light, light, lightweight implementation.
Update
I have been able to get a fairly desired result using .NET 4.0 dynamic objects, such as the following...
dynamic Send<T>(object message);
And then declaring my interface...
public interface IQueryFor<T,K>
{
K Execute(T message);
}
And then its use ...
public class TestCurrentMember
{
public string Email { get; set; }
}
public class TestCurrentMemberQuery : IConsumerFor<TestCurrentMember, Member>
{
private readonly ISession session;
public TestCurrentMemberQuery(ISession session) {
this.session = session;
}
public Member Execute(TestCurrentMember user)
{
// query the session for the current member
var member = session.Query<Member>()
.Where(n => n.Email == user.Email).SingleOrDefault();
return member;
}
}
And then in my Controller...
var member = Transit.Send<TestCurrentMemberQuery>(
new TestCurrentMember {
Email = User.Identity.Name
}
);
effectively using the <T> as my 'Hey, This is what implements the query parameters!'. It does work, but I feel pretty uncomfortable with it. Is this an inappropriate use of the dynamic function of .NET 4.0? Or is this more the reason why it exists in the first place?
Update (2)
For the sake of consistency and keeping this post relative to just the initial question, I'm opening up a different question for the dynamic issue.
Yes, you should be able to handle this with Ninject Conventions. I am just learning the Conventions part of Ninject, and the documentation is sparse; however, the source code for the Conventions extension is quite light and easy to read/navigate, also Remo Gloor is very helpful both here and on the mailing list.
The first thing I would try is a GenericBindingGenerator (changing the filters and scope as needed for your application):
internal class YourModule : NinjectModule
{
public override void Load()
{
Kernel.Scan(a => {
a.From(System.Reflection.Assembly.GetExecutingAssembly());
a.InTransientScope();
a.BindWith(new GenericBindingGenerator(typeof(IQueryFor<>)));
});
}
}
The heart of any BindingGenerator is this interface:
public interface IBindingGenerator
{
void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel);
}
The Default Binding Generator simply checks if the name of the class matches the name of the interface:
public void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel)
{
if (!type.IsInterface && !type.IsAbstract)
{
Type service = type.GetInterface("I" + type.Name, false);
if (service != null)
{
kernel.Bind(service).To(type).InScope(scopeCallback);
}
}
}
The GenericBindingGenerator takes a type as a constructor argument, and checks interfaces on classes scanned to see if the Generic definitions of those interfaces match the type passed into the constructor:
public GenericBindingGenerator(Type contractType)
{
if (!contractType.IsGenericType && !contractType.ContainsGenericParameters)
{
throw new ArgumentException("The contract must be an open generic type.", "contractType");
}
this._contractType = contractType;
}
public void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel)
{
Type service = this.ResolveClosingInterface(type);
if (service != null)
{
kernel.Bind(service).To(type).InScope(scopeCallback);
}
}
public Type ResolveClosingInterface(Type targetType)
{
if (!targetType.IsInterface && !targetType.IsAbstract)
{
do
{
foreach (Type type in targetType.GetInterfaces())
{
if (type.IsGenericType && (type.GetGenericTypeDefinition() == this._contractType))
{
return type;
}
}
targetType = targetType.BaseType;
}
while (targetType != TypeOfObject);
}
return null;
}
So, when the Conventions extension scans the class CurrentUserQuery it will see the interface IQueryFor<CurrentUser>. The generic definition of that interface is IQueryFor<>, so it will match and that type should get registered for that interface.
Lastly, there is a RegexBindingGenerator. It tries to match interfaces of the classes scanned to a Regex given as a constructor argument. If you want to see the details of how that operates, you should be able to peruse the source code for it now.
Also, you should be able to write any implementation of IBindingGenerator that you may need, as the contract is quite simple.