How to model this in DDD and repository pattern - c#

I want to model service like this
public class FooService
{
public GetById(ISecurityContext context, id)
{
//checking context has right to view
//calling Foo repository to getById
}
public Add(ISecurityContext context,Foo fooEntity)
{
//checking context has right to add
//calling Foo repository to add
}
}
In the above methods i want to pass different type of SecurityContext
So what i have did is
Public Interface ISecurityContext
{
}
UsernamePasswordContext : ISecurityContext
{
public string Username { get; set; }
public string Password { get;set; }
}
SessionContext : ISecurityContext
{
public string SessionId {get ; set;}
}
So In my Account Service i have a method
public class AccountService
{
public Account GetAccountFromSecurityContext(ISecurityContext context)
{
if(context is UsernamePasswordContext)
return GetAccountByUsernamePassword(context.Username,context.Password);
else if (context is SessionContext)
return GetAccountBySessionId(context.SessionId);
// more else if for different type of context
}
}
In the above code i didnt liked so many if else
So i tried introducing polymorphism
So in my ISecurityContext interface i added a GetAccount method which all sub class will implement
Public Interface ISecurityContext
{
Account GetAccount();
}
UsernamePasswordContext : ISecurityContext
{
public string Username { get; set; }
public string Password { get;set; }
public Account GetAccount()
{
//call account service
GetAccountByUsernamePassword(this.Username,this.Password);
}
}
and my account service will become like this
public class AccountService
{
public Account GetAccountFromSecurityContext(ISecurityContext context)
{
context.GetAccount();
}
}
But the problem here is that i am calling a service/repository from my UsernamePasswordContext POCO which voilates DDD
So what are other ways i can model this scenario.

I think you're not far off from the solution. In this case, I would inject a factory into your AccountService that would take on the responsibility of the if..then..else. Then, the factory could use one of many possible solutions.
One change I would make right off is I would make your AccountService implement an interface which should make it easier to inject later. Assuming you're using some IOC container, you shouldn't have to worry too much about dependencies because you're letting the container handle all that.
Here are the pieces you already had, with some minor ajustments:
public class Account
{
//some account information and behavior
}
public interface ISecurityContext
{
}
public class UsernamePasswordContext : ISecurityContext
{
public string Username { get; set; }
public string Password { get; set; }
}
public class SessionContext : ISecurityContext
{
public string SessionId { get; set; }
}
Here's your account service along with it's implementation:
public interface IAccountService
{
Account GetAccountFromSecurityContext(ISecurityContext securityContext);
}
public class AccountService : IAccountService
{
readonly IAccountFactory _accountFactory;
public AccountService(IAccountFactory accountFactory)
{
_accountFactory = accountFactory;
}
public Account GetAccountFromSecurityContext(ISecurityContext securityContext)
{
Account account = _accountFactory.Create(securityContext);
return account;
}
}
So, you can see here that I've injected an IAccountFactory that will handle the actual creation (retrieval, whatever) of the Account object. All we care about at this point is that the account gets created/retrieved... we don't care about how.
There are a few ways you can implement a factory like this. One way is to use a type of strategy pattern where you have a list of widgets that know how to resolve an account. Then you just pick the widget (strategy) that matches and execute it. Something similar to this would be a factory that uses an IOC or service locator to resolve a type that has been registered previously in application configuration.
In the way of an example, here's one possible implementation of IAccountFactory using CommonServiceLocator:
public interface IAccountFactory
{
Account Create(ISecurityContext securityContext);
}
public class ServiceLocatorAccountFactory : IAccountFactory
{
readonly IServiceLocator _serviceLocator;
public ServiceLocatorAccountFactory(IServiceLocator serviceLocator)
{
_serviceLocator = serviceLocator;
}
public Account Create(ISecurityContext securityContext)
{
var resolverType = typeof (IAccountResolver<>).MakeGenericType(securityContext.GetType());
dynamic resolver = _serviceLocator.GetInstance(resolverType);
return resolver.Resolve(securityContext);
}
}
My factory here goes out to the service locator context and grabs whatever resolver matches our security context. Here are a couple examples of possible resolvers:
public interface IAccountResolver<in TSecurityContext> where TSecurityContext : ISecurityContext
{
Account Resolve(TSecurityContext securityContext);
}
public class UsernamePasswordAccountResolver : IAccountResolver<UsernamePasswordContext>
{
readonly IRepository _repository;
public UsernamePasswordAccountResolver(IRepository repository)
{
_repository = repository;
}
public Account Resolve(UsernamePasswordContext securityContext)
{
var account = _repository.GetByUsernameAndPassword(securityContext.Username,
securityContext.Password);
return account;
}
}
public class SessionAccountResolver : IAccountResolver<SessionContext>
{
public Account Resolve(SessionContext securityContext)
{
//get the account using the session information
return someAccount;
}
}
The only thing left is to register the resolvers in your IOC container so that they can be found when the service locator tries to resolve them in the factory.

