I previously had a controller that had code like this:
public ActionResult Method(int Id)
{
var foo = doThis(Id)
return View("Error");
}
doThis() is a method that exists in the controller, and performs some logic. I'm now trying to relocate all business logic to a Services project that contains a bunch of classes.
To start I added a class library Project.Services and then added a class FooServices which contains the following:
namespace Project.Services
{
class FooServices
{
public List<Bar> doThis(int Id)
{
//Do stuff
return parentSets;
}
}
}
I've added a reference to this project from my MVC project, and a reference from this Services project to my data model project, but I'm not sure how to proceed now. How can I access these methods from controllers?
How can I access these methods from controllers?
In order to access an instance method you need an instance of the object:
public ActionResult Method(int Id)
{
var foo = new FooServices().doThis(Id)
return View("Error");
}
Of course by doing this you are now strongly coupling your controller logic with a specific implementation of your service making it very difficult to unit test your controllers in isolation.
So to weaken the coupling start by introducing an abstraction:
public interface IFooServices
{
List<Bar> DoThis(int id)
}
and then have your service layer implement this interface:
public class FooServices: IFooServices
{
public List<Bar> DoThis(int id)
{
//Do stuff
return parentSets;
}
}
Alright, now your controller could work with this abstraction:
public class HomeController: Controller
{
private readonly IFooServices service;
public HomeController(IFooServices service)
{
this.sevrice = service;
}
public ActionResult Method(int id)
{
var foo = this.service.DoThis(id)
return View("Error");
}
}
Great, at this stage we really have a weak coupling between your controller and the service layer. All that's left now is to configure your favorite dependency Injection framework to inject the specific service into your controller.
Related
I started refactoring an ASP.Net 5 web application which uses MVC 6 and Entity Framework 7 when I was wondering about some points. My controllers currently use the DbContext implementation via dependency injection to fill the view models and return them for rendering with the view. Like:
public class UserController : Controller
{
[FromServices]
public MyContext myContext { get; set; }
//route which renders all users
public IActionResult Index()
{
var users = myContext.User.OrderBy(u => u.Name);
List<UserIndexViewModel> v = new List<UserIndexViewModel>();
foreach (var item in users)
{
v.Add(new UserIndexViewModel { Name = item.Name, City = item.City, DateOfBirth = item.DateOfBirth });
}
return View(v);
}
//route to edit user
public async Task<ActionResult> Edit(int id)
{
User user = await FindUserAsync(id);
UserEditViewModel v = new UserEditViewModel { Name = user.Name, City = user.City };
return View(v);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Update(int id, UserEditViewModel userModel)
{
User user = await FindUserAsync(id);
try
{
user.Name = userModel.Name;
user.City = userModel.City;
myContext.User.Attach(user);
myContext.Entry(user).State = EntityState.Modified;
await myContext.SaveChangesAsync();
return RedirectToAction("Index");
}
catch (Exception)
{
ModelState.AddModelError(string.Empty, "Unable to save changes.");
}
return View(userModel);
}
private Task<User> FindUserAsync(int id)
{
return myContext.User.SingleOrDefaultAsync(u => u.UserId == id);
}
}
I did some research and I found some blog posts (like this) which asks to keep controllers clean. Ok.. why not?
I started creating a kind of view model builder to put the logic out of the controller methods over to the view model builder. In the above linked article is a hint to create for each view model a own view-model-builder class - which makes sense in my eyes.
For the model User exist two views and thus two view models (UserIndexViewModel and UserEditViewModel). When I create the related view-model-builder classes they should derivate from the same (abstract) class because it could be that both child classes needs a helper method (like FindUserAsync() - it is not the case in my example but just imagine). So I would have a construct like the following:
public interface IViewModelBuilder<TController, TViewModel>
{
TViewModel Build(TController controller, TViewModel viewModel);
Task<TViewModel > BuildAsync(TController controller, TViewModel viewModel);
}
public abstract class UserViewModelBuilder<TViewModel> : IViewModelBuilder<UserController, TViewModel> { ... }
public class UserIndexViewModelBuilder : SiteViewModelBuilder<UserIndexViewModel> { ... }
public class UserEditViewModelBuilder : SiteViewModelBuilder<UserEditViewModel> { ... }
This mentioned function which is needed by multiple view model builders of one model should be implemented in the abstract class (UserViewModelBuilder in my case), right?
I did it like this:
public abstract class UserViewModelBuilder<TViewModel> : IViewModelBuilder<UserController, TViewModel>
{
[FromServices]
public MyContext myContext { get; set; }
public abstract TViewModel Build(UserController controller, TViewModel viewModel);
public abstract Task<TViewModel> BuildAsync(UserController controller, TViewModel viewModel);
public Task<User> FindUserAsync(int id)
{
return myContext.User.SingleOrDefaultAsync(u => u.UserId == id);
}
}
So with this abstract class I can create the implementation of UserIndexViewModelBuilder and UserEditViewModelBuilder classes as well as for example UserDeleteViewModelBuilder and UserCreateViewModelBuilder classes in future...
Now the question:
Is this a right approach to separate the logic from the controller? If yes, do I need a kind of factory for all view model builders which can be accessed via DI in all my controllers? If it is the way which is kind of best practice for MVC applications. Is there something different to the mentioned guide which can/should be used in MVC 6 apps?
Is the abstract class the right place to call the DbContext implementation via DI? It feels not good for me.
Some other points which I missed? Some if-statements for checking response were removed from the UserController snipped for better readability.
Thank you! :-)
Just wanted some guidance how would I go about unit testing the following action:
public ActionResult Index()
{
var model = _resolver.GetService<ISignUpViewModel>();
model.Location = _resolver.GetService<ILocations>().getLocations(string area);
return PartialView("Login", model);
}
private IDependencyResolver _resolverMock;
[TestMethod]
public void SignUpTest()
{
var _resolverMock = new Mock<IDependencyResolver>();
var ctrl = new HomeController(_resolverMock.Object);
var signUpMock = new Mock<ISignUpViewModel>();
var LocationsMock = new Mock<ILocations>();
_resolverMock.Setup(m => m.GetService(It.IsAny<Type>())).Returns(
signUpMock.Object);
_resolverMock.Setup(m => m.GetService(It.IsAny<Type>())).Returns(
LocationsMock.Object);
DependencyResolver.SetResolver(resolverMock.Object);
ctrl.Index();
ctrl.ViewData.Model = signUpMock;
}
How do you build up the model in the unit test?
Also how do I call the getLocations method from the resolver?
Unsure on how to do this?
Your home controller is not dependent on an IDependencyResolver as per your code. It is in fact dependent on an ISignUpViewModel. So you can either pass one of those into the constructor or an ISignUpViewModelFactory. So I would refactor the model resolution out into a factory class:
public class HomeController {
private readonly ISignUpViewModelFactory _modelFactory;
public HomeController(ISignUpViewModelFactory modelFactory){
_modelFactory = modelFactory;
}
public ActionResult Index()
{
return PartialView("Login", _modelFactory.Create(area));
}
}
public interface ISignUpViewModelFactory {
ISignUpViewModel Create(string area);
}
public class ProductionSignUpViewModelFactory : ISignUpViewModelFactory
{
public ISignUpViewModel Create(string area){
// create and return your models here
// if you still have to use a service locator in this factory then
// refactor some more until you get these dependencies out in the open.
}
}
public class MockSignUpViewModelFactory : ISignUpViewModelFactory
{
public ISignUpViewModel Create(string area){
return new SignUpViewModel();
}
}
In production you have your IOC inject an instance of ProductionSignUpViewModelFactory. In test, you pass in a MockSignUpViewModelFactory.
The difference is that using this method you are only testing the action (i.e. the unit) whereas using your current method you are testing the action AND your servicelocator _resolver plus you've obscured the actual dependency i.e. ISignUpViewModel not IDependencyResolver.
As per the comments in ProductionSignUpViewModelFactory, if you have to inject an IDependencyResolver into that factory to make it work then you're probably still doing it wrong. You then need to look at what ProductionSignUpViewModelFactory needs to create an instance of ISignUpViewModel and inject that not an IDependencyResolver.
Eventually you'll get to the top of your dependency chain and you'll find unit testing becomes very, very easy. It's even easier if you build the tests first i.e. TDD. :)
Hi I have model class which is written in MVC.I am using Ef database first approach. In model class I have some queries which deals with database. I have following questions :
1) Is it right way to use database related queries in Model and call that in controller or view?
2)If yes where I should call this model? In Controller or in view ??
3)How I should call this model? Say for example I have class called class1.cs in model.How I should call this model?
Your model contains classes that define the different objects troughout your project. This includes properties with their basic information and methods to perform actions on this object.
1)
Do you really need queries? Why not use the Entity Framework to do it for you? Create the mapping for your domain classes (either trough annotations or fluent api) and use the DbContext to retrieve and save the data stored in your database
2)
Ideally people create repositories that are injected into your controllers (Dependency Injection). These repositories can for example contain something like GetPersonById(int id). Inside this method there would be two things:
Perform an action on the domain object
Save it to the DbContext
For example:
public void Subscribe(int userID, Show show) {
var user = GetUserByID(userID);
if (!user.IsSubscribedTo(show.ShowID)) {
user.Subscribe(show);
_dbContext.SaveChanges();
}
}
Controller -> Method call in repository -> Perform action on corresponding domain object -> Save changes to the database
If you need something that doesn't require an object mutation, it's even more simple:
public User GetUserByID(int id) {
return _dbContext.Users.FirstOrDefault(x => x.ID == id);
}
3)
Trough repositories (see above). Your DbContext will have a bunch of DbSets that contain objects that correspond with every data entry in your database. Trough repositories you can work with these objects and manipulate them. When you call the DbContext.SaveChanges() method, it will look at what has changed in these lists and commit the changes to your database.
Repository example:
class User {
public int ID { get; set; }
public string Name { get; set; }
}
class DatabaseContext : DbContext {
public DbSet<User> Users { get; set; }
}
public interface IUserRepository {
User GetUserByID (int id);
bool UsernameExists (string name);
}
public class UserRepository : IUserRepository {
private DatabaseContext _db;
public UserRepository(DatabaseContext db){
_db = db;
}
public User GetUserByID(int id) {
return _db.Users.FirstOrDefault(x => x.ID == id);
}
public User GetUserByUsername(string username) {
return _db.Users.FirstOrDefault(x => x.Name == username);
}
}
public class UserController : Controller {
private IUserRepository _userRepository;
public UserController(IUserRepository userRepository) {
_userRepository = userRepository;
}
public ActionResult Details(int id){
return View(_userRepository.GetUserByID(id);
}
}
// Ninject settings (install this extension, you want it):
private void AddBindings(){
kernel.Bind<DatabaseContext>().ToSelf().InSingletonScope();
kernel.Bind<IUserRepository>().To<UserRepository>().InRequestScope();
}
You could use some sort of Unit Of Work pattern which you inject in your controller constructor using an inversion of control container (IOC), for instance autofac.
Your unit of work class could hold a reference to repositories, where you would query/insert your data.
Roughly;
public class BackendController : Controller
{
private UnitOfWork _worker;
public BackendController(UnitOfWork worker)
{
this._worker = worker;
}
public ActionResult Admin()
{
var items = _worker.MyRepository.GetAll();
return View(items);
}
}
public class UnitOfWork
{
private ContentRepository _contentRepository;
public UnitOfWork()
{
}
public ContentRepository MyRepository
{
get
{
if (_contentRepository != null)
return _contentRepository;
else
return _contentRepository = new ContentRepository();
}
}
}
public class ContentRepository
{
// holds an object context and methods to retrieve and put data (EF or similar)
}
You would have to register your instance with the IOC container in global.asax, application_start for example, something like this (Using autofac as IOC):
UnitOfWork worker = new UnitOfWork();
var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(worker).SingleInstance();
var container = builder.Build();
...
1) Is it right way to use database related queries in Model and call that in controller or view?
I would recommend not directly accessing the database in your model classes, as you have to remember that MVC is strictly a presentation layer pattern. If you do put your database access logic in your model classes, then you will not be able to have any other client use this functionality, such as a web service. Instead have logic that translates your business objects, defined outside of your ASP.NET MVC project, into your ASP.NET MVC model classes.
This is where the power of n-tier architecture shines, if you create a business and data-access layer, then I could write an ASP.NET MVC front-end, WebForms front-end, WPF front-end, WinForms front-end and all of them could access data using the same service. By putting the logic into the ASP.NET MVC model classes, then you are effectively forcing any other client to duplicate that logic again in their classes.
I need to setup a policy in base controller that applies to all controller instance, like below:
public class BaseController : Controller
{
private IPolicy Policy;
public BaseController()
{
this.Policy= new Policy(HttpContext);
}
}
Within the Policy class, I need to do something like:
this.httpContextBase.User.
Questions: (Update)
What is the better way to design the BaseController in terms of using HttpContext and Unit test.
What is the correct way to unit test HttpContext?
Absolutely no way. You are using the HttpContext inside the constructor of a controller when this context is still not initialized. Not only that this code cannot be tested but when you run the application it will also crash with NRE. You should never use any HttpContext related stuff in a constructor of a controller.
One possibility is to refactor your code and perform this inside the Initialize method:
public class BaseController : Controller
{
private IPolicy Policy;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
this.Policy = new Policy(HttpContext);
}
}
This being said, that's not the approach I would recommend. I would recommend you using dependency injection instead of service location which is considered by many as an anti-pattern.
So:
public abstract class BaseController : Controller
{
protected IPolicy Policy { get; private set; }
protected BaseController(IPolicy policy)
{
Policy = policy;
}
}
Now, all that's left is to configure your favourite Dependency Injection framework to inject the correct instance into the constructor. For example with Ninject.Mvc3 this is achieved with a single line of code:
kernel.Bind<IPolicy>().To<Policy>();
Now you can feel more than free to mock this IPolicy in your unit test without even caring about any HttpContext.
For example let's suppose that you have the following controller that you want to unit test:
public class FooController : BaseController
{
public FooController(IPolicy policy): base(policy)
{ }
[Authorize]
public ActionResult Index()
{
Policy.DoSomething();
return View();
}
}
Now, all that you need to do is pick up your favorite mock framework (Rhino Mocks in my case) and do the mocking:
[TestMethod]
public void Index_Action_Should_DoSomething_With_The_Policy()
{
// arrange
var policyStub = MockRepository.GenerateStub<IPolicy>();
var sut = new FooController(policyStub);
// act
var actual = sut.Index();
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
policyStub.AssertWasCalled(x => x.DoSomething());
}
I'm new to Mvc.
Sorry to my english. ^^
I have some question about asp.net MVC session in the controller.
The Scenario things that I want to do is like follows..
First of all, My development circumstance is entityframework and mvc3.
When Someone logged in each one has different database. So, Each has connect different database.
So, Each person has his own session value which is database connection string. So far so good.
I have simple database Repository and at the each repository's constructor can change database connection.
At controller which calls Repository class, I need session value. But As I know Controller's construction can't keep session value. right?
I want your good advice. Thanks in advance.
Code samples are below:
public class MasterRepository
{
DBEntities _db;
public MasterRepository(string con)
{
_db = new DBEntities(con);
}
}
public class TestController : Controller
{
private string con;
MasterRepository _db;
public TestController()
{
_db = new MasterRepository(Session["conn"].ToString()); // Session is null I want to solve this Part...
}
public ActionResult Index()
{
string con = Session["conn"].ToString(); // Session is assigned.
return View();
}
}
These should explain what's happening to cause Session to be null, and give you a few possible solution options:
Is ASP.NET MVC Session available at any point durign controller construction
Why my session variables are not available at construction of a Controller?
Session null in ASP.Net MVC Controller Constructors
I think you have missed out the "service" part of the controller - service - repository pattern:
http://weblogs.asp.net/fredriknormen/archive/2008/04/24/what-purpose-does-the-repository-pattern-have.aspx
But when you go down this path you will probably also need to learn IoC as well.
Then your code would look more like:
public class MasterRepository
{
public Foo GetAllFoo()
{
return ObjectContextManager.GetObjectContext().AsQueryable().ToList();
}
}
public class MasterService
{
MasterRepository _repository;
public MasterService(MasterRepository repository) // use IoC
{
_repository = repository;
}
public Foo GetAllFoo()
{
return _repository.GetAllFoo();
}
}
public class TestController : Controller
{
MasterService _service;
public TestController(MasterService service) // use IoC
{
_service = service;
}
public ActionResult Index()
{
var model _service.GetAllFoo();
return View(model);
}
}