Get instance of objects based on other values without using service location - c#

I am using a Unit of Work pattern in my mvc 3 app with Ninject. I have run into a problem where i'm having difficulty solving it without using new or service location of some kind.
I am using an abstract base model called MyModel which has 2 concrete subclasses MyModel1 and MyModel2. These need to get sent to the view based on a value set in the users record.
public class MyController : Controller
{
private IUnitOfWork _unitOfWork;
public MyController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; }
...
public ActionResult MyMethod() {
var user = _unitOfWork.Get(user)
if (user.myprop == somevalue)
{
return View(new MyModel1());
}
return View(new MyModel2());
}
This works fine (although I don't like it, it's simple and works. The problem is that using new is an anti-pattern when using Dependancy Injection. Additionally, I now want the models to initialize themselves (from the database) so I need to inject the IUnitOfWork into the constructor of the models. I could, of course do this:
if (user.myprop == somevalue)
{
return View(DependancyResolver.Current.GetService(typeof(MyModel1)));
}
But Service Location is also an anti-pattern.
Any suggestions on how to solve this?

Using new is not an anti pattern for DI if used correctly. There is absolutely no problem to use new to create data containers such as view models.
But it is an anti pattern for MVC applications to have logic or data retrieving code in your view models so that they need dependencies. All this stuff belongs outside into the controller or some services. The data is assigned preformatted to the view model from outside.

Additionally, I now want the models to initialize themselves (from the
database) so I need to inject the IUnitOfWork into the constructor of
the models
No. You should not pass any models to your views. You pass VIEW MODELS only. View models are dumb. They only contain preformatted data for the view to display. If you used AutoMapper for example you could have externalized this into the mapping layer and your controller could become:
public ActionResult MyMethod() {
var user = _unitOfWork.Get(user)
var userViewModel = Mapper.Map<User, UserViewModel>(user);
return View(userViewModel);
}

Related

One controller for different area views

I have MVC5 app which has 2 areas: area1 and area2.
Some views in those areas are using code from controller which is actually same for view in area1 and view in area2.
Now I have 2 controllers per each area, but as I mentioned, the code is very same.
How can I use one Controller per each view in the area 1 and 2 to avoid code duplicity and have simpler maintainability?
Areas are just a layer, but they can still interact with each other and the application at large. If you need to share a controller, you can simply subclass it. Better yet, create an abstract controller outside of the areas and inherit each area's controller from that.
As far as views go, Razor has a very easy convention for handling overrides and fallbacks. It searches multiple directories, based on convention, for the required view and stops only when it finds a match.
For example, if you placed the view in Views\Shared, the last resort fallback, it can be used literally anywhere in your application, including each of your areas. The order of ops for view location is:
Areas\[AreaName]\Views\[ControllerName]
Areas\[AreaName]\Views\Shared
Views\[ControllerName]
Views\Shared
Razor will go down the list looking for the view in each location until it finds it.
You keep the separate controllers as they serve their purposes in the MVC framework. However, you can export much of the code in the controllers to service classes and each controller uses the services as needed -- Now you avoid code duplicity and have simpler maintainability.
Controllers
public class HomeController : Controller
{
private IFooService service;
public HomeController()
{
this.service = new FooService(dbContext);
}
public ActionResult CalculateFoo(int id)
{
var foo = this.service.CalculateFoo(id);
return View(foo);
}
}
public class FooController : Controller
{
private IFooService service;
public FooController()
{
this.service = new FooService(dbContext);
}
public ActionResult Details(int id)
{
var foo = this.service.CalculateFoo(id);
return View(foo);
}
}
Service
public class FooService : IFooService
{
private DbContext db;
public FooService(DbContext db)
{
this.db = db;
}
public Foo CalculateFoo(int id)
{
var foo = this.db.Foo.First(f => f.id == id);
// do stuff
return foo;
}
}

Using a DbContext variable from one Controller to Another

Hi I am using MVC 4 and C# to develop an application that has two controllers:
The first one is called Business, it has a method called Create that calls a method called CreatePartner from another Controller named PartnerController.
public class BusinessController : Controller
{
private storeContext db = new storeContext();
public ActionResult Create(Business business)
{
//Some stuff here
PartnerController pt = new PartnerController();
pt.CreatePartner(int partner_id);
//Here is another stuff that uses db DbContext variable
return RedirectToAction("Index");
}
}
This is the second controller Called Partner
public class PartnerController : Controller
{
private storeContext db = new storeContext();
public void CreatePartner(int partner_id)
{
//Some interesting stuff
}
}
Each controllers has its Dispose() method
The Problem is: After I called the CreatePartnet method from Business controller I try to use the db variable again to save other data but it throws me the following exception:
The operation can not be completed because the DbContext has been disposed
-What is the best way to Use methods from one controller to another that has the same DbContext variable name?.
-Something strange happens: My stuff works locally but when I publish my code in the IIS server is when the app throws that exception.
Thanks!
Might I suggest an alternative approach?
Controllers are not very good places for business logic; that is they're not very good places for "doing stuff". It's often demonstrated in MVC tutorials and examples in this manner but it's really only good for getting into MVC quickly - it's not very good practice.
Furthermore Controllers aren't really supposed to have methods to be called - from themselves or called from another Controller. Controllers should really just contain their Actions.
Instead, extract your logic to an external class. A Service is a design pattern in which commonly used business logic is abstracted away. That way things can have a reference to the service and execute the logic without knowing anything about the implementation.
Observe:
IPartnerService
public interface IPartnerService
{
void CreatePartner(int partnerId);
}
DefaultPartnerService
public class DefaultPartnerService : IPartnerService
{
private StoreContext db;
public DefaultPartnerService()
{
db = new StoreContext();
}
public void CreatePartner(int partnerId)
{
// Something interesting
}
}
BusinessController
public class BusinessController : Controller
{
private IPartnerService _partnerService;
public BusinessController()
{
_partnerService = new DefaultPartnerService();
}
public ActionResult Create(Business business)
{
_partnerService.CreatePartner(business.PartnerId);
return RedirectToAction("Index");
}
}
Of course this approach is also greatly simplified for educational purposes. It's not best practice yet, but it might put you on the right track. Eventually you'll discover problems with this approach and you'll gravitate to reading about Repositories, Unit of Work, Dependency Injection and so on.

MVC repository architecture and accessing different tables

Thank you for helping me understand some of this stuff:
Say I have 2 controllers in an MVC application -
1 controls viewModels related to salespeople
1 controls viewModels related to sales
Each have a their own repository, which access data using Entity framework (code first)
both repositories are set up to handle dependency injection, but also have 0 argument constructors with defaults to use the appropriate EF dataAccess.
the salespeople controller uses a _salesPeopleRepository.getAllSalesPeople() function which returns a List of salespeople to populate an index view.
the sales controller needs to access the same list to populate a dropdownlist.
there are several ways to get the information to the sales controller, and I was wondering which options would be considered best practice:
a) In the controller
db = new DataContext();
_saleRepos = new SalesRepository(db);
_salesPeople = new SalesPeopleRepository(db);
.....
modelA.SalePeopleSelectList = SelectList(_salesPeople.getAllSalesPeople(),"id","name")
b) in the SalesRepository - either using EF itself:
public IEnumerable<salesPerson> getAllSalesPeople()
{
return _db.SalesPeople.ToList();
}
c) or instantiating and injecting the same data access object before calling the function
public IEnumerable<salesPerson> getAllSalesPeople()
{
return (new SalesPersonRepository(_db)).getAllSalesPeople();
}
Edit
If the answer is a), how should custom buisiness logic be called from 1 repository - say for instance sales has a storeId and the repository checks that the storeId entered for the sale matches the storeId for the salesPerson. Should the salesPerson object used for buisness logic purposes (within the salesRepository) be accessed via the salesPerson repository, or directly from the dataContext object?
Thank you for your thoughts and experience
It doesn't make sense to have your SalesRepository retrieving data from the SalesPerson table. That data access logic ought to be centralized in the SalesPeopleRepository. Duplicating the method across repositories will just muddy the water, in my opinion.
So why not have both the SalesRepository and SalesPeopleRepository used in your Sales Controller? I would just instantiate an instance of the SalesPeopleRepository and use the method already defined in there.
Also, if your Controllers are using dependency injection, you could just have the repositories passed in to the constructor:
public SalesController (ISalesRepository salesRepository, ISalesPeopleRepository salesPeopleRepository)
{
this._salesRepository = salesRepository;
this._salesPeopleRepository = salesPeopleRepository;
}
Best Practice always depends on the context, but a combination of the Repository and Unit Of Work patterns are regularly used on top of EF.
Usage:
using (var uow as new DataContext()) {
var salesPeople = new SalesPeopleRepository(uow);
// ...
uow.Commit(); // If changes must be committed back to the database
}
Implementation:
public interface IUnitOfWork {
public void Commit();
}
public class DataContext : IUnitOfWork {
public void Commit() {
this.SaveChanges();
}
}
public class SalesPeopleRepository {
private DataContext _db
public SalesPeopleRepository(IUnitOfWork uow) {
_db = uow as DataContext;
}
public IEnumerable<SalesPerson> GetAllSalesPeople() {
return _db.SalesPeople.ToList();
}
}
First, the C# naming convention should be followed: getAllSalesPeople() should be GetAllSalesPeople. Second, IoC Container and dependency injection would be the best practice in this case.
The item a should be avoied because DataContext and Repositories are created directly in controller, it is violating dependency injection and make your code tight coupling with Repositories and DataContext and no way to mock for unit testing. Instead, repositories should be injected into controllers and DataContext should be injected into Repositories.
public Repository(DataContext dataContext)
{
_dataContext = dataContext;
}
public SalesController(ISalesRepository salesRepository,
ISalesPeopleRepository salesPeopleRepository)
{
_salesRepository = salesRepository;
_salesPeopleRepository = salesPeopleRepository;
}
The lifetime management for DataContext should be kept in per request in IoC Container instead of creating directly in controller, most of IoC Container supports this. Don't know which IoC container you use, but my faves is: Autofac and Windsor.
For the item c, you are making the business logic leak to Repository layer, instead, business logic should be in controller or in separate layer. Repository just deal with CRUD operation with your database.

