Friday, 10 October 2008

Ajax Web Parts Part 4 - Dynamic Web Part Connections

Posts In This Series:

Introduction - ASP.NET AJAX and Web Parts
Ajax Web Parts Part 1 - Drag and Drop
Ajax Web Parts Part 2 - Web Part Connections
Ajax Web Parts Part 3 - Dynamic Web Parts
Ajax Web Parts Part 4 - Dynamic Web Part Connections


Download the source - Part 1
Download the source - Part 2
Download the source - Part 3
Download the source - Part 4




Introduction

Currently the dynamically created Web Parts (described in part 3) cannot be moved between zones. In addition, doing a postback results in more dynamically generated Web Parts appearing. This occurs because the Web Part Manager assigns each dynamically created Web Part a random ID when its AddWebPart() function is called. To fix this problem we need a Web Part Manager that doesn’t assign random IDs and, luckily for us, Lee Dale has created just what we’re after.

Modifying Lee’s code slightly, so that it derives from the Preview DLL’s WebPartManager, rather than the standard WebPartManager (to ensure cross browser drag and drop), gives the following:


namespace AjaxWebParts.Controls
{
public class DynamicWebPartManager
: Microsoft.Web.Preview.UI.Controls.WebParts.WebPartManager
{
public void AddDynamicWebPart(WebPart webPart,
Microsoft.Web.Preview.UI.Controls.WebParts.WebPartZone zone)
{
Internals.AddWebPart(webPart);
Internals.SetZoneID(webPart, zone.ID);
}
}
}


To use this new Web Part Manager we need to make the following changes:

In our DynamicWebParts class, make the following changes:

1. change the WebPartManager alias at the top of the line to become the following:


using WebPartManager = AjaxWebParts.Controls.DynamicWebPartManager;


2. change the addition of the dynamically created Web Part to the Web Part Zone to use the DynamicWebPartManger’s function. So the current


return itsManager.AddWebPart(genericWebPart, zone, 0);


is replaced by:


itsManager.AddDynamicWebPart(genericWebPart, zone);
return genericWebPart;


In the default.aspx page the following changes are required:

1. Add the following to the set of namespace registrations:


<%@ Register Namespace="AjaxWebParts.Controls" TagPrefix="awp" %>


2. Change the reference to the Web Part Manager from “cc1:WebPartManager” to “awp:DynamicWebPartManager”

After these changes have been made everything should now work as it should: the dynamically created Web Parts should now be able to be dragged between zones and multiple Web Parts should not appear when postbacks occur. All that is required now is to implement the connection between the dynamic Web Parts.



Creating Dynamic Web Part Connections

Once dynamic Web Parts exist, with non-random ID values, creating the connections between them is relatively straightforward. We simply need to get the connection point from each Web Part and then, if a connection can be made between the Web Parts, simply create a connection that joins the two connection points.


We therefore need to add a new function to our DynamicWebParts class to create the Web Part connection, as follows:








Finally we need to call this function from our default.aspx.cs code-behind file. The Page_Init() function now becomes:






Now, when the Web Page is run, the dynamically generated Web Parts will be connected. Typing a value into the dynamic provider's text box and clicking the button will result in the value being displayed in the dynamically created consumer Web Part.




Creating Dynamic Web Part Zones

Now that we can dynamically create Web Parts, lets move on to create the rest of the page dynamically, starting with the Web Part Zones.
This is very straightforward – it’s simply a case of creating an instance of a WebPartZone and adding it to the page (note that the WebPartZone that gets created is from the Preview DLL, due to the alias that was declared).

The DynamicWebParts class member function therefore appears as follows:




Similarly, we can create the WebPartManager:




and the UpdatePanel:



Since all the page components can now be created dynamically, the static components in the page markup are no longer required. This page therefore simplifies down to:



Note that a PlaceHolder component has been added to give us somewhere to add our dynamic components.

In the Default.aspx.cs code behind file the Page_Init function now becomes:



And, since the page markup no longer defines a WebPartManager, this needs to obtained dynamically when needed. So the Page_load function now changes to become:




Click here to see this in action.


Putting this all together results in an ASP.NET AJAX page, featuring 2 Web Part Zones and 2 dragable, connected, Web Parts. Everything has now been created dynamically and is therefore just what’s required for populating tab pages.

