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é?

Donc, vous avez besoin d'un modèle qui permet à l'ensemble de la chaîne de connexion dans la dynamique de la sorte ?
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