In the following example, what is an efficient way to implement multitenancy with minimal redundant code? In this scenario, tenant is a student. The students' school has 2 locations and each location is required to have the data (i.e, Courses) stored in a seperate database. When a student logs in, their location determines which database to pull from.
I'm using Entity Framework and Repository Pattern. Currently I have the implementation for accessing Location 1 DB. I've looked into different options to implement Location 2, such as injecting a TenantContext in the HomeController contructor, but I am stuck on how to set the correct database connection and what approach would be most efficient.
Below is the code for Location 1 only.
Example Controller
public class HomeController : Controller
{
ICourseRepository courseRepository;
//How to set the correct repository to use based on location?
public HomeController(ICourseRepository courseRepository)
{
this.courseRepository = courseRepository;
}
//Register for a new class
public ViewResult Register()
{
var courseList = courseRepository.AvailableCourses();
return View(courseList);
}
}
CourseRepository
public class CourseRepository : ICourseRepository
{
private Location1DB context = new Location1DB();
public List<Course> AvailableCourses()
{
//Get available courses from Location 1 Course Table
}
}
Location1Model.Context.cs (This is genereated using EF DbContext Generator)
public partial class Location1DB: DbContext
{
public Location1DB()
: base("name=Location1DB")
{
}
public DbSet<Course> Courses { get; set; }
}
Web.config
<connectionStrings>
<add name="Location1DB" ... />
<add name="Location2DB" ... />
</connectionStrings>
sorry I'll try to edit and provide a more complete answer when I get time tomorrow, but check this SO answer and the castle windsor container doco to get you started (also not sure what container you are using but all the major ones should have this functionality).
The thought would be to read the LocationID out of the cookie, grab the right connection string and have the container pass it as a parameter to your dbcontext.
DbContext is a partial class remember, so you could declare your own partial DbContext class, put an interface on it and pass that as a dependency into your repository.
Related
How can I split the properties, functionality and classes out of the default ASP.Net Mvc / Identity 2.0? I am battling with a few things:
by default, it wants to use OWIN's context to wire up some kind of dependency injection, and control the Managers
it puts the ApplicationDbContext at the application level, where my architecture requires it be available at "lower" levels.
It requires that I declare any properties in the same class as the functionality that acts on those properties (which doesn't fit in with my architecture)
The ApplcationUser model has dependencies on Asp.Net, which I would like to break if I am to move the POCO to a non-MVC layer of the solution
Application architecture:
I have a solution that has several tiers :
Api - defines interfaces for services
Domain - stores POCO models representing a business domain
Business - stores logic for interacting with domain objects, and consumes services
Service - implementation of services, including Entity Framework, and the structure maps for the domain objects
Application - in this case, an MVC application.
My business layer only knows about service interfaces, not implementation, and I am using dependency injection to wire everything up.
I have some interfaces defining read/write/unit of work operations for a data service, and an implementation of these that inherit from DbContext (in my Service layer). Instead of having a series of DbSet<MyPoco> MyPocos {get;set;}, I am wiring it up by passing a series of type configurations that define relationships, then accessing my types through Set<Type>(). All that works great.
This stack has been in place for an existing application, and works well. I know it will transition to an MVC application, and am only having issues with the "out of the box" ASP.Net Identity-2.
My solution to this was to: Abstract all the things
I got around this by abstracting most of the functionality of identity into its own project which allowed for easier unit testing and reuse of the abstraction in other projects.
I got the idea after reading this article
Persistence-Ignorant ASP.NET Identity with Patterns
I then fine tuned the idea to suit my needs. I basically just swapped out everything I needed from asp.net.identity for my custom interfaces which more or less mirrored the functionality provided by the framework but with the advantage of easier abstractions and not implementations.
IIdentityUser
/// <summary>
/// Minimal interface for a user with an id of type <seealso cref="System.String"/>
/// </summary>
public interface IIdentityUser : IIdentityUser<string> { }
/// <summary>
/// Minimal interface for a user
/// </summary>
public interface IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
TKey Id { get; set; }
string UserName { get; set; }
string Email { get; set; }
//...other code removed for brevity
}
IIdentityManager
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager : IIdentityManager<IIdentityUser> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser> : IIdentityManager<TUser, string>
where TUser : class, IIdentityUser<string> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser, TKey> : IDisposable
where TUser : class, IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
//...other code removed for brevity
}
IIdentityResult
/// <summary>
/// Represents the minimal result of an identity operation
/// </summary>
public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> {
bool Succeeded { get; }
}
In my default implementation of the identity manager, which also lives in its own project, I simply wrapped the ApplicationManager and then mapped results and functionality between my types and the asp.net.identity types.
public class DefaultUserManager : IIdentityManager {
private ApplicationUserManager innerManager;
public DefaultUserManager() {
this.innerManager = ApplicationUserManager.Instance;
}
//..other code removed for brevity
public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) {
var result = await innerManager.ConfirmEmailAsync(userId, token);
return result.AsIIdentityResult();
}
//...other code removed for brevity
}
The application layer is only aware of the abstractions and the implementation is configured at startup. I don't have any using Microsoft.AspNet.Identity at the higher level as they are all using the local abstractions.
the tiers can look like this :
Api - defines interfaces for services (including Identity abstraction interfaces)
Domain - stores POCO models representing a business domain
Business - stores logic for interacting with domain objects, and consumes services
Service - implementation of services, including Entity Framework, and the structure maps for the domain objects
Identity - implementation of Microsoft.AspNet.Identity specific services, including Microsoft.AspNet.Identity.EntityFramework; and OWIN configuration
Application - in this case, an MVC application.
In MVC Application layer the AccountController thus only needed
using MyNamespace.Identity.Abstractions
public partial class AccountController : Controller {
private readonly IIdentityManager userManager;
public AccountController(IIdentityManager userManager) {
this.userManager = userManager;
}
//...other code removed for brevity
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Signin(LoginViewModel model, string returnUrl) {
if (ModelState.IsValid) {
// authenticate user
var user = await userManager.FindAsync(model.UserName, model.Password);
if (user != null) {
//...code removed for brevity
} else {
// login failed
setFailedLoginIncrementalDelay();
ModelState.AddModelError("", "Invalid user name or password provided.");
}
}
//TODO: Audit failed login
// If we got this far, something failed, redisplay form
return View(model);
}
}
This assumes you are using some DI framework. It is only in the configuring of the IoC that any mention is made of the layer that implements identity completely abstracting it away from those that have need of using identity.
//NOTE: This is custom code.
protected override void ConfigureDependencies(IContainerBuilder builder) {
if (!builder.HasHandler(typeof(IIdentityManager))) {
builder.PerRequest<IIdentityManager, DefaultUserManager>();
}
}
I'm not sure if the title correctly describes my problem. If someone could better describe my problem by reading the following description, please help me by editing the title to something more meaningful.
I'm trying to learn asp.net MVC with Entity Framework and Ninject.
I was having a look at NuGet Gallery application on GitHub and tried to implement a few parts in my project.
I followed the answer provided in this question [How do architect an ASP.Net MVC app with EF?] and designed my project with the following layered structure.
MyDemoApp
MyDemoApp.Domain (Contains POCO Classes)
MyDomain.Service (Contains references to Domain,EF. It contains only Interfaces)
MyDemoApp.Data (Contains references to EF, Domain, Service. It contains classes dealing with Entity Context and Repository)
MyDemoApp.Web (Contains references to ApplicationModel,Data,Domain,Service,Ninject)
MyDemoApp.ApplicationModel (Contains references to Data, Domain, Serivce. It implements the classes from Service project)
MyDemoApp.Web has no business logic and is acting like Humble Object, as mentioned in this answer
I have a Interface IConfiguration in MyDemoApp.Service project which is being implemented by Configuration class located in MyDemoApp.Web where I'm trying to read the connection string. I need to pass this connection string to the object of EntityContext being created in EntityContextFactory located in MydemoApp.Data
If I add a project reference of MyDemoApp.web to MyDemoApp.Data then Visual Studio Prompts me saying that it would cause a circular reference
In the following code return new EntitiesContext(""); How should I pass a parameter over here that would get the connection string that my bindings.cs gets ?
namespace MyDemoApp.Data
{
public class EntitiesContextFactory : IDbContextFactory<EntitiesContext>
{
public EntitiesContext Create()
{
//TO-DO : Get the Connnectionstring
return new EntitiesContext(""); //Need to pass connection string by calling property from Configuration class in MyDemoApp.Web project
}
}
public class EntitiesContext:DbContext,IEntitiesContext
{
public EntitiesContext(string connectionString) : base(connectionString)
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Provide mapping like foreign key
}
}
}
}
Configuration.cs:
namespace MydemoApp.Web
{
public class Configuration : IConfiguration
{
public string ConnectionString
{
get
{
return ConfigurationManager.ConnectionStrings['dev'].ConnectionString;
}
}
}
}
Bindings.cs:
namespace MydemoApp.Web.Bindings
{
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IConfiguration>().To<Configuration>();
var configuration = new Configuration(); //Gives me Connectionstring
Bind<IEntitiesContext>().ToMethod(context => new EntitiesContext(configuration.ConnectionString)); // This part would help me pass the connection string to the constructor
}
}
}
I don't quite get what problem you are facing. I assume that you need to access a class in Web assembly from Data assembly, but Data assembly already referencing Web assembly.
Can you just inject the configuration interface to your factory constructor, and use that to get the connection string?
public class EntitiesContextFactory : IDbContextFactory<EntitiesContext>
{
public EntitiesContextFactory(IConfiguration configuration){
this.configuration = configuration;
}
IConfiguration configuration;
public EntitiesContext Create()
{
return new EntitiesContext(configuration.ConnectionString);
}
}
I may misunderstand your question though.
Personally, I think you should leverage the ConfigurationManager in your EntitiesContextFactory.
This would look like:
return new EntitiesContext(System.Configuration.ConfigurationManager.ConnectionStrings["{connectionstringname}"].ConnectionString)
This class is agnostic of whether it is an app.config or web.config that is providing the configuration.
All it stipulates is that application that is hosting the dlls for running, must be configured with an (app/web).config that contains that connection string. your app can test for this at startup since it knows it has a dependency on a database connection for it to work.
I have a simple asp.net MVC4 / EF 4.1 project created with VS 2011, with a layer for my domain model and one for my database that contains the DbContext. I have one basic domain class called Batch and a BatchController with the standard CRUD functionality using Index / Create / Edit actions. I add two default records with the overridden Seed method. All this works fine I can add / edit / delete records using the out of the box MVC template:
public class BatchController : Controller
{
private readonly MyContext _context = new MyContext();
public ActionResult Index()
{
return View(_context.Batches.ToList());
}
[HttpPost]
public ActionResult Create(Batch batch)
{
if (ModelState.IsValid)
{
this._context.Batches.Add(batch);
this._context.SaveChanges();
return RedirectToAction("Index");
}
return View(batch);
}
}
I added a new MVC4 Web api project to the solution with the intention of exposing the domain object so the data can be retrieved via json. This uses an api controller that I've called BatchesController, and I added a reference to my domain and database layers. I have two Get() methods, one to return all Batches and one to return a single batch given an id. I'm using IIS Express to host the main MVC app and the Web api. To retrieve all the Batches I run this in a browser:
http://localhost:46395/api/batches
Here's my Web api Controller :
public class BatchesController : ApiController
{
private readonly MyContext _context;
public BatchesController()
{
_context = new MyContext();
}
// GET /api/batches
public IEnumerable<Batch> Get()
{
var batches = _context.Batches.ToList();
if (batches == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return batches;
}
// GET /api/batches/5
public Batch Get(int id)
{
var batch = _context.Batches.Find(id);
if (batch == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
return batch;
}
}
My problem is that when I add a new record and try to retrieve it via a browser, only the existing records aded with the Seed method are returned - I can't get any newly added record to be returned. The DbContext seems to be caching the initial records and not going to the database to get the latest...how do I return newly added records?
Just to clear out the obvious, you have surely rewired to Web API project to point to the same database, right? Because by default Web API will attach its own SQL Compact DB. Meaning that you could effectively be using 2 separate databases
There is an answer, which It doesn't solve my problem:
http://www.strathweb.com/2012/03/serializing-entity-framework-objects-to-json-in-asp-net-web-api/
Also, there is a same question at here:
http://forums.asp.net/t/1814377.aspx/1?Web+api+not+returning+records+from+EF+4+1+DbContext
and I find this useful:
ASP.Net Web API showing correctly in VS but giving HTTP500
BUT THE POINT IS:
You can not send the proxy object to webapi serializer. So it should be project to a new dynamic class or a predefined class which there is no virtual (or maybe IList, ICollection,...).
// GET api/ProfileGame
public dynamic GetProfileGames()
{
return db.ProfileGames.Select(pg => new
{
...
}).AsEnumerable();
}
I am trying out the new Visual Studio 11 Beta with MVC 4.0 and EF 4.3.1.
When adding a controller I get the following message "Unable to retrieve metadata for 'MyService.Entities.Email'. The type initializer for 'System.Data.Entity.Internal.AppConfig' threw an exception"
Repro
I have a basic a solution which has an Entities project (MyService.Entities) and and MVC project (MyService.Website).
In the Entities project I have the bare bones for code first with a class for "Email" and a class for the DbContext. The two classes look like:
EntitiesDb
namespace MyService.Entities
{
public class EntitiesDb : DbContext
{
public EntitiesDb(string nameOrConnectionString)
: base(nameOrConnectionString)
{ }
public EntitiesDb()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Sets up the defaults for the model builder
// Removes the metadata being written to the database, This is being depreciated anyhow
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
// Sets the table names so that they are named as a none plural name
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
// Creates the database from scratch when it builds
base.OnModelCreating(modelBuilder);
}
public DbSet<Email> Emails { get; set; }
}
}
Email
namespace MyService.Entities
{
public class Email
{
public Email()
{
}
[Key, DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int EmailId { get; set; }
public string Subject { get; set; }
public string BodyHTML { get; set; }
}
}
I have referenced the MyService.Entities project in the MyService.Website MVC project and set the Connection String to fit my Database name
<add name="EntitiesDb" connectionString="Data Source=localhost;Integrated Security=SSPI;Initial Catalog=EntitiesDb;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
When I go to create the MVC scaffolding by doing the following:
Right click on Controllers folder > Add > Controller
Set controller name to be EmailController
Set Template to Controller with read/write actions and views, using Entity Framework
Set Model class to Email(MyService.Entities)
Set Data context class to EntitiesDb (MyService.Entities)
Set Views as Razor
It shows a message of
"Unable to retrieve metadata for 'MyService.Entities.Email'. The type initializer for 'System.Data.Entity.Internal.AppConfig' threw an exception"
The confusing thing is that it worked initially and then I started to add some more entities and Properties into the database and then it wouldn't allow me. I've now scaled right back and it is still doing it.
I have tried a few things after looking on the forums:
Checking the Connection string is correct in MVC Project Adding a
Connection string in the Entities Project
Reinstalled Visual Studio 11 Beta in case any updates have affected it
Checking that the references match (they are both EntityFramework
Version 4.3.1.0)
Dropping the database to rebuild (Now I don't have one ;o))
Is this a bug in VS11? Am I missing a reference to the metadata somewhere?
Any help much appreciated.
EDIT:
By un-installing the EntitiesFramework and re-installing the NuGet package fixed the problem.
Remove this section from webconfig
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
</providers>
</entityFramework>
We have a site using Unity and IUnitOfWork for our EF context. Until now we've only been using a single EF Context so this is the one mapped in Unity config. This has all been handled through constructor injection and this is something we'd like to maintain for consistency.
We've now introduced another EF Context for our PaymentController that is used within the site but Unity config currently only allows us to create one type for IUnitOfWork.
I know that I can create a new <register/> element for the new context with a distinct name attribute but how do I implement this within the controller constructor to use the one named payments?
<register type="IUnitOfWork" mapTo="FirstContext" />
<register type="IUnitOfWork" mapTo="PaymentsContext" name="payments"/>
public class PaymentController()
{
public PaymentController(IUnitOfWork unitOfWork)
{
//How to I tell unity that this needs to be a payments
_unitOfWork = unitOfWork;
}
}
Many Thanks
When the FirstContext and PaymentsContext have each an unique set of entities (for instance, each connect to a different database) it is worth wild to explicitly define this in code. One way of doing this is by specifying a factory for each unit of work:
public interface IFirstContextFactory
{
IUnitOfWork CreateNew();
}
public interface IPaymentContextFactory
{
IUnitOfWork CreateNew();
}
public class PaymentController()
{
public PaymentController(PaymentContextFactory paymentContextFactory)
{
//How to I tell unity that this needs to be a payments
this.paymentContextFactory = paymentContextFactory;
}
public void DoSomething()
{
using (var context = this.paymentContextFactory.CreateNew())
{
// Do something useful
context.Commit();
}
}
}
Not only makes this your dependencies very clear (because you know what type of context the code is dealing with), but it also simplifies the DI configuration, because you won't need any named registrations.