overview

This is a short overview of how to use GraphDB from an admin (installation and configuration) and from a client (adding and consuming data) point of view, see the manual for a more complete description of the API.

admin api

The admin consists of only one class which collects both the user-oriented and the data-oriented management methods.

The setup of a fresh GraphDB store requires besides a connection string also the name and password of an administrator. This information is collected in an InstanceToken, it combines connection information with the admin's authentication details. This token has couple of static properties which can be used to quickly create a token or alter one.

For example, you can take the default values and only change the name of the store name:

var token = InstanceToken.Default;
token.StoreName = "MyStore";

Regarding the token and its fields it's important to note that

To install a fresh store using the default values you can simply call

StoreAdmin.Install();

This method runs asynchronously and if you wish to fetch the returned object you need to call is like this

var result = await StoreAdmin.Install();

The returned object (a ScriptResult object) will return whether the script was executed successfully and what the output was of the SQL-CMD executable.

To customize the setup you can pass a InstanceToken like so

var token = InstanceToken.Default;
token.StoreName = "MyGraphDBStore";
token.GraphDBAdminName = "Juan";
var result = await StoreAdmin.Install();

The result.Output of this should be something like

Copyright (c) 2007-2014.
GraphDB database setup version 2014.1
Changed database context to 'master'.
Creating the database
Altering the properties of the database
Fulltext is not installed, please install it first.
Changed database context to 'master'.
Assigning the filestream to the database
Changed database context to 'MyGraphDBStore'.
Creating schema's
Creating the fulltext catalog
Fulltext is not installed, please install it first.
Creating tables
Creating the views
Creating functions
Creating the stored procedures
Adding some required data
Database creation successful!

To confirm that a certain store is installed you can use the StoreExists method. To drop a store you can call

StoreAdmin.DropStore();

which returns a boolean value indicating the success or failure of the drop. If you try to drop a store which doesn't exist an exception will be raised.

The setup of a store will configure the store for internal authentication, meaning that GraphDB users will be managed and authenticated through the store itself. If you want to have external authentication you need to change this immediately after setup:

StoreAdmin.ConfigureStoreForFormsAuthentication(…);

With the following parameters:

It's important to note that configuring the store will drop and recreate all the users in the store. You will lose all users, including the existing admin, if you perform a reconfiguration in alter point in time when you have already created users. The external admin defined in the ConfigureStoreForFormsAuthentication will be created if it does not exist already in the membership database. If the specified user does exist it will be validated with the provided credentials.

Note: right now GraphDB does not include external authentication on the basis of the more recent SimpleMembership mechanisms. It will be included in the future however.

A concrete example of the reconfiguration could be

StoreAdmin.ConfigureStoreForFormsAuthentication(
    token.ConnectionString, "Peter", "ùRla=4423", 
    "data source=.;User=sa;Password=123456;Database=AspNetMembershipDb");

One obvious but often forgotten detail is that in order to make this work you need to define the membership in a configuration file. The typical configuration would look like this

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
        <clear/>
        <add name="MembershipDB"
          connectionString="Some Bogus String here that gets overrided in the custom class"
          providerName="System.Data.SqlClient"/>
    </connectionStrings>
    <system.web>
        <authentication mode="Forms"/>
        <authorization>
            <deny users="?"/>
        </authorization>
        <membership>
            <providers>
                <remove name="AspNetSqlMembershipProvider"/>
                <add name="AspNetSqlMembershipProvider"
                  connectionStringName="MembershipDB"
                  applicationName="GraphDB"
                  type="GraphDB.Shared.GraphDBMembershipProvider, GraphDB.Shared"
                  requiresUniqueEmail="false"
                  requiresQuestionAndAnswer="false"/>
            </providers>
        </membership>
    </system.web>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
    </startup>
</configuration>

If you don't specify this the reconfiguration will not throw an exception but simply hang.

The connection string parameter in the membership configuration above is necessary for the ASP.Net Mechanism to work but its content is not relevant since it is being supplied in the ConfigureStoreForFormsAuthentication. It means that the membership database is provided during setup and cannot be altered by a client. Indeed, otherwise it would be possible by a consumer of the store to login by means of a self-defined (bogus) membership database and thus access any store as an administrator. The GraphDBMembershipProvider is a custom membership provider which ensure that security cannot be compromised.

To confirm that the store has an external authentication you can use

StoreAdmin.GetAuthenticationType(token);

which should return 'WindowsForms'. The default would return 'Internal' instead.

Whether you have a store with internal or external authentication, you gain access to the store through a security context

var myUserSecurityContext = StoreAdmin.Login(token);

The login is also available through the client API of course. This user context is used in each and every interaction with the store and defines who you are and what you can do inside the store. If you are an admin of the store you e.g. confirm this by means of

myUserSecurityContext.IsStoreAdmin

Whether the store has internal or external authentication you can add a new user with a simple

StoreAdmin.AddUser("YourNewUserName","TheUserPassword",token);

Of course, if the authentication instance is external it dictates all the constraints. For example, if the password you supply does not satisfy the password expectations you will get

The password supplied is invalid. 
Passwords must conform to the password strength requirements configured for the default provider.

Changing password (for either authentication mechanism) works with the ChangePassword command while deleting a user can be done using DeleteUser. If you attempt to delete the admin of the store you will receive an exception stating

The system admin should not be deleted.

The admin cannot be removed once assigned at setup. There is a related concept of 'admin' when dealing with workspaces and which refers to the owner or owners of the workspace. This ownership can be revoked or transferred but has nothing to do with the owner, i.e. admin, of the store. The admin of the store is the only user who can manage other users and potentially delete/manage their data without being the owner. Of course, if you wish to use a store without adding other users you can do so since an admin can own workspaces and data as well. The collaboration features are always 'on' but optional. Even if multiple users are present inside a store, if they do not share their workspace they will happily own their data without any interference with others.

client api

The client API allows a user to add and manage data, share it, create workspaces and more. It does not allow the creation of a new store, manage users or security. If you do have an account in a store it's because the admin of the store has created a user for you. Of course, if you if you are the admin of a store and linked both the admin and client API in your application you can fully use all functionalities of the store.

The user can be an internal user or an external user. If the store is configured for external users it means the authentication occurs outside the store and you need the standard ASP.Net membership configuration. If the store is configured for internal users you only need the credentials, the connection details and the client assemblies to access the store.

Usually you start with a login, which with a default installation amounts to

var me = DataManager.Login(InstanceToken.Default);

The token defines the connection to the store (in essence a connection string) together with the name and password of the user. If you have a default setup and only the admin is present the statement above opens the store for you. If you have other credentials or a non-default setup you can instantiate a token or alter the default one. For example;

var token = InstanceToken.Default;
token.UserName = "JustMe";
token.Password = "MySecret";
token.StoreName = "MyGraphDBStore";
var me = DataManager.Login(token);

If you are successfully logged in the 'me' variable contains the security context with which all methods are called. For instance, you can create and insert an Address entity like so

var address = new Address
            {
                AddressLine1 = "Rialto 3b/5",
                City = "Rome",
                Country = "Italy",
                Title = "Company address"
            };
DataManager.AddEntity(address, me);

When you add an entity a whole lot of gears start to spin. Some things are important to know in this context:

As long as you don't explicitly change the current workspace you stay in either the last one you have used or the default one. When a user is created a default workspace is rolled out and at any moment a user has at least one workspace present thus enforcing to always have a workspace where things can be added. There is no limit to the amount of workspaces you can have and the way you wish to partition things is up to you. GraphDB offers a great deal of flexibility in the way data can be partitioned or organized. Usually a workspace is used to define either a semantic boundary or a security boundary (sharing and collaboration).

If you wish to add a new "Documents" workspace just enter

DataManager.AddWorkspace("Documents", me);

You see the workspaces you have access to by means of

DataManager.GetWorkspaces(me);

Note that this list shows also the workspaces someone has shared with you. If none have been shared (i.e. you do not have a role in any other workspace than the ones you have created yourself) you see only the spaces you are the owner of. Workspace are really like rooms in a building and the sharing or collaboration means doors have been created.

When you wish to change workspace you need to explicitly say so. This requires the identifier of the workspace rather than the name because the name of a workspace is not necessarily unique (certainly not across users):

var myspaces = d.GetWorkspaces(me);
var id = myspaces.Single(s => s.Name == "Documents").Id;
DataManager.SetActiveWorkspace(id, me);
var currentWorkspace = DataManager.GetCurrentWorkspace(me);

At any moment you can only be in a single active workspace and a data entity can belong only to one workspace. While this might seem like a harsh constraint, the sharing of workspaces means that (provided your role in a share allows it) you can access entities in other workspaces with ease. It also simplifies considerably the security concerns on many levels.

The scope of a user is the collection of data accessible to the user. If no workspace has been shared the scope is the collection of entities in the workspaces of the user. If workspaces have been shared it includes the data available to him. To search the above address entity within the scope you can use

var address = DataManager.FindNode("home*", null, me);

This is a simple search for "home" within the scope and an arbitrary entity type. The 'null' value can be replaced in general with whatever data type you have stored, it narrows the search to a certain data type. The search

DataManager.FindNode("home*", "Company", me);

will not return anything while

var address = DataManager.FindNode("home*", "Address", me);

would narrow down the search to entities of type Address.

The store allows you to use tags to tag data entities. A tag being a special kind of node in a graph which adorns other data nodes. In addition, a special tag-type has been defined to collect entities in a favorites collection. To add a node to your favorites just use

DataManager.AddToFavorites(address, me);

To tag an entities with e.g. "Special addresses" you would use

DataManager.AddToTag(address, "Special addresses", me);

The API has many more methods related to tags and favorites to manage all this. The tagging is user-bound but is workspace independent, which allows you to combine entities is another way than the way they sit in workspaces. You can look at workspaces as chapters in a book and tags as the index. It's a well-known mechanism used in CMS and mail systems to organize data.

Combining entities into a graph structure is done by a simple connect statement

var connection = DataManager.Connect(me, sourceEntity, targetEntity);

It creates a 'foreign key' if you wish and you can adorn this connection with various bits: a weight factor, a title…as well as an entity. Technically speaking, both a data node and a connection are generic objects with a payload. You can assign properties as well as an arbitrary data object. The Connect method has overloads to achieve this or you can alter a Connection in the same way you would alter a data node;

Connection.Title = "Professional details";
DataManager.UpdateConnection(connection, me);

GraphDB also defines a more sophisticated way to add/update data by means of a Graph structure which effectively combines the methods highlighted above.

Sharing data and workspaces means you enlarge the data scope of another user. You grant access together with a role which restricts the user to certain actions. The fact that connections (relationships) exist between data nodes somewhat complicates the security mechanisms found in classic linear system, a detailed overview being outside the scope of this introductory article. For the user sharing his data things amount however to the simple choice of either making another user a co-owner (co admin), an editor of his data or a reader. This threefold distinction is somewhat similar to the one found in CMS systems. The set of roles is kept to this minimum in order to keep things a straightforward as possible but could be enlarged in function of customer needs.

To grant access to a user with name 'Someone else' with a role 'Editor' to your workspace you would use the following

DataManager.GrantAccess("Someone else", "Documents", "Editor", workspace, me);

Revoking access or changing a user's role would be done similarly. When a user gets access his search actions will include the newly accessible data nodes and can create connections to it.

Sharing and collaboration can also be enabled on a workspace level. You can declare a workspace to be 'public' and thus allow anyone to search for it or create connections without explicitly declaring a share with a particular user. For example, a project manager could work as part of a larger team and define common documents which he manages (i.e. he's the owner) inside a public workspace but allows anyone to consult. GraphDB also defines read-only and protected workspaces but here again, discussing this in detail would go outside the scope of this introduction.

Many methods in the client API help the user to figure out what the effective permission is of a particular node or workspace, for instance

DataManager.GetWorkspaceAccessOverview(workspace, me);

will return an overview of the users, their role and permissions on your workspace. Much effort has been put to make things as easy and productive as possible.

The client API defines many pre-defined entities like Address, Person, Thought, Task, EmailAddress, TwitterUser and more. Adding your own custom entities is really easy and does not force you to implement XML serialization unless you desire to do so. You can rely on the automatic (WCF based) serialization, customize it with attributes or push the pedal by implementing the serialization interface (giving you the maximum flexibility).