Tuesday, 7 October 2008

Ajax Web Parts Part 3 - Dynamic Web Parts

Posts In This Series:

Introduction - ASP.NET AJAX and Web Parts
Ajax Web Parts Part 1 - Drag and Drop
Ajax Web Parts Part 2 - Web Part Connections
Ajax Web Parts Part 3 - Dynamic Web Parts
Ajax Web Parts Part 4 - Dynamic Web Part Connections


Download the source - Part 1
Download the source - Part 2
Download the source - Part 3
Download the source - Part 4




Introduction

So far, in this series on Ajax Web Parts, all the components have been created at design time. The Web Part Zones, the Web Parts themselves, and the connections between them, have all been added statically to the page markup.

In order to achieve our ultimate goal, of movable Web Parts in a user created tab framework, we now need to change to using dynamically created components:

  • Web Part Zones need to be dynamically created so that, eventually, they can be used to populate each tab page.

  • Web Parts and their connections need to be generated at run time to populate the Web Part Zones.

Therefore, we will now investigate how the previous project can be changed to add these dynamic components.



Creating Dynamic Page Components

The easiest way to create dynamic page components is by copying static components – that is, firstly create the required components in the ASP.NET markup and then, once this is working, copy the structure to create the same components dynamically.
We will use this approach to replace the Web Part components that were statically created in the last posts, with a new class that can dynamically generate the same components.



A Dynamic Web Part Class

Rather than simply adding everything to the web form’s code-behind file, we will create a class to create the dynamic components. So first of all, we need to add a new class to the project as follows:


  1. Right-click on the project’s “app_code” node and choose “Add New Item”.
  2. In the dialog that appears choose to add a new class and give this the name “DynamicWebParts.cs”.
  3. Once the class has been added to the project, change the constructor so that it takes an instance of the page and add a property to hold a reference to this value. This is required to give us something to add our components to. The page comes from the System.Web.UI namespace, so a “using” line needs to be added for this.


At this stage the class should look as follows:




In addition to a page, to which the Web Parts can be added, the other thing that is required to create dynamic Web Parts is a Web Part Manager. For now we will simply pass through the static Web Part Manager that exists on the page and store this into a property as follows:



private WebPartManager itsManager;
public WebPartManager Manager
{
set { itsManager = value; }
}


Namespace Selection

If you remember from the previous posts, to get cross-browser drag and drop support we needed to use the Web Part Manager from the Microsoft Web Preview release. Therefore we need to use the same version here in our class. Therefore, at the top of the page the following “using” statement is required:


using Microsoft.Web.Preview.UI.Controls.WebParts;


This namespace is used to give us the Web Part Manager and Web Part Zones needed for cross-browser drag and drop.
However, the Web Parts themselves still come from the standard System.Web.UI.WebControls.WebParts namespace. Therefore, to avoid a clash, we need to explicitly state that the Web Part Manager and Web Part Zones come from Preview DLL. This can be done by specifying the full namespace every time we refer to the WebPartManager and WebPartZones. However this is rather cumbersome.

A more elegant approach is to add an alias so that both WebPartManager and WebPartZone will always reference the Preview DLL's versions. To do this the following lines should be added:




using WebPartManager = Microsoft.Web.Preview.UI.Controls.WebParts.WebPartManager;
using WebPartZone = Microsoft.Web.Preview.UI.Controls.WebParts.WebPartZone;


(Another approach that can be used to specify which DLL to use, when referring to a control, is to use tag mapping in the web.config file. However, this will only work for controls declared in markup and is therefore not appropriate for dynamically created controls. See David Barkol's blog for details)



Dynamic Web Parts

Everything is now in place to allow us to dynamically add some Web Parts to the page. As a first step, let’s replace the static Provider and Consumer Web Parts that were created in the last part of the series. Both of these Web Parts were formed by taking User Controls and adding them to Web Part Zones to create Web Parts. We will use a similar approach when dynamically generating the Web Parts. The function to take a User Control and add it to a Web Part Zone is shown below:





Notice how the steps required to dynamically add a Web Part closely resemble those used to statically add one:

· once again a User Control is loaded (using the Page’s LoadControl function)
· a Web Part is then created (by calling the Web Part Manager’s CreateWebPart function) and added to a Zone (using the Web Part Manager’s AddWebPart function).

Other points to note here are:
1. We’ve created a unique ID for control by simply taking the title supplied for the Web Part and removing any spaces from it.
2. To get the Web Part Zone we need to search the Web Part Manager’s list of Zones until the supplied name is found.
3. The Web Part Manager’s AddWebPart function takes a copy of the supplied Web Part and returns a reference to the copy. Therefore it is this that needs to be returned to get access to the Web Part that actually exists on the page (rather than the Web Part that was created using CreateWebPart).


All that’s required now is to actually use this new function to programmatically generate some Web Parts. Therefore, back in the Default.aspx.cs code behind file, add the following:




This creates an instance of our new class, sets the Web Part Manager to the one that exists in the markup and then creates 2 Web Parts – a Provider, which is added to the first Web Part Zone and a Consumer, which is added to the second Web Part Zone.

Running this should give the following output:





Click here to see this in action.

Note, that at this stage, the dynamic Web Parts cannot be moved between zones. Trying to move them results in more Web Parts appearing. This is a result of the way in which the standard Web Part Manager assigns IDs to the Web Parts and we'll look at this more closely in the next post.


Conclusion

Both statically and dynamically created Web Parts now exist on the page. The statically created Web Parts have a connection between them; any text typed into the input field of the provider Web Part will appear in the label of the consumer Web Part when the button is clicked. The dynamically created Web Parts are not yet connected and, as we'll see in the next part of this series, creating this connection is not as straightforward as it should be (this seems to be a recurring theme!). In addition, drag and drop doesn't yet work for the dynamically created Web Parts - this is something that will also be resolved in the next post.

Monday, 15 September 2008

Ajax Web Parts Part 2 - Web Part Connections

Posts In This Series:

Introduction - ASP.NET AJAX and Web Parts
Ajax Web Parts Part 1 - Drag and Drop
Ajax Web Parts Part 2 - Web Part Connections
Ajax Web Parts Part 3 - Dynamic Web Parts
Ajax Web Parts Part 4 - Dynamic Web Part Connections


Download the source - Part 1
Download the source - Part 2
Download the source - Part 3
Download the source - Part 4



Introduction

The first part of this series introduced the components required to perform basic Web Part drag and drop.

In that post a simple Web Part was created from the Calendar component. This was then used to illustrate how a Web Part could be moved between Web Part Zones that had been created at design time.

Although the Calendar component was useful for illustrating how a Web Part can be moved between zones, it doesn’t really give a realistic view of how Web Parts would be used in a real-world situation. For this we need something slightly more complex – a pair of Web Parts that communicate via a connection.



Click here to see what will be created.



Web Part Connections

Two Web Parts are required to form a Web Part Connection; a Provider Web Part to initiate the connection and a Consumer Web Part to receive the connection.

For our example, both of these Web Parts can be formed by creating a standard User Control and then adding it to a WebPartZone (by dragging it from the Solution Explorer window and dropping it into the WebPartZone in the Design view of the Web Form).

For simplicity the Provider part consists of only 2 items: a text box to enter a string and a button to send the string to the Consumer part. So, in the markup, the Provider is given by:






The Consumer only contains a label, to display the string that is received from the Provider. Its markup is therefore as follows:






To allow these Web Parts to communicate we must now define the connection between them. This is done by creating an interface that specifies the type and name of parameters that may be passed between the Web Parts.

In our case we are only sending a string (the text entered into the text box) from the Provider to the Consumer. The interface (in the sample download code this is defined in IWebPartInterface.cs within the App_Code directory) therefore defines that the Consumer can get a single string, called Message, from the Provider and appears as follows:


public interface IWebPartInterface
{
string Message { get;}
}



In the code-behind the User Controls must specify the part they play in the connection.

The Provider, as its name suggests, must provide the interface. It does this by having a function that returns the interface. This function is identified by using the ConnectionProvider attribute. Each end of the connection is referred to as a Connection Point. The ConnectionProvider attribute takes a parameter that assigns a name to the connection point (for our provider we’ve radically called it “ProviderConnectionPoint”).

Since, in our case, the Provider class inherits from the IWebPartInterface the member function can simply return an instance of its class (i.e. it returns this).

Finally, the Provider needs to actually return some data to give to the consumer. In our case this is simply the value that gets entered into the text box and, from the interface we’ve defined, we know that this value should be labelled as Message.

Therefore the complete code-behind of the Provider class is as follows:


public partial class User_Controls_Provider
: System.Web.UI.UserControl, IWebPartInterface
{
[ConnectionProvider("ProviderConnectionPoint")]
public IWebPartInterface GetProviderData()
{
return this;
}

public string Message
{
get { return TextBox1.Text; }
}
}



In the Consumer the ConnectionConsumer attribute is used to specify that the SetProviderData method is used to get the interface and store it into a local variable.

Once the connection has been established between the Provider and the Consumer, the Consumer can use it to set the text of its label and this is done at the pre-render stage of the page lifecycle.


public partial class User_Controls_Consumer
: System.Web.UI.UserControl
{
IWebPartInterface itsProvider = null;

[ConnectionConsumer("ConsumerConnectionPoint")]
public void SetProviderData(IWebPartInterface aProviderData)
{
itsProvider = aProviderData;
}

protected override void OnPreRender(EventArgs e)
{
if (itsProvider != null)
{
Label1.Text = itsProvider.Message;
}
base.OnPreRender(e);
}
}



Finally, the connection needs to be specified in the Web Part Manager. This needs to define which Web Part acts as the provider of the connection and which as the consumer. So, for the Web Parts we’ve defined, the markup appears as follows:




Putting this all together results in a Web Page consisting of 2 Web Parts that can be dragged between the Web Part Zones and that can communicate. Entering some text into the provider Web Part’s text box and clicking on the button results in the text appearing in the consumer Web Part, as shown below:






Click here to see this in action.



Conclusion

This post has expanded our Web Part example to show how 2 Web Parts can communicate using a Web Part Connection. Everything has still been created statically at design time. In the next post I’ll look at how these Web Parts and Web Part Zones can be created dynamically to form a tab framework.


Links


More information on Web Part Connections can be found at the following:

http://www.carlosag.net/Articles/WebParts/connectionsTutorial.aspx

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webparts.webpartconnection.aspx





Saturday, 7 June 2008

Ajax Web Parts Part 1 - Drag and Drop

Posts In This Series:

Introduction - ASP.NET AJAX and Web Parts
Ajax Web Parts Part 1 - Drag and Drop
Ajax Web Parts Part 2 - Web Part Connections
Ajax Web Parts Part 3 - Dynamic Web Parts
Ajax Web Parts Part 4 - Dynamic Web Part Connections


Download the source - Part 1
Download the source - Part 2
Download the source - Part 3
Download the source - Part 4



Introduction
In this post I'm going to describe the very basic steps required to get Web Parts drag and drop up and running from scratch. This will use a Calendar item, added to a Web Part Zone, to make a generic Web Part. This is the standard demonstration of Web Parts that has been used in a multitude of other Web Part tutorials - it's replication here is purely to get the basic components in place before moving on to other, more advanced, topics.

Click here to see what will be created.

Required Components
At present, due to the evolving nature of the subject, there are a large number of different versions of ASP.NET and its related components. These components can appear in releases with titles such as “futures”, “extensions” and “Community Technology Previews (CTPs)". As a result, one of the major challenges when working with ASP.NET is finding the appropriate set of components to use – each release appears to have its own unique fixes and quirks and, consequently, it can be difficult to find the correct combination to achieve the desired results. Hopefully ASP.NET 4.0 will fix all the bugs and tie everything together!

Therefore, when working with ASP.NET AJAX and Web Parts we will require more than the standard ASP.NET framework; extra components are needed either to add functionality or to fix problems in the current release. To begin with we will start with a standard system and add these extra components as required.

Initially, to follow along with the code in these posts, you will require 2 things:

1. Visual Studio 2008 or Visual Web Developer Express
2. The ASP.NET AJAX Control Toolkit





Creating the initial project
From the file menu, select "New Web Site" and then choose "AJAX Control Toolkit WebSite" from the list of available options:







Adding the Web Part Components
Now we need to add a few components to the page to give us something to work with.
From the toolbox, when in design or split mode, drag the following items onto the default.aspx page:
From the WebParts toolbox tab:


  • 1 x Web Part Manager
  • 2 x Web Part Zones

Then, from the Standard toolbox tab, drag a Calendar component and drop it into the first Web Part Zone - this will automatically convert the Calendar into a generic Web Part.

After the addition of these items, the default.aspx page should look as shown below (it also includes a ToolkitScriptManager which is there as a consequence of the initial project choice we made. At present this isn't being used, but will be required later.)


Before we can actually run this project, and get the drag and drop behaviour that we’re after, we need to make a small addition to the code behind.


Display Modes and Personalization
If you were to run the project in its current state, you would see one of two things - either you would get a database error, or you would see the Calendar component, but would be unable to change its position.

The reason why drag and drop is not yet possible is due to the display mode setting of the Web Part Manager. Display modes are used to define what operations can be performed on the Web Parts; the default display mode is "Browse" and this is the mode currently used by our page. In this mode it's only possible to do basic operations, such as minimize and close; it's not possible to perform drag and drop. To enable drag and drop requires, at a minimum, the display mode to be changed to "Display".

However, things aren't quite so simple. When web parts are moved on the page it's necessary to save the information about their new positions so that they can be restored to these locations the next time the page is rendered. This information is stored into a personalization table in a database. Thus, to enable the more advanced features of Web Parts, such as drag and drop, requires a database to be available. If you haven't yet got a database the easiest option is to download SQL Server Express.

To set the Web Part Manager’s display mode, add the following code into the Default.aspx.cs file:



protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// set the display mode to "Design" to allow drag and drop
WebPartDisplayMode mode = WebPartManager1.SupportedDisplayModes["Design"];
if (mode != null)
{
WebPartManager1.DisplayMode = mode;
}
}
}


