I've read several articles about how to use subdomains and custom routes for multitenant applications, but the project I'm working on requires only one domain. We're using the default membership provider, and storing the encrypted tenant ID in the cookie.
My question regards the controllers. We're currently building them so that the first item in every action retrieves the TenantID from the cookie, and then passes that into every Linq query. Is it safe to move that to the top of the controller class instead, so it only happens once per controller instance? Or does that cause potential data crossover if multiple users are accessing the same controller?
I found this article which suggests that that's possible, but I want to be sure.
As an example, this is the current system:
public class ThisController : Controller
{
private DBContext db = new ThisContext();
public ActionResult Index()
{
long tenantid = AuthUser.GetTenantID();
...
This is what we're considering:
public class ThisController : Controller
{
private DBContext db = new ThisContext();
private Int64 tenantid = AuthUser.GetTenantID();
public ActionResult Index()
{
...
My understanding of the default behavior is that a new instance of the controller class is created with every request, but I want to be sure that's correct before we proceed.
Yes new instance of controller is indeed created by default for each request made to an mvc application. You can test it yourself by adding a constructor to the controller and doing Debug.WriteLine in the constructor.
Related
I'm trying to get details about the current user in my DBContext so that I can store a CreatedByUserId and ModifiedByUserId when a record is updated.
What I'm finding is that the IPrincipal instance injected is valid for the controllers, but is null when injected into my DB Context, which is in a separate assembly.
I'm doing the injection with Autofac as follows:
builder.Register(c => HttpContext.Current.User).As<IPrincipal>().InstancePerRequest();
builder.Register<AppDbContext>(c => new AppDbContext(GlobalHost.DependencyResolver.Resolve<IPrincipal>())).InstancePerLifetimeScope();
My controller constructors look like this, and user will be valid here as expected:
public class ProductsController : Controller
{
private readonly IProductService _productService;
public ProductsController(IProductService productService, IPrincipal userPrincipal)
{
var user = userPrincipal;
_productService = productService;
}
My DBContext constructor looks like this and user will be null here:
public partial class AppDbContext : System.Data.Entity.DbContext, IAppDbContext
{
public AppDbContext(IPrincipal principal)
: this("Name=SqlConnection", principal)
{
var user = principal;
}
The controller code is called before the DB Context code, so it's not a timing issue, so I'm guessing the issue here is that the DB Context code is running on a different thread to the controller with different identity maybe?
If I use this code to get the identity in my DB context I can successfully get the user:
var user = System.Threading.Thread.CurrentPrincipal;
But it seems like I might run into issues getting the user in two different ways in the same app, and I'd need to figure out a way to make the DI return HTTPContext's user to the web project and the thread's principal to another assembly, all of which smacks of being the wrong solution?
Can anyone help me understand exactly why I'm seeing the behaviour above and advise on the best way to get the principal in the different assemblies of an mvc app?
So, the issue here turns out to be that I'm using the wrong Dependency Resolver when setting up the DB Context in this line:
builder.Register<AppDbContext>(c => new AppDbContext(GlobalHost.DependencyResolver.Resolve<IPrincipal>())).InstancePerLifetimeScope();
GlobalHost.DependencyResolver is giving me the SignalR resolver rather than MVC's resolver. Removing the GlobalHost bit then gives me the System.Web.MVC.DependencyResolver instead and then I can use that to get the IPrincipal as follows:
builder.Register<AppDbContext>(c => new AppDbContext(DependencyResolver.Current.GetService<IPrincipal>())).InstancePerRequest();
There's probably a really basic answer to this question but I am new to Entity and MVC and am getting used to the basics.
I'm trying to automatically generate a MVC controller for the main table Sites with a dropdown for server. It seems like I would need a model like this:
public class Sites
{
public TTSites TTSites { get; set; }
public List<servers> server { get; set; }
public Sites()
{
server = new List<servers>();
}
}
This is using the classes TTSites and servers both with string server
But if I set this as my model class and my entity database as data context it says I need to define a key. Should I be using the base classes instead of the model or what? Do i need to set something up in the model or base class?
It seems like you've got some terminology confused. You code the controller actions in a controller class, and the routing engine determines what controller action to call based on the URL. For example, if you have a HomeController class with a default Index action, it might look like this:
public ActionResult Index()
{
// code here
}
This would be invoked with the default routing, if you went to your site with a URL like this (let's say your site can be hit via the www.mysite.com URL:
http://www.mysite.com/Home
That would get you into the Index action in the controller.
Ordinarily, one would use a view model to use on the UI side, and that would be populated from an entiy with the data you need in the view itself. If you had two entities like TTSite and Server, you'd populate the Sites view model like so, as a (very simple) example:
public ActionResult Index()
{
var servers = yourDbContext.Servers.ToList();
var ttSite = yourDbContext.TTSites.GetByID(1); // retrieve one entity by its ID value, this would be acquired dynamically based on some sort of user input rather than hard-coded
var viewModel = new Sites(servers);
viewModel.TTSite = ttSite;
return View(viewModel);
}
I'm not including anything regarding making drop-downs, just illustrating getting data into a view model and then creating a view with that view model.
Note that you would not use the Sites class as an entity but rather a view model, and setting its data based on entities from your database. You wouldn't be setting any primary keys in a view model class; those are the concern of the data model, and you've presumably already got those entities (such as TTSite) set up in a usable fashion in your data layer.
Once you've got a controller action and a view up and working, you can turn to getting the view model data into a form usable by a drop-down list, and going from there.
I'm curious of all of the various ways people are building their ViewModels and why they choose that method.
I can think of several ways here:
-1. Injected repository - the controller loads the model and maps to the ViewModel. Here the ViewModel constructor could take various collections to interally set for ex. in a select list such as:
public CustomerController(ISomeRepository repository)
{
_repository = repository;
}
public ActionResult Create()
{
CustomerCreateViewModel model = new CustomerCreateViewModel(_repository.GetShipTypes,
_repository.GetStates);
..
..
}
-2. ViewModelBuilder - Either injected or instantiated in the controller with an instance of the injected repository. Called via something like
>var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);
or,
var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);
-3. Directly in controller (no code required - its messy)
-4. Some other service (injected or not) that returns domain model which the controller then maps or a ViewModel (anyone doing this to return a view model that isn't specifically named/noted as a ViewModel builder class?)
public JobCreateViewModel BuildJobCreateViewModel(int parentId)
{
JobCreateViewModel model = new JobCreateViewModel();
model.JobStatus = _unitOfWork.JobRepository.GetJobStatuses();
model.States=_unitOfWork.StateRepository.GetAll();
return model;
}
Now on the return trip - regarding validating your view models - are you inheriting from a base ViewModel class for standard validations, or copying your validations (ex. data annotation attributes) between all of your ViewModels, or simply relying on server side validation so it can all be validated againt your domain object?
Any others? Anything better? Why?
EDIT
Based on a link below, I did find a nice article from Jimmy Bogard on the architecture of ViewModels. While it doesn't address the question above directly, it's a great reference for anyone coming here for ViewModel information.
http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/
I inject a service into the controller, not a repository, and then use AutoMapper to convert it into a view model. The benefit of the service layer in this case is that it could aggregate multiple simple operations from one or more repositories into a single operation exposing a domain model. Example:
private readonly ICustomerService _service;
public CustomerController(ICustomerService service)
{
_service = service;
}
[AutoMap(typeof(Customer), typeof(CustomerViewModel))]
public ActionResult Create(int id)
{
Customer customer = _service.GetCustomer(id);
return View(customer);
}
in this example AutoMap is a custom action filter that I can write which executes after the controller action, inspects the returned object and uses defined AutoMapper mappings to map it to the specified destination type. So the view gets the corresponding CustomerViewModel as model type. Would have been equivalent to:
public ActionResult Create(int id)
{
Customer customer = _service.GetCustomer(id);
CustomerViewModel vm = Mapper.Map<Customer, CustomerViewModel>(customer);
return View(vm);
}
it's just that it is too much plumbing and repetitive code that could be centralized.
I would also recommend you watching the putting your controllers on a diet video from Jimmy Bogard.
I just finished a project where we did a variation on #4. We had a service class injected into the controller. The service class held dependencies on the repository and a model builder class (we called it model factory).
The controller called into the service class, which handled business validation logic, and then fetched view models from the appropriate factory. The models themselves relied on data annotations for input validation.
It worked really well for our team. There was enough separation of concerns to allow the devs to do their work without affecting one another, but it was manageable enough to understand what was going on.
It's the first time we tried it and we'll be sticking with it. I'm interested to see how others respond.
Our method is to inject the repository in to the controller and map it to the ViewModel using Automapper http://automapper.org/. Our ViewModels contain data annotation attributes to allow the validation to occur on the client.
We call methods on the repository which return Domain objects (Entity Framework). The domain objects are mapped to the ViewModel. We tend to use the same ViewModel for edits and adds so the data annotations are needed once. In its simplest form it looks like the following code:
public ActionResult List(int custId, int projId)
{
var users = _userRepository.GetByCustomerId(custId);
var userList = Mapper.Map<IEnumerable<CMUser>, IEnumerable<UserListViewModel>>(users);
return View(userList);
}
I use a service layer that hides the domain model from the controller returning ViewModels from the service methods. This allows me to make changes to the domain model without impacting the client.
I have an asp.net mvc app which has membership implemented.
So a user has to log in. Each user belongs to a organisation (multi-tenancy).
How would I handle the organisation parameter globaly? I was thinking this could be a good thing for a global filter because all the data needs to be filtered for the given organisation. And the organisation is connected with the username but not in the same table.
for example I have a index action like this
public ActionResult Index()
{
var result = _repository.GetListByOrganisation(organisation);
return View(result);
}
I was thinking about having a global attribute thats queries the db for an organisation based on a giving username. Since my controller already contains the authorize attribute I have the user name. It would be nice to cache the organisation (session, controllercontext) and not query the organisation from db on each request.
Is this a way to implement something like this? Or are there other ways which would be better? And how can I set a property on the controller / controllercontext from whithin a filter?
So any thoughts on this as well as comments would be great...
I would do this via DI.
You can use either a third-party DI container or your own code. Either way, you want to set the organization ID on a per-request basis.
So you'll be creating a unit of work and injecting that in your controller. For the sake of simplicity, let's pretend that your unit of work is the _repository field in your sample code, even though most real-world apps are more complex.
You add a constructor parameter to the controller:
public FooController(IFooRepository repository)
{
this._repository = repository;
}
...and an organization ID on FooRepository:
public class FooRepository: IFooRepository
{
public FooRepository(long organizationId)
{
this._organizationId = organizationId;
}
}
Now in either your DI container setup or a MVC controller factory, you set this all up:
builder.Register(c => new FooRepository(GetOrgIdForCurrentUser()).As<IFooRepository>();
builder.Register(c => new FooController(c.Resolve<IFooRepository>());
Perhaps you could have the organization embedded on the URL, for example if your route looks like this /{organization}/{controller}/{action}
then you'll get URLs like
/bigorg/products/list
/smallorg/products/list
and you'll receive the organization in your controller either a parameter to your method or via the RouteData object.
Let’s say I'm developing a helpdesk application that will be used by multiple departments. Every URL in the application will include a key indicating the specific department. The key will always be the first parameter of every action in the system. For example
http://helpdesk/HR/Members
http://helpdesk/HR/Members/PeterParker
http://helpdesk/HR/Categories
http://helpdesk/Finance/Members
http://helpdesk/Finance/Members/BruceWayne
http://helpdesk/Finance/Categories
The problem is that in each action on each request, I have to take this parameter and then retrieve the Helpdesk Department model from the repository based on that key. From that model I can retrieve the list of members, categories etc., which is different for each Helpdesk Department. This obviously violates DRY.
My question is, how can I create a base controller, which does this for me so that the particular Helpdesk Department specified in the URL is available to all derived controllers, and I can just focus on the actions?
I have a similar scenario in one of my projects, and I'd tend to use a ModelBinder rather than using a separate inheritance hierarchy. You can make a ModelBinder attribute to fetch the entity/entites from the RouteData:
public class HelpdeskDepartmentBinder : CustomModelBinderAttribute, IModelBinder {
public override IModelBinder GetBinder() {
return this;
}
public object GetValue(ControllerContext controllerContext, string modelName, Type modelType, ModelStateDictionary modelState) {
//... extract appropriate value from RouteData and fetch corresponding entity from database.
}
}
...then you can use it to make the HelpdeskDepartment available to all your actions:
public class MyController : Controller {
public ActionResult Index([HelpdeskDepartmentBinder] HelpdeskDepartment department) {
return View();
}
}
Disclaimer: I'm currently running MVC Preview 5, so some of this may be new.
The best-practices way: Just implement a static utility class that provides a method that does the model look-up, taking the RouteData from the action as a parameter. Then, call this method from all actions that require the model.
The kludgy way, for only if every single action in every single controller needs the model, and you really don't want to have an extra method call in your actions: In your Controller-implementing-base-class, override ExecuteCore(), use the RouteData to populate the model, then call the base.ExecuteCore().
You can create a base controller class via normal C# inheritance:
public abstract class BaseController : Controller
{
}
public class DerivedController : BaseController
{
}
You can use this base class only for controllers which require a department. You do not have to do anything special to instantiate a derived controller.
Technically, this works fine. There is some risk from a design point of view, however. If, as you say, all of your controllers will require a department, this is fine. If only some of them will require a department, it might still be fine. But if some controllers require a department, and other controllers require some other inherited behavior, and both subsets intersect, then you could find yourself in a multiple inheritance problem. This would suggest that inheritance would not be the best design to solve your stated problem.