Related

How to get multiple implementations of the same service interface each in separate scopes

I have an asp.net core 2.2 web application. There is an Interface which is implemented by multiple classes.
services.AddTransient<IHandler, HandlerA>();
services.AddTransient<IHandler, HandlerB>();
Each implementation of IHandler injects scoped EF DbContext and if the same DbContext is shared between different threads, then periodically a floating exception will occur when trying to access the same entity. So I get each handler in a separate scope.
using (var scope = _serviceProvider.CreateScope())
{
var handlers = scope.ServiceProvider.GetServices<IHandler>();
await Task.WhenAll(handlers.Select(async h =>
{
using var internalScope = scope.ServiceProvider.CreateScope();
var handler = internalScope.ServiceProvider
.GetServices<IHandler>()
.First(f => f.Name == h.Name);
await handler.Handle(cancellationToken);
}));
}
This solution seems to work, but I'm not sure if it's optimal. Maybe there is a better way to get multiple implementations of the same service interface in separate scopes?
You do not need to access same entity using different DBContext.
Define services and inject in controllers explained above link. Each service will access DB using same db context through Manager Classes.
You can use service this way as you seeking best practices. And use dependency injection to access the services from controllers.
Define Service, Domain classes and interfaces.
public class Service : Attribute
{
}
//Domain Classes
public class Entity
{
string str {get; set;}
int numb {get; set;}
}
//DBContext
public class DbContext : IdentityDbContext
{
public DbContext(DbContextOptions<DbContext> options)
: base(options)
{
}
public DbSet<Entity> Entities { set; get; }
}
//Interfaces
interface IHandler
{
string method1(Entity entity);
int method2();
}
Implement Interfaces using manager classes
public class HandlerA: IHandler
{
private readonly DbContext _dbContext;
public HandlerA(DbContext dbContext)
{
_dbContext = dbContext;
}
string method1(Entity entity)
{
//access db or business stuff
_dbContext.Entities.Add(entity);
_dbContext.SaveChanges();
}
int method2(){}
}
public class HandlerB: IHandler
{
string method1(Entity entity)
{
//access db or business stuffs
_dbContext.Entities.Remove(entity);
_dbContext.SaveChanges();
}
int method2(){}
int method3(){}
}
//Services
[Service]
public class DoService1Stuff()
{
private readonly HandlerA _handlerA;
public DoService1Stuff(HandlerA handlerA)
{
_handlerA= handlerA;
}
//Implement your task
public Do(Entity entity)
{
_handlerA.method1(entity);
}
}
[Service]
public class DoService2Stuff()
{
private readonly HandlerB _handlerB;
public DoService2Stuff(HandlerB handlerB)
{
_handlerB= handlerB;
}
//Implement your task
public Do(Entity entity)
{
_handlerA.method1(entity);
}
}
Register services through dependency injection in startup.cs
services.AddTransient<IHandler, HandlerA>();
services.AddTransient<IHandler, HandlerB>();
Access services in controllers
[HttpPost]
public async Task<IActionResult> DoStuff1([FromServicec] DoService1Stuff doService1Stuff)
{
var entity= new Entity
{
str="hello",
numb=2020;
};
return Ok(doService1Stuff.Do(entity))
}
//Implement second service as needed.

How to inject different implementations to same interface without conditional/context DI?

I have the following problem and I currently have a solution using conditional dependency injection. I have read that this is a bad idea, such as here in the SimpleInjector docs. I have read a large number of posts now and have seen various things suggesting using Strategy, Factory patterns, etc. What I am really looking for is some specifics - i.e. an example of some code - about how to solve without conditional injection. I need more that "use a factory". Here's a simplified version of my code. This is in an MVC web app, thus the controllers.
public abstract class QAControllerBase : Controller
{
protected readonly QABusinessLayer _blQA;
public QAControllerBase(QABusinessLayer bl)
{
_blQA = bl;
}
[HttpGet]
public ActionResult PPR(string accession, string site)
{
var m = _blQA.popPPRViewModel(accession);
return View(m);
}
}
public class QASouthController : QAControllerBase
{
public QASouthController([QASouthBinding] QABusinessLayer bl) : base(bl)
{
}
// some actions that are specific to South
}
public class QANorthController : QAControllerBase
{
public QANorthController([QANorthBinding] QABusinessLayer bl) : base(bl)
{
}
// some actions that are specific to North
}
public abstract class QABusinessLayer
{
protected readonly IFullBaseRepo _repo;
public QABusinessLayer(IFullBaseRepo repo)
{
_repo = repo;
}
public abstract PPRViewModel popPPRViewModel(string accession);
protected PPRViewModel DoSomeCommonStuff(PPRViewModel model)
{
...
return model;
}
}
public class SouthBusinessLayer: QABusinessLayer
{
public SouthBusinessLayer([QASouthBinding] IFullBaseRepo repo) : base(repo)
{
}
public override PPRViewModel popPPRViewModel(string accession)
{
var m = new PPRViewModel();
// do some stuff that is specific to South
DoSomeCommonStuff(m);
return m;
}
}
public class NorthBusinessLayer : QABusinessLayer
{
public NorthBusinessLayer([QANorthBinding] IFullBaseRepo repo) : base(repo)
{
}
public override PPRViewModel popPPRViewModel(string accession)
{
var m = new PPRViewModel();
// do some stuff that is specific to North
DoSomeCommonStuff(m);
return m;
}
}
and here is the Ninject binding code that is pertinent:
kernel.Bind<QABusinessLayer>()
.To<SouthBusinessLayer>()
.WhenTargetHas<QASouthBinding>()
.InRequestScope();
kernel.Bind<QABusinessLayer>()
.To<NorthBusinessLayer>()
.WhenTargetHas<QANorthBinding>()
.InRequestScope();
The QASouthBinding and QANorthBinding are just simple attributes. I am not asking for Ninject specific example. Any code sample as to how this might be handled without using conditional or context based injection as I am now.
Make your QABusinessLayer class abstract.
Change your startup configuration to:
kernel
.Bind<SouthBusinessLayer>()
.To<SouthBusinessLayer>()
.InRequestScope();
kernel
.Bind<NorthBusinessLayer>()
.To<NorthBusinessLayer>()
.InRequestScope();
Change your controller constructors to accept a concrete business layer type:
public class QANorthController : QAControllerBase
{
public QANorthController(NorthBusinessLayer businessLayer) : base(businessLayer)
{
}
}
public class QASouthController : QAControllerBase
{
public QASouthController(SouthBusinessLayer businessLayer) : base(businessLayer)
{
}
}
Few things:
If Ninject auto-binds concrete types to the same type, then you don't need to manually configure the dependencies during startup.
You may want to use an interface rather than just passing your concrete BusinessLayer type.

Implementing a rich domain model in WCF where the Client objects act as remote facades

