ASP.NET MVC 4, Die “WebSecurity.InitializeDatabaseConnection" - Methode nur einmal aufgerufen werden können
Ich entwickle ein code der ersten web-app in Visual Studio 2012 Express.
Benutze ich diesen connection string in der web.config:
<add name="myContext" connectionString="Data Source=.;Integrated Security=True;Initial Catalog=cityKingMVC4" providerName="System.Data.SqlClient" />
Ich bin mit SimpleMembership.
Ich versuche, Samen 1 administrator-Filter/InitializeSimpleMembershipAttribute.cs:
...
WebSecurity.InitializeDatabaseConnection("myContext", "Users", "UserId", "Email", autoCreateTables: true);
//A: Create Admin user
if (!WebSecurity.ConfirmAccount("[email protected]"))
{
WebSecurity.CreateUserAndAccount("[email protected]", "password");
}
//B: Create admin role if not exist
if (!Roles.RoleExists("Administrator"))
{
Roles.CreateRole("Administrator");
Roles.AddUserToRole("[email protected]", "Administrator");
}
Wenn ich Ein Kommentar & B es stürzt nicht ab. Wenn ich nicht ich bekomme diese:
Die "WebSecurity.InitializeDatabaseConnection" - Methode nur einmal aufgerufen werden können.
Wenn ich debug und setzen einen breakpoint auf 'WebSecurity.InitializeDatabaseConnection' - es Bedarf nur es einmal und es gibt keinen anderen code aufrufen WebSecurity.InitializeDatabaseConnection überall.
Wenn ich debug - stürzt es auf eine andere Zeile oben in der Datei (standard SimpleAuthentication-Datei):
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
mit diesem Fehler:
Ausnahme wurde ausgelöst durch das Ziel für einen Aufruf.
Stack Trace:
[InvalidOperationException: The "WebSecurity.InitializeDatabaseConnection" method can be called only once.]
WebMatrix.WebData.WebSecurity.InitializeMembershipProvider(SimpleMembershipProvider simpleMembership, DatabaseConnectionInfo connect, String userTableName, String userIdColumn, String userNameColumn, Boolean createTables) +87978
WebMatrix.WebData.WebSecurity.InitializeProviders(DatabaseConnectionInfo connect, String userTableName, String userIdColumn, String userNameColumn, Boolean autoCreateTables) +86
myapPMVC4.Filters.SimpleMembershipInitializer..ctor() in c:\Users\name\Documents\Visual Studio 2012\Projects\myapPMVC4\myapPMVC4\Filters\InitializeSimpleMembershipAttribute.cs:43
[InvalidOperationException: The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588]
myapPMVC4.Filters.SimpleMembershipInitializer..ctor() in c:\Users\name\Documents\Visual Studio 2012\Projects\myapPMVC4\myapPMVC4\Filters\InitializeSimpleMembershipAttribute.cs:88
[TargetInvocationException: Exception has been thrown by the target of an invocation.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +159
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +256
System.Activator.CreateInstance(Type type, Boolean nonPublic) +127
System.Activator.CreateInstance(Type type) +11
System.Threading.LazyHelpers`1.ActivatorFactorySelector() +72
System.Threading.LazyInitializer.EnsureInitializedCore(T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory) +241
System.Threading.LazyInitializer.EnsureInitialized(T& target, Boolean& initialized, Object& syncLock) +139
myapPMVC4.Filters.InitializeSimpleMembershipAttribute.OnActionExecuting(ActionExecutingContext filterContext) in c:\Users\name\Documents\Visual Studio 2012\Projects\myapPMVC4\myapPMVC4\Filters\InitializeSimpleMembershipAttribute.cs:22
System.Web.Mvc.Async.AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(IActionFilter filter, ActionExecutingContext preContext, Func`1 nextInChain) +145
System.Web.Mvc.Async.AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(IActionFilter filter, ActionExecutingContext preContext, Func`1 nextInChain) +840201
System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__31(AsyncCallback asyncCallback, Object asyncState) +266
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +146
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +202
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag) +112
System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__1e(AsyncCallback asyncCallback, Object asyncState) +839055
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +146
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +166
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag) +27
System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__17(AsyncCallback asyncCallback, Object asyncState) +50
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +146
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +166
System.Web.Mvc.Controller.BeginExecuteCore(AsyncCallback callback, Object state) +826145
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +146
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +166
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate endDelegate, Object tag) +27
System.Web.Mvc.Controller.BeginExecute(RequestContext requestContext, AsyncCallback callback, Object state) +401
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__2(AsyncCallback asyncCallback, Object asyncState) +786250
System.Web.Mvc.Async.WrappedAsyncResult`1.Begin(AsyncCallback callback, Object state, Int32 timeout) +146
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate`1 endDelegate, Object tag, Int32 timeout) +166
System.Web.Mvc.Async.AsyncResultWrapper.Begin(AsyncCallback callback, Object state, BeginInvokeDelegate beginDelegate, EndInvokeDelegate endDelegate, Object tag) +27
System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +343
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +12550291
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288
Was ist Los?
Thx
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Threading;
using System.Web.Mvc;
using WebMatrix.WebData;
using System.Web.Security;
using myapPMVC4.Models;
namespace myapPMVC4.Filters
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
//Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
//WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
if (!WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("myapPMVC4DBContext", "Users", "UserId", "Email", autoCreateTables: true);
}
//Create Admin user
if (!WebSecurity.ConfirmAccount("[email protected]"))
{
//WebSecurity.CreateUserAndAccount("admin", "pass", new { email = "[email protected]" });
WebSecurity.CreateUserAndAccount("[email protected]", "pass");
}
//Create admin role if not exist
if (!Roles.RoleExists("Administrator"))
{
Roles.CreateRole("Administrator");
Roles.AddUserToRole("[email protected]", "Administrator");
}
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
}
möglich, Duplikat der WebSecurity.InitializeDatabaseConnection-Methode nur einmal aufgerufen werden können
nicht kopieren - das sah, hat mir nicht helfen
Hinzugefügt stack-trace oben
InformationsquelleAutor niico | 2013-05-12
Du musst angemeldet sein, um einen Kommentar abzugeben.
Das problem ...
ist, dass
InitializeDatabaseConnection
AnrufeWebSecurity.InitializeProviders
intern, und diese Methode ist nicht thread-safe, dann kombinieren Sie dies mit der Tatsache, dass WebSecurity in der Regel muss die Initialisierung von verschiedenen Orten. Dies hat Auswirkungen auf die web-Anwendungen von Natur aus multi-threaded-Umgebungen ... undWebSecurity.Initialized
undWebSecurity.InitializeDatabaseConnection
sind nicht thread-sicher, wenn Sie zusammen verwendet - Sie erstellen eine typische race condition.Seeding (für die Migration) bedeutet, dass Ihre
WebSecurity
kann initialisiert werden, mehr als einmal müssen Sie möglicherweise auch, initialisieren Sie in den Globalen.asax.cs für Bereitstellungen mit Impfung ausgeschaltet, und IhreInitializeSimpleMembershipAttribute
können potenziell mehrmals aufgerufen werden simultaneusly von http-Anfragen im live-Bereitstellungen etc.Setzen Sie die Initialisierung code an mehreren stellen bricht auch Ihre TROCKENness
Die Lösung ...
Stellen Sie sicher, dass Ihre init-Aufrufe sind thread-sicher, und treten nur einmal pro Instanz einer Anwendungsdomäne. Verwenden Sie eine thread-sichere singleton-Klasse, um dies zu tun; und reduzieren Sie die Duplizierung von code.
Aufruf des singleton -
EnsureInitialize
Methode von jedem/alle der folgenden, für Ihre Anwendung geeignet:Application_Start
Methode, bevor irgendetwas anderes)Seed
- Methode (vor dem anlegen der Benutzer)SimpleMembershipInitializer
Konstruktor nach dem Kontext initialisiert ist)Hier ist ein einfaches Beispiel singleton:
Sobald ich dies getan hatte, in meinem Fall der Fehler, die Sie erwähnen, sind verschwunden, nicht wieder gesehen zu werden.
Fußnoten
Die singleton-Klasse auch hält Ihren code TROCKEN, was besonders nützlich während der frühen Phase der app-Entwicklung wenn Sie brauchen, um später ändern Sie die Konfiguration Ihres
WebSecurity.InitializeDatabaseConnection
da es nur an einem Ort sein (Ende edit)Ich habe auch immer die
SimpleMembershipInitializer
sauber, und statt Samen meine Benutzer zusammen mit der gemeinsamen Aussaat in Migrationen\Configuration.csSeed
Methode. Dies hilft bei der Testbarkeit von seeding durch meine Migrationen, indem Sie alles an einem Ort. Ich verwende unit-Tests, um sicherzustellen, können wir immer rauf und runter gehen die Migrationen Baum, so das macht es einfacher, das zu tun.Jedoch die Lage Ihrer seeding-code keine Rolle, es ist eher nur sicherstellen, dass, Global, müssen Sie initialisiert WebSecurity nur einmal innerhalb Ihrer Anwendungsdomäne, und dass jeder Aufruf
InitializeDatabaseConnection
thread-sicher ist.Die Umsetzung dieses jetzt - kann Sie empfehlen, alle Beispiel-Programme, die ich herunterladen kann, die zu übernehmen best practice - wie dieses. Ich bin neu in der MVC-und es wäre auch sehr hilfreich. MVCMusicStore geht nicht annähernd weit genug...
Wo empfehlen Sie putting diesem code?
Als eigene Klasse, Sie können es überall, solange es ist erreichbar, indem alle Punkte, die ich erwähnt habe, dass die Notwendigkeit, es zu nennen. Ich bin mir nicht sicher über die Probe - Anwendungen-die Vorlage aus VS sind ein guter Anfang, aber ich habe nicht gefunden eine gute, große, best-practice-Beispiele noch.
Um zu versuchen und zu verstehen, die situation zu verbessern. Ich habe dies in Erster Linie der Application_Start (): "wenn (!WebSecurity.Initialisiert) { System.Daten.Entität.Datenbank.SetInitializer(neue MyAppMVC4.Modelle.SampleData()); }' ich habe auch diesen, innerhalb InitializeSimpleMembershipAttribute.cs: if (!WebSecurity.Initialisiert) { WebSecurity.InitializeDatabaseConnection("MyAppMVC4DBContext", "Benutzer", "UserId", "E-Mail", autoCreateTables: true); } Was Sie sagen, ist, Sie zu Konflikten & brauchen Sie verschieben auf die gleiche Stelle im code, das ist nur einmal ausgeführt?
InformationsquelleAutor Andy Brown
Fügen Sie diesen code
Global.asax.cs
. Dies stellt sicher, dass Ihre Datenbank immer Initialisiert werden, bevor alle anderen Ausführungen. Auch stellen Sie sicher sein, die erste Anmeldung inApplication_Start()
Loszuwerden
Filters/InitializeSimpleMembershipAttribute.cs
oder kommentiert einfach den code im inneren, in Fall, dass Sie möchten, um wieder zu gehen.Entfernen
[InitializeSimpleMembership]
obenAccountController.cs
Auch wenn Sie noch nicht bereits aktiviert Migrationen, ich möchte Sie ermutigen, so zu tun. So können Sie Ihre Samen in
Configuration.cs
innerhalb desMigration folder
beim ausführenEnable-Migrations
InformationsquelleAutor Komengem
Wenn es bereits initialisiert, dann stellen Sie sicher, dass Ihr Erster Anruf:
Diese Weise werden Sie sicher sein, dass Sie nicht wiederholen Sie die Initialisierung.
Ich habe versucht Verpackung LazyLoader (siehe AccountController.cs oben) in diesem - hat nicht geholfen.
InformationsquelleAutor Husein Roncevic
Haben Sie auch die InitializeSimpleMembership-Attribut auf Ihre AccountController-Klasse? (dies ist die Standardeinstellung). Wenn ja, sind Sie initialisieren zweimal.
"Sie müssen rufen Sie die "WebSecurity.InitializeDatabaseConnection" - Methode vor dem Aufruf einer anderen Methode der "WebSecurity" - Klasse. Dieser Aufruf sollte sein gelegt in eine _AppStart.cshtml-Datei in das Stammverzeichnis Ihrer Website."
du bist absolut sicher, dass dies der einzige Ort, wo die InitalizeDatabaseConnection Methode ist? Bist du sicher, dass Sie nicht das Attribut in mehr als einem Platz?
Nein, wie ich oben sagst - Wenn ich entfernen [IntializeSimpleMembership] im AccountController.cs - ich bekomme den oben genannten Fehler (was bedeutet, es noch nicht initialisiert wurde an alle
Nein? Sie sind sich nicht sicher?
InformationsquelleAutor Erik Funkenbusch
Sicher zu stellen, dass die WebSecurity.InitializeDatabaseConnection nicht zweimal genannt, verwenden Sie einfach die WebSecurity.Initialisiert um zu überprüfen, ob es wurde bereits genannt. Diese blog-Beitrag finden Sie detaillierte Hinweise zu Aussaat-und customizing-SimpleMembership. Es ist eine Serie in diesem blog über die Verwendung SimpleMembership und ich würde auch empfehlen, sich auf Entkopplung SimpleMembership von Ihrem ASP.NET MVC-Anwendung. Sie können die kompletten source-code für diese Beispiele hier.
InformationsquelleAutor Kevin Junghans