If this is the first time that the page is being rendered (i.e. not a postback), then this code checks the Web Part Manager to see if the "Design" mode is contained in its list of supported display modes. If it is, then it sets this to be the current display mode.


We now have everything in place to enable drag and drop. Press F5 to run the project and hopefully you should see the following output:

If you have run this using Internet Explorer, drag and drop functionality should now be enabled:
- when the cursor is hovered over the title bar it should change to the directional cursor and clicking and holding on the Calendar web part's title bar should enable it to be selected and dragged to the second Web Part Zone.

However, with the current release of ASP.NET 3.5, if you have run this in a browser other than IE (e.g. Firefox), then the chances are that the drag and drop won't be working - to fix this we need to make another modification.


Web Part Drag and Drop in Firefox
For some reason Microsoft have chosen not to include the fix for Firefox (and other non-IE) browsers in the latest releases of the ASP.NET framework. To get things working in all browsers requires the download of the
Microsoft ASP.NET Futures (July 2007) Release - obviously this is a technology preview release and is therefore not supported for production sites - however, the alternative is to not have drag and drop support for all non-Microsoft browsers, so you need to choose which of these is the most important to you.

Once this futures release has been downloaded, its components need to be added to your Visual Studio toolbox. To do this, you need to do the following steps:

  1. In the toolbox window, move the cursor into the bottom tab pane and right click to bring up the context menu. From this choose "Add Tab" and create a new tab for the futures release.

  2. From within this new tab pane, select "Choose Items.." from the right-click context menu.

  3. In the dialog that appears choose browse and locate the futures DLL (mine was downloaded to C:\Program Files\Microsoft ASP.NET\ASP.NET Futures July 2007\v1.3.61025\3.5).Click on OK once all the components of this DLL have been selected. All these components should then be added to the new tab of the toolbox, as shown below.