I'm working on a WCF project where I want to implement a RICH domain model where the client-side objects act as remote facades for server-side functionality but with certain shared aspects between client/server, such as validation. Let's say I have an Order class with two methods: Save() and Submit(). On the Server the Save() method would write to the database and the Submit() would send the order to a supplier's system.
I want to mirror the rich domain model on the client but instead of doing a database write in the Save() method, I want run the validation code and then call SaveOrder(this) on a WCF service interface. This would follow Fowler's Service layer + Domain model patterns. Ideally I want to write an AbstractOrder base class, implementing all shared functionality and specifying the abstract functions and then implement a ClientOrder, a ServerOrder and a WCF interface IOrderService(with Save(AbstractOrder) and Submit(AbstractOrder)) which acts as the service server-side. The ClientOrder's Save() / Submit() would call the Save/Submit methods on the IOrderService and pass itself during method call.
Is there a way to instruct WCF which objects to instantiate and deserialize the content into? I specifically want to work throughout my entire application with the Abstract version of the object and only upon deserialization figure out whether I need the Client/Server-side version of the object? We've already customized the WCF communication channels: we use protobuf combined with gzip compression for data transport between client/server and Ninject for service instantiation. Ideally I want to offload object instantiation to Ninject.
I specifically don't want the Order class to be a WCF service because I'm dealing with a fairly fat client where a large amount of logic is needed to keep the system perform within set limits and I preferably don't want to end up with an anemic domain model where most logic is stuffed into services.
In code it would like this:
[ServiceContract]
public interface IOrderService
{
[OperationContract]
AbstractOrder GetById(int id);
[OperationContract]
IEnumerable<AbstractOrder> GetBySupplier(int supplierId);
[OperationContract]
void Save(AbstractOrder order);
[OperationContract]
void Submit(AbstractOrder order);
}
public abstract class AbstractOrder()
{
public int Id { get; set; }
public string Description { get; set; }
public List<AbstractOrderline> OrderLines { get; set; }
public abstract void Save();
public abstract void Submit();
}
public class ClientOrder : AbstractOrder
{
public override void Save()
{
ValidateOrThrow();
_service.Save(this);
}
public override void Submit()
{
ValidateOrThrow();
_service.Submit(this);
}
}
public class ServerOrder : AbstractOrder
{
public override void Save()
{
ValidateOrThrow();
_unitOfWork.Save(this);
}
public override void Submit()
{
Save();
_supplierOrderService.Submit(this);
}
}
By default you cannot do this:
// Interface
AbstractOrder IOrderService.GetById(int);
// Service
AbstractOrder OrderService.GetById(int id)
{
return new ServiceOrder(...);
}
// Client
ClientOrder = (ClientOrder)IOrderService.GetById(42);
Because the order that the service returns is not a ClientOrder. Using some reflection and a custom formatter you should be able to come a long way.
Alternatively, you could rely on composition, not inheritance. Introduce an IRepository<T> (or give it a name) in your shared code and create a property for that on your model:
public interface IRepository<T>
{
void Save(T model);
void Submit(T model);
}
public class Order()
{
public int Id { get; set; }
public string Description { get; set; }
public List<AbstractOrderline> OrderLines { get; set; }
[XmlIgnore]
public IRepository<Order> Repository { get; set; }
public void Save()
{
if (Repository == null) { throw new NotSupportedException(); }
Repository.Save(this);
}
public void Submit()
{
if (Repository == null) { throw new NotSupportedException(); }
Repository.Submit(this);
}
}
Now you can inject the service- or client-specific logic thorugh this repository into your model:
// Client-specific implementation
public class ClientOrderRepository : IRepository<Order>
{
private readonly IClientOrderService _service;
public ClientOrderRepository(IClientOrderService clientOrderService)
{
_service = clientOrderService;
}
public void Save(Order order)
{
_service.Save(order);
}
public void Submit(Order order)
{
_service.Submit(order);
}
}
Then your service and client look like this:
// Interface
Order IOrderService.GetById(int);
// Service
Order OrderService.GetById(int id)
{
return new Order(...);
}
// Client
Order order = IOrderService.GetById(42);
order.Repository = new ClientRepository(...);
order.Submit();

Moq framework Func<T,T>

