Working with Offline Data in Briefcase files (.NET)

Briefcases provide support for persisting client data in a file or a folder. This can be useful in different scenarios, for example:

  • Briefcase can be used to store uncommitted data changes between client application restarts
  • Briefcase can be used to store rarely changed dictionary and lookup data. This will allow to avoid reloading of the same data from the server on every client application restart
  • Briefcase can be used to implement offline work mode for the client application.

Additionally a set of custom application-specific string properties can be stored alongside the data. For example, version number of the data format can be stored, to ensure newer versions of your application reload the stored data correctly, even if data format changes over time.

There are two different models of briefcase files - single-file briefcases (FileBriefcase class) and folder-based briefcases (FolderBriefcase class), respectively.

In single file mode all data tables and custom properties are stored in one single file (usually with a .daBriefcase extension). This provides convenient storage and makes it easy for users to handle briefcase files if necessary and to share them between platforms, but it also imposes some restrictions on the flexibility with which individual data tables can be read from and written to the file.

In folder mode, each table is written to an individual file inside a briefcase folder (usually with a .briefcase extension). This allows more flexible access for reading and updating individual tables.

In both cases, the data is stored using the highly efficient binary format provided by the Bin2DataStreamer, which is also recommended for the transfer of data between the client & server. In folder briefcase mode, each individual table is stored internally as a single-file briefcase and custom properties are stored in a separate .plist file.

The main advantage of using a Briefcase instead of some embedded database (f.e. SQLite.NET) to cache user data or to implement offline mode, is that a Briefcase stores not only user data but also its state (ie was some data row deleted, updated or inserted). This greatly simplifies synchronization with a Data Abstract-based server.

Note: Briefcase methods are not thread-safe. Briefcase data tables are safe for multithreaded read operations, however any write operations must be synchronized.

Working with Briefcases

The following mini sections take you through the operations of using a briefcase file.

Briefcase initialization

briefcase = new FileBriefcase(briefcaseFileName, true);

Note: There is no need to add '.briefcase' extension to the file name. If there is no extension in the provided file name then '.briefcase' extension will be added automatically.

If second constructor parameter is set to true then the Briefcase will be open for read. All data tables that it contains will be deserialized and loaded into memory.

briefcase.ReadBriefcase();
briefcase = new FolderBriefcase(briefcaseFolderName, true);

If second constructor parameter is set to true then Briefcase will be open for read and all containing data tables will be deserialized and loaded into memory. Setting this parameter to false will allow the data to be loaded lazily. In this case only the table names will be loaded into memory, while the data itself will be deserialized only on first request. This provides a reduction of memory consumption when briefcase contains large but rarely accessed data tables.

Due to different data storage methods, folder briefcases are more situated to store briefcases containing large data tables.

Accessing data stored in a briefcase

There are no differences in data access operations between folder- and file-based briefcases.

  • Adding new table to the briefcase:
briefcase.AddTable(dataTable);
  • Accessing a briefcase table by its name:
dataTable = briefcase.FindTable("TableName");

Note that this method returns a copy of the instance being stored in the briefcase, so changing a datatable acquired via the FindTable method won't affect the data being stored by the briefcase.

  • Deleting a table from the briefcase by its name:
briefcase.DeleteTable("TableName");

Note: This method will not immediately remove the table from disk; this only happens when the .WriteBriefcase() method is called to write the entire briefcase back to the disk.

  • Fill the DataSet instance with table data loaded from the briefcase
briefcase.Fill(dataSet);

It is also possible to provide a list of tables to load, when access to only a subset of briefcase tables is required.

Accessing custom data properties stored in the briefcase

  • Adding a new custom property to a briefcase:
briefcase.Properties.Add("PropertyName", "PropertyValue");
  • Accessing a custom property value by name:
customPropertyValue = briefcase.Properties["PropertyName"];
  • Deleting all the properties from the briefcase:
briefcase.Properties.Clear();
  • Removing a custom property specified by name:
briefcase.Properties.Remove("PropertyName");
  • Getting a count of the available custom properties:
propertiesCount := briefcase.Properties.Count;

Writing briefcase back to the disk

  • Writing a briefcase to the file system
briefcase.WriteBriefcase();

Please examine and run our Briefcases Sample sample to see the file- and folder-based briefcases in action.

See Also