As you can see, the toolbox now contains both a WebPartManager and WebPartZone that have been added from the Futures release. All we need to do now are replace the standard versions of these that we'd added already with these new Futures versions and that should fix our Web Parts drag and drop for all browsers.



AJAX Enabling The Web Parts
We've only one thing left to do, and that's remove the annoying postbacks that occur when the Web Parts are moved. To do this we simply need to wrap everything in an UpdatePanel from the AJAX Extensions tab of the toolbox. We already have a ScriptManager present from the AJAX Control Toolbox - however, for consistency, I've chosen to remove this and replace it with the standard version. Once everything is in place, the body of my default.aspx file now looks as follows:







Click here to see this in action.


This concludes the introduction to Web Parts. In future posts I'll expand apon this simple project to show how Web Parts can be combined with both the ASP.NET AJAX framework and the ASP.NET AJAX Toolkit Tab component.


Thursday, 5 June 2008

ASP.NET AJAX and Web Parts

Posts In This Series:

Introduction - ASP.NET AJAX and Web Parts
Ajax Web Parts Part 1 - Drag and Drop
Ajax Web Parts Part 2 - Web Part Connections
Ajax Web Parts Part 3 - Dynamic Web Parts
Ajax Web Parts Part 4 - Dynamic Web Part Connections