I am new with Moq and TDD and what I am trying to do is to set up method on repository interface.
Here is full story.
I have a domain entity class called Tenant with property BusinessIdentificationNumber
public class Tenant:EntityBase<Tenant>,IAggregateRoot
{
...
public string BusinessIdentificationNumber {get;set;}
...
}
Next I have repository for this entity which interface is like
public interface IRepository<T>
{
...
T FindBy(Func<T,bool> func);
...
}
where the problem is, I use a domain service which holds the rules for creating a tenant and is like
public class TenantCreationService:ITenantCreationService
{
public TenantCreationService(IRepository<Tenant> tenantRepository){...}
public void CreateTenant(Tenant tenant)
{
//from here there is call to IRepository<Tenant>.FindBy(funcMethod);
}
}
And in unit testing where I am testing the TenantCreationService I mock the repository passed to constructor, but I would like to test the feature :
when tenant with BusinessIdentificationNumber already exists in storage or session it should be returned.
So I was trying to do it like
repositoryMock.Setup(x=>x.FindBy(It.Is<Tenant>(t=>t.BusinessIdentificationNumber
== _tenantInTest.BusinessIdentificationNumber))).Returns(_tenantInTest)
but it does not compile. You know what I want to do?
EDIT:
when i try to compile the snippet below
repositoryMock.Setup(e => e.FindBy(t => t.BusinessNumber == _validTenant.BusinessNumber)).Returns(
_validTenant);
i get exception
Unsupported expression: t => (t.BusinessNumber == value(DP.IPagac.UnitTests.DP.IPagac.Module.TenantManagement.TenantDomainServiceTests)._validTenant.BusinessNumber)
I think what you are trying the acheive is this (removed some things that were extraneous for example and created ITenent so it can be mocked dynamically):
[TestFixture]
public class Test
{
[Test]
public void CreateTenentAlreadyExistsTest()
{
var tenentMock = new Mock<ITenant>();
var repoMock = new Mock<IRepository<ITenant>>();
tenentMock.Setup(t => t.BusinessIdentificationNumber).Returns("aNumber");
repoMock.Setup(r => r.FindBy(It.Is<System.Func<ITenant, bool>>(func1 => func1.Invoke(tenentMock.Object)))).Returns(tenentMock.Object);
var tenantCreationService = new TenantCreationService(repoMock.Object);
tenantCreationService.CreateTenant(tenentMock.Object);
tenentMock.VerifyAll();
repoMock.VerifyAll();
}
}
public interface ITenant
{
string BusinessIdentificationNumber { get; set; }
}
public class Tenant : ITenant
{
public string BusinessIdentificationNumber { get; set; }
}
public interface IRepository<T>
{
T FindBy(System.Func<T, bool> func);
}
public class TenantCreationService : ITenantCreationService
{
private readonly IRepository<ITenant> _tenantRepository;
public TenantCreationService(IRepository<ITenant> tenantRepository)
{
_tenantRepository = tenantRepository;
}
public void CreateTenant(ITenant tenant)
{
var existingTenant =
_tenantRepository.FindBy(t => t.BusinessIdentificationNumber == tenant.BusinessIdentificationNumber);
if (existingTenant == null)
{
//do stuff
}
}
}
public interface ITenantCreationService
{
void CreateTenant(ITenant tenant);
}
"when tenant with BusinessIdentificationNumber already exists in storage or session it should be returned." - from this test description I understood that this behavior you should test in repository class not in on service class
In unit test for services you should not test data accesses layer I mean your repositories,
you should just verify that the repository method FindBy was called.
and my suggest Create ITenantRepositry that derive from IRepository interface and from base class Repostiry.

MVC 3 - how to implement a service layer, do I need repositories?

