简体   繁体   English

尝试在ASP.NET MVC应用程序中打开db4o数据库时,是什么导致此DatabaseFileLockedException?

[英]What is causing this DatabaseFileLockedException when trying to open a db4o database in an ASP.NET MVC app?

I'm building a small web application with ASP.NET MVC 2, using db4o as a datastore. 我正在使用db4o作为数据存储,使用ASP.NET MVC 2构建一个小型Web应用程序。

I have added an HttpModule—as per the example here —to give the application access to the db4o database, and everything is working perfectly on my development machine under the VS2008 ASP.NET Development Server. 我已经按照此处的示例添加了HttpModule,以使应用程序能够访问db4o数据库,并且在VS2008 ASP.NET开发服务器下的开发机器上,一切都能正常运行。

However, when I deploy the app to my web host and try to access it, I get a DatabaseFileLockedException at the line where the HttpModule tries to open the database file. 但是,当我将应用程序部署到Web主机并尝试访问它时,在HttpModule尝试打开数据库文件的那一行出现了DatabaseFileLockedException But there should be nothing else accessing the file; 但是应该没有其他访问文件的权限。 indeed on first run of the app it will only just have been created when this exception gets thrown. 实际上,在首次运行该应用程序时,它只会在引发此异常时才创建。

The web host's servers are running IIS 7 on Windows Server 2008, and the application is running under Full Trust. Web主机的服务器在Windows Server 2008上运行IIS 7,并且该应用程序在“完全信任”下运行。 It is a sub-application, in case that makes any difference. 如果有任何不同,它是一个子应用程序。

I can't work out why this error is occurring on the live server, but not locally on my development server. 我无法弄清楚为什么在实时服务器上而不是在开发服务器本地发生此错误。 Can anyone help me out or suggest what I should do next? 谁能帮助我或建议我下一步该怎么做?

That's a mistake in the example-code. 这是示例代码中的错误。 It assumes that the HttpModule.Init is only called once, which isn't necessarily true. 它假定HttpModule.Init仅被调用一次,这不一定是正确的。 Depending how your application is configured, it can be called multiple times. 根据您的应用程序的配置方式,可以多次调用它。 To fix this, check in the HttpModule-Handler if the instance is already there: 要解决此问题,请在HttpModule-Handler中检查实例是否已存在:

using System;
using System.Configuration;
using System.Web;
using Db4objects.Db4o;

namespace Db4oDoc.WebApp.Infrastructure
{
    public class Db4oProvider : IHttpModule
    {
        private const string DataBaseInstance = "db4o-database-instance";
        private const string SessionKey = "db4o-session";

        // #example: open database when the application starts
        public void Init(HttpApplication context)
        {
            if (null==HttpContext.Current.Application[DataBaseInstance])
            {
                HttpContext.Current.Application[DataBaseInstance] = OpenDatabase();
            }
            RegisterSessionCreation(context);
        }

        private IEmbeddedObjectContainer OpenDatabase()
        {
            string relativePath = ConfigurationSettings.AppSettings["DatabaseFileName"];
            string filePath = HttpContext.Current.Server.MapPath(relativePath);
            return Db4oEmbedded.OpenFile(filePath);
        }
        // #end example

        // #example: close the database when the application shuts down
        public void Dispose()
        {
            IDisposable toDispose = HttpContext.Current.Application[DataBaseInstance] as IDisposable;
            if (null != toDispose)
            {
                toDispose.Dispose();
            }
        }
        // #end example

        // #example: provide access to the database
        public static IObjectContainer Database
        {
            get { return (IObjectContainer)HttpContext.Current.Items[SessionKey]; }
        }
        // #end example

        // #example: A object container per request
        private void RegisterSessionCreation(HttpApplication httpApplication)
        {
            httpApplication.BeginRequest += OpenSession;
            httpApplication.EndRequest += CloseSession;
        }

        private void OpenSession(object sender, EventArgs e)
        {
            IEmbeddedObjectContainer container =
                (IEmbeddedObjectContainer)HttpContext.Current.Application[DataBaseInstance];
            IObjectContainer session = container.OpenSession();
            HttpContext.Current.Items[SessionKey] = session;
        }

        private void CloseSession(object sender, EventArgs e)
        {
            if (HttpContext.Current.Items[SessionKey] != null)
            {
                IObjectContainer session = (IObjectContainer)HttpContext.Current.Items[SessionKey];
                session.Dispose();
            }
        }
        // #end example
    }
}

As alternative you could use the Application_Start from the Global.apsx, which is called only once for sure. 作为替代方案,您可以使用Global.apsx中的Application_Start,它只能被调用一次。

You have another problem here. 您在这里还有另一个问题。

When AppPools restart there can be an overlap when the old AppPool is finishing request and the new AppPool is servicing new requests. 重新启动AppPool后,当旧的AppPool正在完成请求而新的AppPool正在为新请求提供服务时,可能会出现重叠。

During this time you will have two processes trying to access the same db4o file 在这段时间内,您将有两个尝试访问同一db4o文件的进程

To get around this you can use something like the hack below. 为了解决这个问题,您可以使用下面的技巧。

Note the use of Db4oFactory.OpenServer instead of Db4oEmbedded.OpenFile . 注意使用Db4oFactory.OpenServer而不是Db4oEmbedded.OpenFile This allows the use of transactions on a more fine grained basis. 这允许更细粒度地使用事务。

public IObjectServer OpenServer()
{
    Logger.Debug("Waiting to open db4o server.");
    var attempts = 0;
    do
    {
        try
        {
            return Db4oFactory.OpenServer(fileName, 0);
        }
        catch (DatabaseFileLockedException ex)
        {
            attempts++;
            if (attempts > 10)
            {
                throw new Exception("Couldn't open db4o server. Giving up!", ex);
            }

            Logger.Warn("Couldn't open db4o server. Trying again in 5sec.");
            Thread.Sleep(5.Seconds());
        }
    } while (true);
}

Hope this helps 希望这可以帮助

Sounds like permission issues if it works on dev. 如果适用于开发人员,这听起来像是权限问题。 Stick a notepad file in the same directory and try to open that with some bare bones file code. 将记事本文件粘贴在同一目录中,然后尝试使用一些裸露的文件代码将其打开。 I bet you'll have the same issue. 我敢打赌,您也会遇到同样的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM