ASP.NET

This topic applies to .NET version only 

You can use db4o as a persistent layer of your ASP.NET application. The actual integration of db4o into your web application is quite simple: you just need to add reference to Db4objects.Db4o.dll and use it in a client/server mode.

Security Requirements 

However, as it is characteristic to web-applications in general, there are some security permissions involved, which can in fact forbid db4o functionality in your ASP.NET application. So, before developing/deploying you should make sure that the required permissions would be granted to your application at the hosting server:

  1. ASPNET user should have read/write permissions to the directory containing database file. Obviously this is necessary to work with the database.
  2. Trust Level of your site should be set to "Full".

  3. All the necessary permissions should be granted to db4o assembly. The easiest way to ensure this is to add full trust to db4o:

    • For .NET 1.1 you can set this using caspol utility:
    • caspol -af Db4objects.Db4o.dll
    • For .NET versions >= 2.0 Db4objects.Db4o.dll should be installed in GAC

    If full trust is not a suitable solution for, you can check the minimum security permissions that db4o dll needs to operate using permcalc.exe tool from your Visual Studio installation.

    PermCalc.exe -Sandbox Db4objects.Db4o.dll

    sandbox.permcalc.xml
    01<?xml version="1.0"?> 02<Sandbox> 03 <PermissionSet version="1" class="System.Security.PermissionSet"> 04 <IPermission version="1" class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Read="*AllFiles*" PathDiscovery="*AllFiles*" /> 05 <IPermission version="1" class="System.Security.Permissions.ReflectionPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Flags="MemberAccess" /> 06 <IPermission version="1" class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Flags="UnmanagedCode, Execution, ControlEvidence" /> 07 <IPermission Window="SafeSubWindows" Clipboard="OwnClipboard" version="1" class="System.Security.Permissions.UIPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> 08 <IPermission version="1" class="System.Security.Permissions.KeyContainerPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" Unrestricted="true" /> 09 </PermissionSet> 10</Sandbox>

    Consult with your web-server administrator to grant these permissions.

Sample Application

Let's look at an example implementation: we will create a simple ASP.NET application, which will use db4o to store, retrieve and delete objects

The basic requirements for seamless db4o integration are:

In order to keep page-specific code clean we will implement db4o functionality in a separate Db4oHttpModule implementing IhttpModule interface.

Database file path can be saved in Web.Config:

<appSettings>
    <add key="db4oFileName" value="~/Data/Test.yap"/>
</appSettings>

Make sure that you have Data folder inside you web-site directory. ASPNET user should have enough rights to create and modify files inside this folder. You should also make sure that Data folder is not accessible to anonymous user; otherwise web-server visitors will be able to download your database.

We will open db4o connection only with the first client request:

Db4oHttpModule.cs: Client
01public static IObjectContainer Client 02 { 03 get 04 { 05 HttpContext context = HttpContext.Current; 06 07 IObjectContainer objectClient = context.Items[KEY_DB4O_CLIENT] as IObjectContainer; 08 09 if (objectClient == null) 10 { 11 objectClient = Server.OpenClient(); 12 context.Items[KEY_DB4O_CLIENT] = objectClient; 13 } 14 15 return objectClient; 16 } 17 }

Db4oHttpModule.cs: Server
01private static IObjectServer Server 02 { 03 get 04 { 05 HttpContext context = HttpContext.Current; 06 07 if (objectServer == null) 08 { 09 string yapFilePath = context.Server.MapPath(ConfigurationSettings.AppSettings[KEY_DB4O_FILE_NAME]); 10 11 objectServer = Db4oFactory.OpenServer(yapFilePath, 0); 12 } 13 14 return objectServer; 15 } 16 }

Db4oHttpModule.vb: Client
01Public Shared ReadOnly Property Client() As IObjectContainer 02 Get 03 Dim context As HttpContext = HttpContext.Current 04 Dim objectClient As IObjectContainer = TryCast(context.Items(KEY_DB4O_CLIENT), IObjectContainer) 05 If objectClient Is Nothing Then 06 objectClient = Server.OpenClient 07 context.Items(KEY_DB4O_CLIENT) = objectClient 08 End If 09 Return objectClient 10 End Get 11 End Property

Db4oHttpModule.vb: Server
01Private Shared ReadOnly Property Server() As IObjectServer 02 Get 03 Dim context As HttpContext = HttpContext.Current 04 If objectServer Is Nothing Then 05 Dim yapFilePath As String = context.Server.MapPath(ConfigurationManager.AppSettings(KEY_DB4O_FILE_NAME)) 06 objectServer = Db4oFactory.OpenServer(yapFilePath, 0) 07 End If 08 Return objectServer 09 End Get 10 End Property

The following code will ensure that the database is closed upon termination:

Db4oHttpModule.cs: Application_EndRequest
01private void Application_EndRequest(object sender, EventArgs e) 02 { 03 HttpApplication application = (HttpApplication)sender; 04 HttpContext context = application.Context; 05 06 07 IObjectContainer objectClient = context.Items[KEY_DB4O_CLIENT] as IObjectContainer; 08 09 if (objectClient != null) 10 { 11 objectClient.Close(); 12 } 13 14 objectClient = null; 15 context.Items[KEY_DB4O_CLIENT] = null; 16 }
Db4oHttpModule.cs: Dispose
1public void Dispose() 2 { 3 if (objectServer != null) 4 { 5 objectServer.Close(); 6 } 7 8 objectServer = null; 9 }

Db4oHttpModule.vb: Application_EndRequest
01Private Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs) 02 Dim application As HttpApplication = CType(sender, HttpApplication) 03 Dim context As HttpContext = application.Context 04 Dim objectClient As IObjectContainer = TryCast(context.Items(KEY_DB4O_CLIENT), IObjectContainer) 05 If Not (objectClient Is Nothing) Then 06 objectClient.Close() 07 End If 08 objectClient = Nothing 09 context.Items(KEY_DB4O_CLIENT) = Nothing 10 End Sub
Db4oHttpModule.vb: Dispose
1Public Sub Dispose() Implements IHttpModule.Dispose 2 If Not (objectServer Is Nothing) Then 3 objectServer.Close() 4 End If 5 objectServer = Nothing 6 End Sub

This is basically all the functionality that is required from db4o module. In order to make use of it we need to register it in Web.Config:

<httpModules>
      <add type="Db4objects.Db4odoc.Web.Data.Db4oHttpModule" name="Db4oHttpModule" />
</httpModules>

With the help of the created module we can access db4o database fairly easy:

Default.aspx.cs: SaveMessage
1public static void SaveMessage(string username, string text) 2 { 3 Message msg = new Message(username, text); 4 Db4oHttpModule.Client.Set(msg); 5 }

Default.aspx.cs: RetrieveAll
1public static IList RetrieveAll() 2 { 3 return Db4oHttpModule.Client.Get(typeof(Message)); 4 }
Default.aspx.cs: DeleteAll
1public static void DeleteAll() 2 { 3 IList messages = Db4oHttpModule.Client.Get(typeof(Message)); 4 foreach (Message msg in messages) 5 { 6 Db4oHttpModule.Client.Delete(msg); 7 } 8 }

Default.aspx.vb: SaveMessage
1Public Shared Sub SaveMessage(ByVal username As String, ByVal text As String) 2 3 Dim msg As Message = New Message(username, text) 4 Db4oHttpModule.Client.Set(msg) 5 End Sub

Default.aspx.vb: RetrieveAll
1Public Shared Function RetrieveAll() As IList 2 Return Db4oHttpModule.Client.Get(GetType(Message)) 3 End Function
Default.aspx.vb: DeleteAll
1Public Shared Sub DeleteAll() 2 3 Dim messages As IList = Db4oHttpModule.Client.Get(GetType(Message)) 4 For Each msg As Message In messages 5 Db4oHttpModule.Client.Delete(msg) 6 Next 7 8 End Sub

To test the whole application you can use the following simple form:

default.aspx
01<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Db4objects.Db4odoc.Web._Default" %> 02 03<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 04 05<html xmlns="http://www.w3.org/1999/xhtml" > 06<head><title>Guestbook.aspx</title></head> 07<body> 08 09<form id="Form1" runat="Server"> 10<b>Username:</b> 11<br><input id="username" type="text" size="30" runat="Server"> 12 13<p> 14 15<b>Message:</b> 16<br><textarea id="message" cols=60 rows=10 runat="Server"></textarea> 17 18<p> 19 20<input id="BtnGet" type="submit" value="Get messages" 21OnServerClick="ButtonGet_Click" runat="Server"> 22 23<input id="BtnSet" type="submit" value="Add message" 24OnServerClick="ButtonSet_Click" runat="Server"> 25 26<input id="BtnClear" type="submit" value="Clear messages" 27OnServerClick="ButtonClear_Click" runat="Server"> 28 29<span id="entries" runat="Server"/> 30 31</form> 32 33</body> 34</html>
default.aspx.cs
01using System; 02using System.Collections; 03using Db4objects.Db4odoc.Web.Data; 04 05namespace Db4objects.Db4odoc.Web 06{ 07 08 public partial class _Default : System.Web.UI.Page 09 { 10 protected void Page_Load(object sender, EventArgs e) 11 { 12 13 } 14 15 public static IList RetrieveAll() 16 { 17 return Db4oHttpModule.Client.Get(typeof(Message)); 18 } 19 // end RetrieveAll 20 21 public static void DeleteAll() 22 { 23 IList messages = Db4oHttpModule.Client.Get(typeof(Message)); 24 foreach (Message msg in messages) 25 { 26 Db4oHttpModule.Client.Delete(msg); 27 } 28 } 29 // end DeleteAll 30 31 public static void SaveMessage(string username, string text) 32 { 33 Message msg = new Message(username, text); 34 Db4oHttpModule.Client.Set(msg); 35 } 36 // end SaveMessage 37 38 public void ButtonGet_Click(Object s, EventArgs e) 39 { 40 entries.InnerHtml = ""; 41 IList list = RetrieveAll(); 42 foreach (Message msg in list) 43 { 44 entries.InnerHtml = "<hr>" + msg.ToString() + entries.InnerHtml; 45 } 46 } 47 // end ButtonGet_Click 48 49 public void ButtonSet_Click(Object s, EventArgs e) 50 { 51 SaveMessage(username.Value, message.Value); 52 username.Value = ""; 53 message.Value = ""; 54 } 55 // end ButtonSet_Click 56 57 public void ButtonClear_Click(Object s, EventArgs e) 58 { 59 DeleteAll(); 60 entries.InnerHtml = ""; 61 } 62 // end ButtonClear_Click 63 } 64}

default.aspx
01<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Default.aspx.vb" Inherits="Db4objects.Db4odoc.Web._Default" %> 02 03<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 04 05<html xmlns="http://www.w3.org/1999/xhtml" > 06<head><title>Guestbook.aspx</title></head> 07<body> 08 09<form id="Form1" runat="Server"> 10<b>Username:</b> 11<br><input id="username" type="text" size="30" runat="Server"> 12 13<p> 14 15<b>Message:</b> 16<br><textarea id="message" cols=60 rows=10 runat="Server"></textarea> 17 18<p> 19 20<input id="BtnGet" type="submit" value="Get messages" 21OnServerClick="ButtonGet_Click" runat="Server"> 22 23<input id="BtnSet" type="submit" value="Add message" 24OnServerClick="ButtonSet_Click" runat="Server"> 25 26<input id="BtnClear" type="submit" value="Clear messages" 27OnServerClick="ButtonClear_Click" runat="Server"> 28 29<span id="entries" runat="Server"/> 30 31</form> 32 33</body> 34</html>
default.aspx.vb
01Imports Db4objects.Db4o 02Imports Db4objects.Db4odoc.Web.Data 03 04 05Namespace Db4objects.Db4odoc.Web 06 Partial Class _Default 07 Inherits System.Web.UI.Page 08 09 Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 10 11 End Sub 12 13 Public Shared Function RetrieveAll() As IList 14 Return Db4oHttpModule.Client.Get(GetType(Message)) 15 End Function 16 ' end RetrieveAll 17 18 Public Shared Sub DeleteAll() 19 20 Dim messages As IList = Db4oHttpModule.Client.Get(GetType(Message)) 21 For Each msg As Message In messages 22 Db4oHttpModule.Client.Delete(msg) 23 Next 24 25 End Sub 26 ' end DeleteAll 27 28 Public Shared Sub SaveMessage(ByVal username As String, ByVal text As String) 29 30 Dim msg As Message = New Message(username, text) 31 Db4oHttpModule.Client.Set(msg) 32 End Sub 33 ' end SaveMessage 34 35 Public Sub ButtonGet_Click(ByVal s As Object, ByVal e As EventArgs) 36 entries.InnerHtml = "" 37 Dim list As IList = RetrieveAll() 38 For Each msg As Message In list 39 entries.InnerHtml = "<hr>" + msg.ToString() + entries.InnerHtml 40 Next 41 End Sub 42 ' end ButtonGet_Click 43 44 Public Sub ButtonSet_Click(ByVal s As Object, ByVal e As EventArgs) 45 SaveMessage(username.Value, Message.Value) 46 username.Value = "" 47 Message.Value = "" 48 End Sub 49 ' end ButtonSet_Click 50 51 Public Sub ButtonClear_Click(ByVal s As Object, ByVal e As EventArgs) 52 DeleteAll() 53 entries.InnerHtml = "" 54 End Sub 55 ' end ButtonClear_Click 56 End Class 57 58End Namespace

Persisting Objects in ASP.NET2 

If you are creating your application in ASP.NET2 you should take into consideration the fact that the assembly names are generated automatically on each build by default. Db4o distinguish persisted classes by name, namespace and assembly, so after the assembly name change, you won't be able to access classes saved with the previous version of the assembly.

There are several workarounds:

  • You can create a separate class library keeping db4o logic and persistent classes. This can also help if you need to access fully trusted db4o library from partially trusted ASP application
  • You can build your ASP.NET2 application manually using aspnet_compiler utility from .NET2 SDK.
  • aspnet_compiler.exe -v /WebSite -f -fixednames c:\WebSite -c -errorstack

  • You can use db4o aliasing API to redirect saved classes to the new assembly name. The following method should be called before opening database file to make all the classes within the namespace available after assembly name change:
  • Db4oHttpModule.cs: ConfigureAlias
    1public void ConfigureAlias() 2 { 3 Assembly assembly = Assembly.GetExecutingAssembly(); 4 String assemblyName = "Db4objects.Db4odoc.Web.Data.*, " + assembly.GetName().ToString().Substring(0, assembly.GetName().ToString().LastIndexOf("Version") - 2); 5 Db4oFactory.Configure().AddAlias(new WildcardAlias("Db4objects.Db4odoc.Web.Data.*, WebSite", assemblyName)); 6 }

    Db4oHttpModule.vb: ConfigureAlias
    1Public Sub ConfigureAlias() 2 Dim asm As Assembly = Assembly.GetExecutingAssembly() 3 Dim asmName = "Db4objects.Db4odoc.Web.Data.*, " + asm.GetName().ToString().Substring(0, asm.GetName().ToString().LastIndexOf("Version") - 2) 4 Db4oFactory.Configure().AddAlias(New WildcardAlias("Db4objects.Db4odoc.Web.Data.*, WebSite", asmName)) 5 End Sub

    You can use TypeAlias for aliasing only specific class.