MVC - Controller to Service Layer Communication

In my ASP.net mvc app I am using a Service Layer and Repositories to keep my controllers thin. A typical details read only view looks like this:
public ActionResult Details(int id)
{
var project = _projectService.GetById(id);
return View(Mapper.Map<Project, ProjectDetails>(project));
}
Service Layer:
public class ProjectService : IProjectService
{
public Project GetById(int id)
{
var project = _projectRepository.GetProject(id);
// do some stuff
return project;
}
}
public class ProjectRepository : IProjectRepository
{
public Project GetProject(int id)
{
return context.Projects.Find(id);
}
}
Moving from the service layer to the view model is pretty easy because of automapper, which can flatten things pretty easily. Moving the other direct, from the view model to pass into my service layer is where I struggle to come up with a good solution.
In a situation like a Create action, what is a good approach for this?
[HttpPost]
public ActionResult Create(CreateProjectViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// TODO
return RedirectToAction("Index");
}
I'm pretty sure that the service layer should not know anything about view models, but I also don't think that AutoMapper works well in this scenario either, since it's not good at taking a flat model and making it into a complex object.
What should my controller look like to communicate with the service layer? I want to keep the code in the controller as light as possible.
You could define a bidirectional mapping and then go the other way around:
[HttpPost]
public ActionResult Create(CreateProjectViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
Project project = Mapper.Map<CreateProjectViewModel, Project>(model);
// pass the project entity to your service layer
_projectService.Create(project);
return RedirectToAction("Index");
}
or if you are updating an entity you might first want to fetch the existing entity that you want to update from the service:
[HttpPost]
public ActionResult Update(CreateProjectViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
Project project = _projectService.GetById(model.Id);
Mapper.Map<CreateProjectViewModel, Project>(model, project);
// pass the project entity to your service layer
_projectService.Update(project);
return RedirectToAction("Index");
}
The only way I have seen this done so far is to manually create a bunch of model transformation classes, for example:
public interface ITransformer<out To, in From>
where To : class
{
To Transform(From instance);
}
public class SomeDataToSomeViewModelTransformer : ITransformer<SomeViewModel, SomeDataModel>
{
public SomeViewModel Transform(SomeDataModel instance)
{
return new SomeViewModel
{
InvitationId = instance.Id,
Email = instance.EmailAddress,
GroupId = instance.Group.Id
};
}
}
And another Transformer implementation to go back the other way (ViewModel -> DataModel).
And having the Controller know to call the correct transformer.
I +1 your question because I would love to see a nice clean way to do this too, without having to manually write a bunch of code to map models.
If your service layer is solely dedicated to support your MVC application and no other clients you could consider using the objects passed through and from your service layer as part of your viewmodels. This would obviate the need to automap the inbound calls as you'd be sending in the actual objects required from the controller.
You could also consider not having the services return domain objects, this would mean that the automapping should be invoked with the service methods rather than the controller actions.

Dependency Injection with Cyclic Dependency

Let me have two very basic objects like:
public class View
{
public View(Controller controller)
{
// Use the model exposed by the controller here
}
}
public class Controller
{
private readonly IView view;
public Controller()
{
this.view = new View(this);
}
public Controller(View v)
{
this.view = v;
}
}
Later I decide to inject View object into the Controller via DI but there I have a cyclic dependency (i.e. I can't use var ctrl = new Controller(new View(ctrl));). How would you go about injectin the dependency in this case?
The most common solution is to use a dependency property to solve circular dependencies. i.e. create a new property in one of the classes and let the IoC container assign it.
If you are using Unity you should add [Dependency] to that property.
A sidenote: A View should not have a dependency to a controller. It should not be aware of it at all.
Update in reply to comment
You can't. That's the problem with circular dependencies. The only other solution is to use composition. That is to break out the common functionality into a separate class and include it in both the controller and the view.
I actually found a nice solution using Ninject.
public class Controller
{
private readonly View view;
public Controller(ViewModule viewModule)
{
using (IKernel kernel = new StandardKernel(viewModule))
{
this.view = kernel.Get<View>(new ConstructorArgument("controller", this);
}
}
}
Where the ViewModule is a pre-configured Ninject module to resolve the particular view dependency (GUI, CLI, etc.) Minor problem here is that, I'm now dependent on the particular DI framework.
You can't do that at all with constructor-injection
If you change the constructor of the controller to
public Controller(IView view)
in which order would you create the two objects?
View needs the controller Instance and the controller needs the view.
However, you can make the IView Property of the controller public, and set the Property after creation (Some DI-Containers can do this for you automatically when you set the correct attribute).

Categories

Resources