24

我创建了一个新的ASP.NET MVC 4应用程序,并希望它先使用代码。但是,如果数据库文件不存在,它似乎不会最初创建它。如果我删除App_Data文件夹的.mdf文件,然后我得到,当应用程序试图访问数据库中的以下异常:如果我运行它代码第一次尝试创建数据库时出现异常

System.Data.SqlClient.SqlException: Cannot attach the file '<path-to-db-file>.mdf' as database '<my-db-file-name>'. 

在应用程序在调试器,那么我可以看到,在调用LazyInitializer.EnsureInitialized时,InitializeSimpleMembershipAttribute :: OnActionExecuting方法发生异常。捕获到的异常是:

[System.Reflection.TargetInvocationException] {"Exception has been thrown by the target of an invocation."} System.Reflection.TargetInvocationException 

随着内部异常:

[System.InvalidOperationException] {"The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588"} System.InvalidOperationException 

于是具有我在上面提到的作为其内部异常的第一个例外。

任何想法我做错了什么?

更新

我只是一个全新的MVC4应用尝试。我可以通过执行以下操作来复制它:

  1. 在VS向导中创建MVC应用程序。
  2. 第一次运行该应用程序并转到登录页面(注意现在生成的mdf文件)。
  3. 删除mdf文件,然后回到登录页面。现在抛出异常。
+7

你有没有想过这个想法? – Eonasdan

+0

@Eonasdan,一年后,是的。请看我的答案。 – joelmdev

回答

0

您必须停止IISExpress实例并重新启动它(通过在Visual Studio中按F5键)。然后您将能够再次创建数据库。

2

您可以处理的Code First数据库初始化在Global.asax文件的Application_Start方法中在项目的根文件夹,如下所示:

protected void Application_Start() 
    { 
     Database.SetInitializer<MyDBContext>(null); 
    } 

如果你传递null SetInitializer它不会创造或修改你的数据库表,你应该手动完成。

数据库不重新生成的原因是Application_Start在应用程序生命周期中仅触发一次。

+1

这不再是MVC4中的最佳做法。改为使用App_Start文件夹中的类。 – kingdango

2

MVC生成的代码使用名为“DefaultConnection”的数据库连接字符串。 如果您在Web.config中使用不同的名称,你需要参考该名:

  1. InitializeSimpleMembershipAttribute.SimpleMembershipInitializer.ctor()在InitializeSimpleMembershipAttribute.cs)。
  2. UsersContext.ctor()在AccountModel.cs

(或只是在你的项目中搜索 “DefaultConnection”)。

1

只有通过SQL管理工具或对象资源管理器,才能删除资源管理器中自动创建的.mdf文件。

你得到(并可以在您所提供的步骤复制)的问题是该数据库中的LocalDB仍注册。

+0

LocalDB支持数据库为文件,所以这不一定是真的。请参阅http://blogs.msdn.com/b/sqlexpress/archive/2011/07/12/introducing-localdb-a-better-sql-express.aspx – joelmdev

4

如果你深入到应用程序的InitializeSimpleMembershipAttribute类,你会看到它继承了ActionFilterAttribute类的以下重载方法:

public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     // Ensure ASP.NET Simple Membership is initialized only once per app start 
     LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock); 
    } 

注意评论。该应用程序每次运行检查一次,以确保简单成员资格已正确初始化。看看类别顶部的私有变量:

private static SimpleMembershipInitializer _initializer; 
    private static object _initializerLock = new object(); 
    private static bool _isInitialized; 

它们都是静态的,它们都是作为参考传递的。这里对你的情况最重要的是_isInitialized。什么LazyInitializer.EnsureInitialized做的是检查_isInitialized标志,如果是假的它初始化裁判瞄准它的过去,在这种情况下SimpleMembershipInitializer类型的_initializer。此时它将标志设置为真,然后继续。如果LazyInitializer.EnsureInitialized看到该标志是真的,它什么也不做,只是返回目标。由于该标志是一个静态变量,因此它在应用程序的整个生命周期中保持其值,这意味着在第一次初始化函数EnsureInitialized之后,即使数据库文件不再存在,它也会始终简单地返回目标。换句话说,如果在初始化后删除.mdf文件,则应用程序不会知道,并且应用程序试图从数据库读取或写入时会抛出异常。为了解决这个问题,你必须重新启动应用程序,这意味着杀死开发服务器,如果这是你正在使用或在IIS中重新启动应用程序。

所以这就是你面临的问题,但我怀疑很多跑过这个问题的人都有一个类似但不同的问题,他们在尝试登录时收到与此类似的错误消息:

CREATE FILE在尝试打开或创建物理文件'C:\ path \ to \ your \ project \ App_Data \ dbfile.mdf'时遇到操作系统错误5(访问被拒绝)。 CREATE DATABASE失败。列出的某些文件名不能被创建。检查相关的错误。

这很容易解决,我会尽快在这里介绍。

默认状态下的Visual Studio 2012使用的SQL Server Express的削减版本叫的LocalDB。 LocalDB将启动应用程序的子进程,如果您在Visual Studio的开发服务器上运行应用程序(例如,http:// localhost:[port]是您的浏览器中显示的内容),那么您正在运行应用程序和您的用户帐户下的LocalDB,而不是在SYSTEM或NETWORKSERVICE下。您需要做的所有事情就是为您的用户分配项目的App_Data文件夹的修改权限。再次尝试登录,应该成功创建.mdf文件。

如果你好奇,你可以了解更多有关的LocalDB here.

+0

修改App_Data文件夹的权限解决了我的问题。我希望这可以帮助别人。 – BrianLegg

9

得到了同样的问题,发现我的解决方案here。 所有你需要做的就是通过打开VS开发人员命令提示符停止的LocalDB并输入(不带引号):

“sqllocaldb.exe停止V11.0”

“sqllocaldb.exe删除V11。0"

下一次EF将重新生成文件以及数据库。

+0

您的链接帮助了我:) –

+2

LocalDB实例可能有其他名称。运行'sqllocaldb info'将列出所有现有的LocalDB实例。 – Paul

0

什么固定它对于我来说,当我收到这个错误是我在VS项目的App.config文件改变了连接字符串。

我已经在连接字符串中添加了这个:

<connectionStrings> 
<add name="Blog" connectionString="Data Source=(LocalDb)\MSSQLLocalDB;Integrated Security=true;AttachDbFileName=C:\Users\kostadin\Database1.mdf" providerName="System.Data.SqlClient" /> 

希望这有助于别人

012。
相关问题