Download the source - Part 1
Download the source - Part 2
Download the source - Part 3
Download the source - Part 4



Introduction
In my quest to create a database capable of storing anything and everything (see earlier posts), my attention over the last few months has turned from the back end to the front end UI.

One obvious way to display a set of disparate information is to use a Web Portal style framework - a set of widgets (small window components) within a tab framework - the tabs can be used to represent the general categories and each widget can be used to display a sub-set of information for that category. Since I’m coming from an ASP.NET background, Web Parts sounded like a perfect fit for the implementation of these widgets, and the Tab Control, from the ASP.NET AJAX Toolkit, sounded like the ideal way to wrap all these Web Parts together.

In theory, the creation of this Web Portal sounded like it would be a breeze - just drop a few Web Part Zones onto the Tab Control, and populate them with the Web Parts to show information from each category. In reality, as usual, things turned out to be not quite so simple. Over the next few posts I’m going to describe the creation of a simple version of this Web Portal and highlight the problems, and workarounds, involved with each stage.

To start I’ll be describing the very basics of getting Web Parts up and running, before moving onto some more complex issues, such as dynamically generating the Web Parts and creating new tab pages on demand.
The content of these posts won’t really provide any information that can’t be found elsewhere, however I hope that by bringing it all together, into a single place, that this will be of benefit to some - certainly it would have helped me. As mentioned, most of the stuff concerning the dynamic creation of Web Parts can be found in other locations and, when I can remember where I obtained information from, I’ll try and reference these other sources. One things that these posts won’t be are in-depth overviews of either Web Parts or ASP.NET AJAX - a basic knowledge of these is assumed - if you’d like more information on either of these topics, I can recommend the books shown in the reading list.

Tuesday, 3 July 2007

Using SemWeb with MySQL

Getting SemWeb to work with MySQL is pretty much the same as for SQLite (see the last post). Again, using the news.rdf file from Mozilla, the command line to enter data into the MySQL database now becomes:

rdfstorage news.rdf --out "mysql:rdf:database=news;username=test"

This assumes that a new database (schema) called "news" has been created in MySQL and that a user "test" exists that doesn't require a password (both these things can be done using the MySQL Administrator UI).

Initially running this command line in the installed version of the SemWeb\bin directory results in the following error being generated:

System.IO.FileNotFoundException: Could not load file or assembly 'MySql.Data, Version=1.0.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' or one of its dependencies. The system cannot find the file specified.


This error means that the MySQL.Data.dll is missing, so the first step is to get this from MySQL ADO.Net Data Provider 5.0.7

After placing this DLL in the bin directory and running the command line again, the following error will appear:

System.IO.FileLoadException: Could not load file or assembly 'MySql.Data, Version=1.0.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)


In this case the important part is the "manifest definition does not match the assembly reference" bit - as happened with the SQLite DLL, this MySQL DLL is newer than the version that was used to build the SemWeb.MySQLStore.dll and so the 2 DLLs are incompatible. We need to rebuild this SemWeb DLL.


The steps to do this are as follows:

  • Open the SemWeb solution in Visual Studio
  • Add a new project of type "Class Library" and called "SemWeb.MySQLStore"
  • Delete the default "Class1.cs" that gets added to the project
  • Choose to add an existing item to the project and pick "MySQLStore.cs" from the SemWeb\src directory
  • Add a reference to the "MySQL.Data.dll " that should already be in the SemWeb\bin directory
  • Add a reference to the SemWeb project
  • In the project properties, set the output path to the SemWeb\bin directory

These are the exact same steps that were required for the SQLiteStore DLL (although obviously referencing different files). However, building the MySQLStore DLL now results in the following compiler error:

The type or namespace name 'MySqlConnection' could not be found (are you missing a using directive or an assembly reference?)

To fix this error the following needs to be added to the top of the MySQLStore.cs file:

using MySql.Data.MySqlClient;


So the complete set of using directives at the top of the file should now appear as:


using System;
using System.Collections;
using MySql.Data.MySqlClient;
using System.Data;

