Ninject : Pass object down layers through bindings for multitenancy - asp.net-mvc

I have a multitenant application in Asp.NET MVC with Ninject and Fluent nHibernate. I have one Database per tenant and I create one session factory for each tenant.
Now after the tenant logins, I need (if it doesn't exists) create a SessionFactory and get a session out of it. That's done.
My problem now is that the specific tenant info is extracted from the FormsAuth cookie and I need to pass it down layers...
Here are my layers :
Web
Service
Data
When my controllers need to access some info, they use the specific info service to get to the data repository with has a session which come from the sessionfactory.
In Data Layer :
Bind<SessionFactoryFactory>().ToSelf()
.InSingletonScope();
Bind<ISession>()
.ToMethod(ctx => ctx.Kernel.Get<SessionFactoryFactory>()
.Get(**[??TENANTINFOOBJECT??]**).OpenSession())
.WhenParentNamed("TenantDB")
.InRequestScope();
Bind<ISomeInfoRepository>()
.To<SomeInfoRepository>()
.InRequestScope()
.Named("TenantDB");
In Service Layer :
Bind<ISomeInfoService>().To<SomeInfoService>()
.InRequestScope();
In Web Layer :
public class SomeController : BaseController
{
ISomeInfoService someInfoService;
public SomeController(ISomeInfoService someInfoService)
{
this.someInfoService= someInfoService;
}...
How do I send to my sessionfactory the tenant info with Ninject? When a web request is made, I extract the tenant id from the cookie and can build the required tenant object (id + connection string). How do I pass it down the layers with Ninject to my SessionFactoryFactory?

Register a type that is your TenantInfo in the request scope. This TenantInfo could be created from the cookies using the ToMethod as you are doing in your question.
Then Bind the ISession to a ninject provider (a class which inherits from Provider). Make this provider take as a constructor argument (or property) the TenantInfo. Within the provider you then have the necessary information to construct your session. for the Tenant.

Related

ServiceBusTrigger in a Multitenant application - Dependency Injection for ServiceBusReceivedMessage

I have a multitenant application which uses scoped dependencies to retrieve a tenantId from an incoming httprequests to the Azure functions and instantiate various resources based on the tenant.
For example:
services.RegisterScoped((sp)=>
{
var httpContextAccessor = sp.GetRequiredService<IHttpContextAccessor>();
var tenantId = httpContextAccessor.GetTenantId(); // extension method
// Instantiate some other tenant specific dependencies e.g. DBContext.
});
Now, I have a ServiceBusTrigger which processes messages for all tenants. The ServiceBusReceivedMessage parameter contains an object which has a tenantId property so that each message can be processes for a particular tenant.
Is there a way to have the ServiceBusReceivedMessage instantiate a resource, say a DbContext, from within the function? This is necessary because each message may have to persist some data via a DbContext, which needs to be instantiated with a specific connection string based on the tenantId in the message.
Some things I have considered:
Using Activator.CreateInstance(//pass in the tenant connection string after retrieving it manually)
Can ServiceBusRecievedMessage be registered within the serviceBusTrigger per message?? This seems hacky (there isn't a straightforward way to do that) but also the most preferred approach as the rest of the DI containers can be leveraged without having to instantiate objects manually as in the first option.
[FunctionName("MyCustomTrigger")]
public Task Run(
[ServiceBusTrigger("MultiTenantEndpoint")]
ServiceBusReceivedMessage message,
ServiceBusClient client,
ServiceBusMessageActions messageActions,
ILogger logger,
ExecutionContext executionContext)
{
var tenantId = message.GetTenantId();
// register tenantId as scoped for this request only somehow?
await injectedService.Process(message);
}
Alternate approaches or designs for this?

ASP.net Core EF DataContext not Scoped as per Documentation?

In my Startup.cs file, I have set up a data context to participate in DI.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer("Connection String");
});
}
According to Dependency Injection Doc, the above code automatically puts the data context as Scoped in the IoC container. I am under the impression that an instance of MyDbContext is created for every request. A subsequent request would then have a new MyDbContext instance throughout its lifetime.
I have a controller set up and I'm passing MyDbContext via constructor DI. I make a simple GET request, and I get the data I want. I make a change to that very entity in SQL Management Studio, like change the value of one property/column. I make that same GET request. I don't get the new value that I set in SQL Management Studio.
This makes me think that ASP.net Core holds on to the same instance of MyDbContext across the lifetime of my application. If I stopped and restarted the application, that GET request will return the value I expected.
How do I refresh this data context for each request if I set it up with DI?
Am I missing something? I might post more code if needed.

MVC with WCF service design

Being new to MVC, and WCF (somewhat), I'd like to ask a design question. I have an MVC application, with a simple screen. I need to call a WCF service, which returns a reply object type. To separate the WCF calls from my MVC app, I have created a ServiceProxy dll, which exposes a method called RegisterWithService, passing it an IP address.
So, MVC app, calls
ServiceProxy.RegisterWithService(xxx.xxx.xxx.xxx);
The method then creates a RegistrationRequest object, and sends that to the WCF service. The reply (a RegisterResponce object) replies with an object.
My question is, is it OK to pass that object back to the MVC controller to deal with, or should I create some form of DTO... so that the ServiceProxy creates a new object type (maybe, RegistrationDTO, which has the same fields as the WCF reply object, and passes that back to the MVC app? That, I guess, makes the MVC non-reliant on the WCF objects... so a change in the service contract would only cause a change in the proxy class I created - leaving the MVC app segregated.
Does that seem like a good design?
I think that 2 levels of objects are enough:
Domain models (coming from your WCF service)
View models (specific to the MVC application)
So you could use the service proxy interface that was generated for you when you imported the WCF service definition as repository layer. This interface will return your data contracts which will represent the domain models. The Controller will be responsible for calling various methods on this interface and mapping the domain models to view models that will be passed to the view.
For example:
public class HomeController: Controller
{
private readonly IServiceProxy service;
public HomeController(IServiceProxy service)
{
this.service = service;
}
public ActionResult Index(int id)
{
SomeDataContract domainModel = this.service.Get(id);
MyViewModel model = Mapper.Map<SomeDataContract, MyViewModel>(domainModel);
return View(model);
}
}
Of course if your application gets more complex you could introduce an additional abstraction layer and DTOs.

Authenticated User and Service Layer

I have a MVC 4 application which uses a Service Layer in a different class library.
Some of the calls to that service layer needs to know which uses is requesting the data.
The data records is different depending on the User Roles.
For Prevent Coupling Issue, Should I pass the username in the request (HttpContext.User.Identity.Name) or should I access it directly on the service layer using the same HttpContext.User.Identity.Name .
I am never sure if I should hide the HttpContext from the service layer.
Simply pass the currently authenticated user as parameter to your service layer. Never use HttpContext.User.Identity.Name in your service layer.
For example:
[Authorize]
public ActionResult SomeAction()
{
string user = User.Identity.Name;
this.someService.SomeOperation(user);
...
}
Your service layer should never be tied to an HttpContext.
Passing HttpContext to the service layer may look tempting, but would be a bad choice. It would make a hard link between ASP.net runtime services and the business logic (this is exactly what you are trying to avoide, i assume). The best would be to create class to represent the logged in user, which you can populate in a base controller and pass that on to the service layer.
This way, you get best of both worlds

Ninject - Constructor Argument from Session

We are building a multi-tenant database application utilizing ASP.NET MVC, the Entity Framework Code First, and the soon to be released SQL Azure Federations. Our repository accepts a DbContext as a constructor argument that is injected using Ninject. The problem is that the DbContext has an int constructor argument to specify the account id that will be used for the requests made with that context. Something like this:
public class DatabaseContext : DbContext
{
public DatabaseContext(int accountId)
{
// Code here to ensure we only work with data associated with
// the account identified by accountId
}
}
The value for the account id will be stored in a Session variable. The question is how do we get Ninject to inject a value from Session into the constructor when it creates a new instance of DatabaseContext?
Or is there another way I should go about injecting the account id into the DbContext?
There are a few ways. I like using the .ToMethod approach.
Bind<DatabaseContext>().ToMethod(
c => new DatabaseContext((int)HttpContext.Current.Session["Acct"]);
Though to solve this particular problem, I've found it better to create an ISessionManager service that has session-based data on it. Anything that wants, e.g., an accountId would have this service injected into the constructor, and access its AccountId property when it needs an account ID.

Resources