I am currently building my first MVC 3 application, using EF Code First, SQL CE and Ninject.
I have read a lot about using Repositories, Unit of Work and Service Layers. I think I have got the basics sorted out, and I have made my own implementation.
This is my current setup:
Entities
public class Entity
{
public DateTime CreatedDate { get; set; }
public Entity()
{
CreatedDate = DateTime.Now;
}
}
public class Profile : Entity
{
[Key]
public Guid UserId { get; set; }
public string ProfileName { get; set; }
public virtual ICollection<Photo> Photos { get; set; }
public Profile()
{
Photos = new List<Photo>();
}
public class Photo : Entity
{
[Key]
public int Id { get; set; }
public Guid FileName { get; set; }
public string Description { get; set; }
public virtual Profile Profile { get; set; }
public Photo()
{
FileName = Guid.NewGuid();
}
}
SiteContext
public class SiteContext : DbContext
{
public DbSet<Profile> Profiles { get; set; }
public DbSet<Photo> Photos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Interface: IServices
public interface IServices : IDisposable
{
PhotoService PhotoService { get; }
ProfileService ProfileService { get; }
void Save();
}
Implementation: Services
public class Services : IServices, IDisposable
{
private SiteContext _context = new SiteContext();
private PhotoService _photoService;
private ProfileService _profileService;
public PhotoService PhotoService
{
get
{
if (_photoService == null)
_photoService = new PhotoService(_context);
return _photoService;
}
}
public ProfileService ProfileService
{
get
{
if (_profileService == null)
_profileService = new ProfileService(_context);
return _profileService;
}
}
public void Save()
{
_context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Interface
public interface IPhotoService
{
IQueryable<Photo> GetAll { get; }
Photo GetById(int photoId);
Guid AddPhoto(Guid profileId);
}
Implementation
public class PhotoService : IPhotoService
{
private SiteContext _siteContext;
public PhotoService(SiteContext siteContext)
{
_siteContext = siteContext;
}
public IQueryable<Photo> GetAll
{
get
{
return _siteContext.Photos;
}
}
public Photo GetById(int photoId)
{
return _siteContext.Photos.FirstOrDefault(p => p.Id == photoId);
}
public Guid AddPhoto(Guid profileId)
{
Photo photo = new Photo();
Profile profile = _siteContext.Profiles.FirstOrDefault(p => p.UserId == profileId);
photo.Profile = profile;
_siteContext.Photos.Add(photo);
return photo.FileName;
}
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
Database.SetInitializer<SiteContext>(new SiteInitializer());
}
NinjectControllerFactory
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninjectKernel;
public NinjectControllerFactory()
{
ninjectKernel = new StandardKernel();
AddBindings();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return controllerType == null
? null
: (IController)ninjectKernel.Get(controllerType);
}
private void AddBindings()
{
ninjectKernel.Bind<IServices>().To<Services>();
}
}
PhotoController
public class PhotoController : Controller
{
private IServices _services;
public PhotoController(IServices services)
{
_services = services;
}
public ActionResult Show(int photoId)
{
Photo photo = _services.PhotoService.GetById(photoId);
if (photo != null)
{
string currentProfile = "Profile1";
_services.PhotoService.AddHit(photo, currentProfile);
_services.Save();
return View(photo);
}
else
{
// Add error message to layout
TempData["message"] = "Photo not found!";
return RedirectToAction("List");
}
}
protected override void Dispose(bool disposing)
{
_services.Dispose();
base.Dispose(disposing);
}
}
I can build my solution and it seems to be working correctly.
My questions are:
Are there any obvious flaws in my implementation that I am missing?
Will I be able to use this with TDD? Usually I see mocking of repositories but I haven't used that in the above, will that cause issues?
Am I using DI (Ninject) correctly and enough?
I am a hobby programmer, so any comments and/or suggestions to my code are welcome!
You've got the general idea, but it takes a while to really get used to Dependency Injection. I see a number of possible improvements to be made:
Your IServices interface seems unnecessary. I'd prefer to have the controller specify which services it needs (IPhotoService, etc.) via its constructor, rather than using the IServices interface like some kind of strongly-typed service locator.
Did I see a DateTime.Now in there? How are you going to verify that the date gets set correctly in a unit test? What if you decide to support multiple time zones later? How about using an injected date service to produce that CreatedDate?
There is a very good Ninject extension specifically for MVC. It takes care of plugging into the various points that MVC 3 supports for injection. It implements things like your NinjectControllerFactory. All you have to do is make your Global class extend a specific Ninject-based application.
I'd suggest using NinjectModules for setting your bindings, rather than setting them in your ControllerFactory.
Consider using Binding by Convention so that you don't have to explicitly bind each service to its implementation.
Update
The Ninject MVC Extension can be found here. See the README section for an example of how to extend the NinjectHttpApplication. This example uses Modules, which you can read more about here. (They're basically just a place to put your binding code so that you don't violate the Single Responsibility Principle.)
Regarding conventions-based bindings, the general idea is to have your binding code scan the appropriate assemblies and automatically bind things like IPhotoService to PhotoService based on the naming convention. There is another extension here to help with such things. With it, you can put code like this in your module:
Kernel.Scan(s =>
{
s.From(assembly);
s.BindWithDefaultConventions();
});
The above code will auto-bind every class in the given assembly to any interface it implements that follows the "Default" conventions (e.g. Bind<IPhotoService>().To<PhotoService>()).
Update 2
Regarding using the same DbContext for an entire request, you can do something like this (using the Ninject.Web.Common library, which is required by the MVC extension):
Bind<SiteContext>().ToSelf().InRequestScope();
Then any context-dependent services that Ninject creates will share the same instance across a request. Note that I have personally used shorter-lived contexts, so I don't know off the top of my head how you'd force the context to be disposed at the end of the request, but I'm sure it wouldn't be too difficult.
The IServices and Services types seem superfluous to me. If you drop them and change your controller's constructor to be
public PhotoController(IPhotoService photoService, IProfileService profileService)
{
_photoService = photoService;
_profileService = profileService;
}
it will be more apparent what it is actually depending on. Moreover, when you create a new controller, that only really needs IProfileService, you can just pass an IProfileService instead of a full IService, thus giving the new controller a lighter dependency.
I could argue that your services look very much with a repository. Look closely to the interface:
IQueryable<Photo> GetAll { get; }
Photo GetById(int photoId);
Guid AddPhoto(Guid profileId);
Looks very much like a repository to me. Maybe because the example is rather simple but I see the point of having a service if you add use case logic on it. instead of these rather simpel CRUD operations.
And you could argue that EFs DbSet and DbContext are the repositories and unit of work of the app...and at this point we enter a new zone that is somewhat out of scope of the question.

Categories

Resources