ASP.NET changement de Base EF chaîne de connexion lorsque l'utilisateur se connecte au
Après quelques heures de recherche et de trouver aucun moyen de le faire; il est temps de se poser la question.
J'ai un ASP.NET de Base 1.1 projet à l'aide de EF de Base et MVC qui est utilisé par plusieurs clients. Chaque client a sa propre base de données avec exactement le même schéma. Ce projet est actuellement une application Windows en cours de migration vers le web. À l'écran de connexion, l'utilisateur dispose de trois champs, Code de l'Entreprise, le nom d'utilisateur et Mot de passe. J'ai besoin d'être en mesure de modifier la chaîne de connexion lorsque l'utilisateur tente de connexion basé sur ce qu'ils tapent dans la Société de l'entrée du Code alors souvenez-vous de leurs commentaires tout au long de la durée de la session.
J'ai trouvé quelques façons de le faire avec une base de données et plusieurs schéma, mais aucun avec plusieurs bases de données en utilisant le même schéma.
La façon dont j'ai résolu ce problème n'est pas une réelle solution au problème, mais une solution qui a fonctionné pour moi. Mes bases de données et des applications sont hébergées sur Azure. Mon fix pour ce qui était de mettre à jour mon application service à un plan qui prend en charge des fentes (seulement un supplément de 20 $par mois pour 5 emplacements). Chaque logement a le même programme, mais la variable d'environnement qui contient la chaîne de connexion est propre à chaque entreprise. De cette façon, je peux aussi chaque sous-domaine aux entreprises d'avoir accès si je veux. Bien que cette approche peut ne pas être ce que les autres faisaient, il était le plus rentable pour moi. Il est plus facile de publier à chaque emplacement que de passer des heures à faire le reste de la programmation ne fonctionne pas bien. Jusqu'à ce que Microsoft vous permet de facilement modifier la chaîne de connexion c'est ma solution.
En réponse à Herzl, la réponse de
Cela semble comme il pourrait travailler. J'ai essayé de la mettre en œuvre. Une chose que je fais est bien à l'aide d'un référentiel de classe qui accède à mon contexte. Mon contrôleurs obtenir le référentiel injecté dans des appels de méthodes dans le référentiel que l'accès au contexte. Comment puis-je le faire dans un référentiel de la classe. Il n'y a pas de OnActionExecuting surcharge dans mon référentiel. Aussi, si cela persiste pour la session, ce qui se passe lorsqu'un utilisateur ouvre son navigateur à nouveau l'application et est toujours enregistré dans un cookie d'une durée de 7 jours? N'est-ce pas une nouvelle session? Sonne comme l'application serait de lancer une exception parce que la variable de session serait nulle et à cet effet, pas une chaîne de connexion complète. Je suppose que je pourrais aussi le stocker en tant que Demande et de l'utilisation de la Réclamation si la variable de session est null.
Voici ma classe de référentiel. IDbContextService était ProgramContext mais j'ai commencé à ajouter vos suggestions pour essayer et obtenir de travailler.
public class ProjectRepository : IProjectRepository
{
private IDbContextService _context;
private ILogger<ProjectRepository> _logger;
private UserManager<ApplicationUser> _userManager;
public ProjectRepository(IDbContextService context,
ILogger<ProjectRepository> logger,
UserManager<ApplicationUser> userManger)
{
_context = context;
_logger = logger;
_userManager = userManger;
}
public async Task<bool> SaveChangesAsync()
{
return (await _context.SaveChangesAsync()) > 0;
}
}
En réponse à La FORCE JB réponse
J'ai essayé de mettre en oeuvre votre approche. J'obtiens une exception dans le Programme.cs sur la ligne
host.Run();
Voici mon Programme.cs' classe. Intacte.
using System.IO;
using Microsoft.AspNetCore.Hosting;
namespace Project
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Et mon Démarrage.cs' classe.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using Project.Entities;
using Project.Services;
namespace Project
{
public class Startup
{
private IConfigurationRoot _config;
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
_config = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_config);
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.User.RequireUniqueEmail = true;
config.Password.RequireDigit = true;
config.Password.RequireLowercase = true;
config.Password.RequireUppercase = true;
config.Password.RequireNonAlphanumeric = false;
config.Password.RequiredLength = 8;
config.Cookies.ApplicationCookie.LoginPath = "/Auth/Login";
config.Cookies.ApplicationCookie.ExpireTimeSpan = new TimeSpan(7, 0, 0, 0); //Cookies last 7 days
})
.AddEntityFrameworkStores<ProjectContext>();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, AppClaimsPrincipalFactory>();
services.AddScoped<IProjectRepository, ProjectRepository>();
services.AddTransient<MiscService>();
services.AddLogging();
services.AddMvc()
.AddJsonOptions(config =>
{
config.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
Dictionary<string, string> connStrs = new Dictionary<string, string>();
connStrs.Add("company1", "1stconnectionstring"));
connStrs.Add("company2", "2ndconnectionstring";
DbContextFactory.SetDConnectionString(connStrs);
//app.UseDefaultFiles();
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(config =>
{
config.MapRoute(
name: "Default",
template: "{controller}/{action}/{id?}",
defaults: new { controller = "Auth", action = "Login" }
);
});
}
}
}
Et l'exception:
InvalidOperationException: Unable to resolve service for type 'Project.Entities.ProjectContext' while attempting to activate 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[Project.Entities.ApplicationUser,Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole,Project.Entities.ProjectContext,System.String]'.
Ne savez pas quoi faire ici.
Réussite partielle modifier
Bon, je suis votre exemple de travail. Je peux définir la chaîne de connexion dans mon référentiel constructeur à l'aide d'un id différent. Mon problème maintenant est de connecter et de choisir la bonne base de données. Je pense à l'extraction de référentiel à partir d'une session ou de réclamation, quel que soit n'a pas la valeur null. Mais je ne peux pas définir la valeur avant d'utiliser le SignInManager dans la Connexion du contrôleur parce que SignInManager est injecté dans le contrôleur, ce qui crée un contexte avant de me mettre à jour la variable de session. La seule façon que je peux penser à est de à deux la page de connexion. La première page vous demandera le code de l'entreprise et de mettre à jour la variable de session. La deuxième page, le SignInManager et ont le référentiel injecté dans les contrôleurs de constructeur. Ce qui pourrait se produire après la première page des mises à jour de la variable de session. Cela peut effectivement être plus attrayant visuellement, avec des animations de connexion entre les deux points de vue. Sauf si quelqu'un a des idées sur la façon de le faire sans deux de connexion de points de vue, je vais essayer et de mettre en œuvre les deux page de connexion et poste le code si ça fonctionne.
Il est cassé
Quand il était en marche, c'est parce que j'ai toujours eu un cookie valide. Je voudrais exécuter le projet et il serait ignorer la connexion. Maintenant, je reçois l'exception InvalidOperationException: No database provider has been configured for this DbContext
après le nettoyage de ma cache. J'ai marché à travers tout cela et le contexte est créé correctement. Ma conjecture est que l'Identité est d'avoir une sorte de questions. Pourrait le code ci-dessous en ajoutant le cadre de l'entité dans les magasins de ConfigureServices
être à l'origine du problème?
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.User.RequireUniqueEmail = true;
config.Password.RequireDigit = true;
config.Password.RequireLowercase = true;
config.Password.RequireUppercase = true;
config.Password.RequireNonAlphanumeric = false;
config.Password.RequiredLength = 8;
config.Cookies.ApplicationCookie.LoginPath = "/Company/Login";
config.Cookies.ApplicationCookie.ExpireTimeSpan = new TimeSpan(7, 0, 0, 0); //Cookies last 7 days
})
.AddEntityFrameworkStores<ProgramContext>();
Modifier
J'ai vérifié Identity
est le problème. J'ai tiré des données de mon dépôt avant l'exécution de PasswordSignInAsync
et il tirait les données de l'amende juste. Comment est la DbContext créé pour l'Identité?
Oui j'ai besoin de modifier la chaîne de connexion de manière dynamique comme dans les versions précédentes de l'EF.
Juste pour être clair, vous avez besoin d'un échantillon à l'api web ou de bureau ? Évidemment, l'utilisation de ef de base
Oui dans ASP.NET de Base.
Veuillez vérifier ma réponse
OriginalL'auteur ozziwald | 2016-11-28
Vous devez vous connecter pour publier un commentaire.
Créer un DbContext usine
Initialiser DbContext usine
En démarrage.cs
D'utilisation
Reportez-vous à http://stackoverflow.com/a/32210383/7045253, en utilisant le conteneur d'injection ne serait pas vous permettre de modifier la valeur par défaut de la connexion. Voir aussi cet article, http://stackoverflow.com/a/36840901/7045253
Veuillez voir le plus de ma question.
services.AddDbContext<DbContextFactory>();
ne compile pas carDbContextFactory
est statique.DbContextFactory est utilisé pour la création de nouveaux dbcontext objet. Tandis qu'une connexion de l'utilisateur, l'utilisation et la var dbContext= DbContextFactory.Créer("xxx")' pour créer un nouveau dbcontext avec cartographie de chaîne de connexion de cet utilisateur.
OriginalL'auteur The FORCE JB
En fonction de votre question, je vais apporter une solution en supposant que certaines choses:
Tout d'abord, j'ai créé trois bases de données dans mon instance locale de SQL Server:
Alors, je vais créer un tableau avec une ligne dans chaque base de données:
Prochaine étape est de créer un utilisateur avec l'Authentification SQL et accorder l'accès à lire les bases de données, dans mon cas, mon nom d'utilisateur est johnd et le mot de passe est 123.
Une fois ces étapes terminées, nous allons créer une application MVC dans ASP.NET de Base, j'ai utilisé MultipleCompany comme nom de projet, j'ai deux contrôleurs: Accueil et de l'Administration, l'objectif est de montrer une connexion en premier et ensuite rediriger vers un autre point de vue pour afficher les données selon la base de données sélectionnée dans "login".
Pour accomplir votre exigence, vous aurez besoin d'utiliser la session sur ASP.NET application de Base vous pouvez modifier ce moyen de stockage et de lire les données plus tard, pour l'instant c'est pour le concept de test uniquement.
HomeController code:
AdministrationController code:
Code de la vue d'Accueil:
Code de la vue Administration:
LoginModel code:
CompanyDbContext code:
ConfigurationValue code:
AppSettings code:
IDbContextService code:
DbContextService code:
Code de démarrage:
J'ai ajouté cette packages pour mon projet:
Mon appsettings.fichier json:
Veuillez vous mettre l'accent sur le concept de sujet pour se connecter à la base de données sélectionné dans la vue d'accueil, vous pouvez modifier une partie de ce code comme une amélioration, veuillez vous rappeler que je suis fournissant cette solution en faisant certaines hypothèses selon votre brève question, n'hésitez pas à demander au sujet de tout exposé aspect de cette solution pour améliorer ce morceau de code en fonction de vos besoins.
Fondamentalement, nous avons besoin de définir un service permettant de créer une instance de la base de données de contexte selon la base de données sélectionnée, c'est IDbContextService interface et DbContextService c'est l'implémentation de cette interface.
Comme vous pouvez le voir sur DbContextService code, on remplace les valeurs à l'intérieur de {} pour construire différents de la chaîne de connexion, dans ce cas, j'ai ajouté les noms de base de données dans la liste déroulante, mais dans le développement réel merci d'éviter de cette façon parce que, pour des raisons de sécurité, il est préférable de ne pas exposer les vrais noms de vos bases de données et d'autres configurations, vous pouvez avoir une parité table à partir du contrôleur de côté pour résoudre le code de l'entreprise selon la base de données sélectionnée.
Une amélioration pour cette solution, ce serait d'ajouter un peu de code pour sérialiser modèle de connexion sous forme de json dans la session au lieu de la stocker chaque valeur distincte.
S'il vous plaît laissez-moi savoir si cette réponse est utile.
PD: Laissez-moi savoir dans les commentaires si vous voulez le code complet à télécharger dans un lecteur
J'ai essayé de vous suivre parce qu'il fait sens pour moi, mais j'ai une erreur: erreur: 40 - impossible d'ouvrir une connexion à SQL Server...comment avez-vous créé les utilisateurs?
Selon votre message d'erreur, vous devez revoir votre chaîne de connexion
La même chaîne de connexion je l'ai essayer dans une autre application et cela a fonctionné
OriginalL'auteur H. Herzl
Depuis que vous êtes à la construction d'un multi-locataire de l'application web, vous devez d'abord décider comment allez-vous la distinction entre les locataires. Allez-vous les utiliser differnent URL? ou peut-être la même URL, mais l'ajout d'une partie dans l'URL?
En supposant que vous avez choisi ce dernier, le locataire 1 aurait une URL de ce type: http://localhost:9090/tenant1/orders
Locataire 2 aurait une URL de la forme: http://localhost:9090/tenant2/orders
Vous pouvez le faire en utilisant le routage d'URL:
Comme pour la chaîne de connexion, vous avez besoin d'une classe pour décider de la chaîne de connexion en fonction de l'URL, et injecter cette classe dans la DB contexte.
Dans votre base de données Contexte:
OriginalL'auteur Haitham Shaddad
Vous avez trouvé votre réponse, mais peut-être que mon post peut être utile pour quelqu'un. J'ai eu un problème semblable à cette question. J'ai dû changer mon entity framework connectionstring pour connecter les différentes serveur de base de données après que l'utilisateur est connecté. Et pour tout d'abord la solution que j'ai supprimé cette fonction de ma classe de contexte,
parce que je ne pouvais pas appelé à cette fonction à partir de l'extérieur. Et j'ai eu cette auto constructeur généré
Après la suppression, j'ai ajouté ce code de ma classe de contexte.
Enfin, maintenant, je peux changer ma chaîne de connexion à partir où je veux. C'est juste comme ça,
Espère que cela peut être bon pour quelqu'un.
OriginalL'auteur Emre SOLUĞAN
Mise à jour pour passer de la chaîne de connexion
Pour passer le générées dynamiquement connexion à votre contexte, créer une classe partielle dans le même contexte que votre contexte-classe partielle serait de s'assurer qu'elle reste intacte, si quelqu'un a un outil personnalisé (pour edmx), la génération automatique de code sera effacé et régénérée. Si vous avez ce code dans une classe partielle, il ne sera pas anéantie. Pour le premier code, cela ne s'applique pas. Voici le code:
La façon dont je l'ai fait dans le passé est d'avoir une base de données où les comptes (noms d'utilisateur, mots de passe) de tous les clients sont stockées. Le compte de l'exécution de l'application en vertu serait utilisé pour communiquer avec cette base de données pour authentifier le client qui se connecte (CompanyID, Mot de passe).
Par la suite, une fois authentifié, un jeton est généré. Par la suite, l'utilisateur authentifié serez en interaction avec le client (la Société) de la base de données. Pour cette partie, vous pouvez créer la connexion à la volée comme le montre ici mais je vais le copier et le coller comme:
Vous devrez fournir votre propre csdl, lsed, et msl noms dans le code ci-dessus. Si vous utilisez le Code d'Abord, puis votre chaîne de connexion n'aura pas besoin de les métadonnées.
Veuillez voir le jour.
J'ai essayé à partir d'autres postes. La propriété de Connexion dans la Base de données a été supprimée en EF de Base. Si je pouvais faire cela, savez-vous comment je pourrais passer une chaîne de caractères du paramètre connString lorsqu'une instance du Contexte est instancié?
Vous la passer au constructeur. J'ai juste fait cela il y a quelques jours et il fonctionne. Vous passez avant qu'il ne soit instancié (dans le constructeur). J'ai édité mon post. Vous n'avez pas besoin de ne rien faire, sauf pour créer un partiel avec un seul paramètre du constructeur.
OriginalL'auteur CodingYoshi
Vous pouvez essayer ce qui suit lors de la création de votre instance de contexte:
Puis faire un constructeur dans votre classe de contexte qui accepte une chaîne de caractères en paramètre, et l'utiliser comme:
OriginalL'auteur Awais Mahmood