The project should now rebuild successfully and the new SemWeb.MySQLStore.dll should now appear in the SemWeb\bin directory.

Unfortunately this still isn't the end of the process - running the command line again results in the following error:

MySql.Data.MySqlClient.MySqlException: Table 'news.rdf_statements' doesn't exist

The DLL is now ok, its just that the database that its creating has a few problems; inspecting the database in MySQL Administrator shows that the "rdf_literals" and "rdf_entities" tables have been created but the "rdf_statements" table hasn't been made.

Setting the SEMWEB_DEBUG_SQL environment variable (type "set SEMWEB_DEBUG_SQL=1" at the command prompt) and then running the command line again generates some debug information (alternatively put a break point on the "
CreateTable" function in the SQLStore.cs file and run the program in the debugger, after first setting up the command line arguments in the project properties). The error generated is:

System.FormatException: Input string was not in a correct format.

This is caused by the SemWeb database "Open" function (from MySQLStore.cs) querying the version of the database and then trying to set this into the .NET Version class; however, the version string returned from my version of MySQL is "5.0.41-community-nt" and this doesn't match with the expected .NET version string format, which is expecting only integers seperated by a period character ('.') - hence an error is thrown on the first call to "Open" and so the creation of the first database table ("rdf_statements") fails.

To fix this I've just put a try-catch around the setting of the version string, so basically I just ignore when the version can't be set.




private void Open()
{
if (connection != null)
return;
MySqlConnection c = new MySqlConnection(connectionString);
c.Open();
connection = c; // only set field if open was successful

using (IDataReader reader = RunReader(@"show variables like 'version'"))
{
reader.Read();
try
{
version = new Version(reader.GetString(1));
}
catch(Exception e)
{
if (Debug) Console.Error.WriteLine(e.Message);
}
}
}


Finally, rebuilding the SemWeb DLL and re-running the command line successfully adds the RDF to the database:

news.rdf 0m0s, 81 statements, 1728 st/sec
Total Time: 0m2s, 81 statements, 30 st/sec

Monday, 2 July 2007

Using SemWeb with SQLite

As mentioned in the previous post I've had a few problems getting SemWeb, the C# RDF library, to persist data to a database. Here I describe the steps I've had to follow to get things working.

I've been using Visual Studio on Windows - I suspect that these problems may not exist when using Mono on Linux.

I'm using the following versions:


SQLite

Following the approach described in the SemWeb documentation, I first tried to set up a database connection to a SQLite database.

Following the SemWeb documentation I performed the following steps:

  • Placed the "sqlite3.dll" (from the SQLite download) into my windows System32 directory
  • Added the "Mono.Data.SqliteClient.dll" from the the Mono install directory "Mono-1.2.4\lib\mono\2.0" into my SemWeb\bin directory
  • Downloaded the sample RDF file from http://www.mozilla.org/news.rdf
  • Entered the specified command line at a DOS prompt in the SemWeb\bin directory:
    rdfstorage.exe news.rdf --out "sqlite:rdf:Uri=file:news.sqlite;version=3"
  • Pressed return and stood well back.

I was greeted with the following:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileLoadException: The located assembly's manifest definition with the name 'Mono.Data.SqliteClient' does not match the assembly reference.

Basically my Mono SQLite adapter was newer than the version that the SemWeb.SqliteStore.dll had been built with.

Unfortunately the SemWeb Visual Studio solution doesn't come with a SemWeb.SqliteStore project, so the following steps are required:

  • Open the SemWeb solution in Visual Studio
  • Add a new project of type "Class Library" and called "SemWeb.SqliteStore"
  • Delete the default "Class1.cs" that gets added to the project
  • Choose to add an existing item to the project and pick "SQLiteStore.cs" from the SemWeb\src directory
  • Add a reference to the "Mono.Data.SqliteClient.dll" that should already be in the SemWeb\bin directory
  • Add a reference to the SemWeb project
  • In the project properties, set the output path to the SemWeb\bin directory

I also rebuilt the SemWeb and RDFStorage projects (after setting their output directories to the bin directory). Once built I re-ran the command line and this time obtained the expected result:


news.rdf 0m0s, 81 statements, 1036 st/sec
Total Time: 0m1s, 81 statements, 42 st/sec



Next time I'll describe the steps I've had to follow to get SemWeb up and running with MySQL.