.Net interface for RQL

102 views
Skip to first unread message

RustyLogic

unread,
Jun 18, 2008, 5:24:57 AM6/18/08
to RedDot CMS Users
Hi,

Use at your own risk etc.
I have written and used this library extensively. It is written
in .Net 2, Studio 2008.
It only covers functionality that I required but could easily be
extended.
You will need to alter the WebServices addresses to point to your own
CMS server.


<url>http://groups.google.co.uk/group/RedDot-CMS-Users/web/
RustyLogic.zip?hl=en</url>

Regards,
John

RustyLogic

unread,
Jun 18, 2008, 5:25:58 AM6/18/08
to RedDot CMS Users

theHam

unread,
Jun 18, 2008, 5:44:38 AM6/18/08
to RedDot CMS Users
All i can say is thanks! I've been working on a similar project in
vb.net in my downtime at work for a couple of months (i dont' get much
downtime :P). You've just saved me a whole heap of effort.

But just to cover myself off what sort of licence are you releasing
this under?

Thank again.

On Jun 18, 7:25 pm, RustyLogic <j...@rustylogic.com> wrote:
> http://groups.google.co.uk/group/RedDot-CMS-Users/web/RustyLogic.zip?...

markus giesen

unread,
Jun 18, 2008, 5:58:21 AM6/18/08
to RedDot CMS Users
Thanks john! It's just great that you decided to publish your stuff!
I hope others will follow!

RustyLogic

unread,
Jun 18, 2008, 6:26:55 AM6/18/08
to RedDot CMS Users
License... As long as no-one pretends they wrote it themselves (keep
the RustyLogic namespace), do what you like with it.
I may post updates here which you can then slot in without messing
about.
Other than that do what the hell you like with it!

Regards,
John
> >http://groups.google.co.uk/group/RedDot-CMS-Users/web/RustyLogic.zip?...- Hide quoted text -
>
> - Show quoted text -

RustyLogic

unread,
Jun 18, 2008, 6:33:47 AM6/18/08
to RedDot CMS Users
An example usage to get you started:

This exports all projects and keeps the last 3 days, add it to a
schedule and you're all done:
I Havn't included the Helper classes but you can just put your own
code in.

using System;
using System.Collections.Generic;
using System.Text;
using Sbc.Helper;
using System.IO;
using System.Configuration;
using RustyLogic.RedDotNet;

namespace RustyLogic.RedDotDailyExport
{
class Program
{
static void Main(string[] args)
{
ConfigHelper.Encrypt(false);
string username =
ConfigurationManager.AppSettings["username"];
string password =
ConfigurationManager.AppSettings["password"];
string exportPath =
ConfigurationManager.AppSettings["exportPath"];
string emailTo =
ConfigurationManager.AppSettings["emailTo"];
string emailFrom =
ConfigurationManager.AppSettings["emailFrom"];
string serverName =
ConfigurationManager.AppSettings["serverName"];
EmailHelper emailHelper = new EmailHelper("localhost");
Session.Login(username, password);
try
{
User exportUser = null;
foreach (User user in User.List())
{
if (user.Name == username)
{
exportUser = user;
break;
}
}

Server server = null;
foreach (Server cmsServer in Server.List())
{
if (cmsServer.Name == serverName)
{
server = cmsServer;
}
}
List<Project> projects = Project.List();
DirectoryInfo exportDir = new
DirectoryInfo(exportPath);
foreach (Project project in projects)
{
project.Select();
try
{
// Clear out some publishing logs or the
export may fail.
project.DeletePublishingLogs(3);
project.Export(exportDir, true, true, true,
true, server, server, true, exportUser, project.Name + " export job
completed", project.Name + " export job completed on " + server.Name +
" as " + exportUser.Name);
}
catch (Exception ex)
{
emailHelper.Send(emailFrom, emailTo, "Export
Failed", ex.Message + ex.StackTrace + ex.Data);
}
}

PurgeDirectory(exportPath, new TimeSpan(48, 0, 0));
}
catch (Exception ex)
{
emailHelper.Send(emailFrom, emailTo, "Export Failed",
ex.Message + ex.StackTrace + ex.Data);
}
finally
{
Session.Logout();
}
}
public static void PurgeDirectory(string rootDirectory,
TimeSpan maximumAge)
{
DirectoryInfo root = new DirectoryInfo(rootDirectory);
DirectoryInfo[] directories = root.GetDirectories();
foreach (DirectoryInfo dir in directories)
{
TimeSpan directoryAge =
DateTime.Now.Subtract(dir.CreationTime);
if (directoryAge.CompareTo(maximumAge) > 0)
{
dir.Delete(true);
> > >http://groups.google.co.uk/group/RedDot-CMS-Users/web/RustyLogic.zip?...Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -

El Pollo Loco

unread,
Jun 20, 2008, 11:06:41 AM6/20/08
to RedDot CMS Users
This is probably the biggest contribution to this Google Group
ever......

One thing I do not see in this library, and to where many people do
not do this, is extracting the <IODATA> node and its attributes out of
RQL calls....

This is so you can just pass in the necessary RQL, and with the
<IODATA> node already having been constructed.

So for example, you would overload your Execute method, and that it
could take just the session key (which is all you need for most of
project related RQLs), or just the Login Guid (which is all you need
for most Server Mgr RQLs), or both (for RQLs like publishing a page).


public static void Execute(RQLService.RqlService rql_ws, string
client_xml, string session_key)
{
string rql = "<IODATA sessionkey=\"" + session_key + "\">" +
client_xml + "</IODATA>";
rql_ws.Execute(rql);
}

public static void Execute(RQLService.RqlService rql_ws, string
client_xml, string session_key, string login_guid)
{
string rql = "<IODATA loginguid=\"" + login_guid + "\"
sessionkey=\"" + session_key + "\">" + client_xml + </IODATA>";
rql_ws.Execute(rql);
}

public static void Execute(string client_xml, string login_guid,
RQLService.RqlService rql_ws)
{
string rql = "<IODATA loginguid=\"" + login_guid + "\">" +
client_xml + "</IODATA>";
rql_ws.Execute(rql);
> > > >http://groups.google.co.uk/group/RedDot-CMS-Users/web/RustyLogic.zip?...quoted text -

RustyLogic

unread,
Jun 20, 2008, 2:00:15 PM6/20/08
to RedDot CMS Users
Oddly enough it goes one step further to extracting those, you don't
have to pass them to the Session class because it already knows them.
A flag is passed to request them to be added before execution.

Calls to Session.Execute use the following:

Session.Execute(string rql) - inserts nothing (for bespoke building of
RQLs)
Session.Execute(string rql, Info.LoginGuid) - inserts loginguid before
execution
Session.Execute(string rql, Info.SessionKey) - inserts loginguid &
sessionkey before execution

So for example, to release a page, you call Page.Release() which in
turn builds the rql and calls
Session.Execute(rqlXml, Session.Info.SessionKey);

I did it that way because sometimes (can't remember when off the top
of my head!) you might want to add other parameters to IODATA before
sending the command through to Session.

Err.. did that make sense? LOL

Thanks for all the positive feedback!
> > > > >http://groups.google.co.uk/group/RedDot-CMS-Users/web/RustyLogic.zip?...text -

mitch

unread,
Jun 21, 2008, 3:17:31 PM6/21/08
to RedDot CMS Users
Thanks for this contribution! I am a .NET developer that has recently
been working with RQL and RedDot. I am quite amazed their isn't a
company provided .NET API over RQL. I ended up having to write my own
as well.

One thought from my experiences was using the built in XML
serialization saved me tons of time? I do admit it makes your classes
a little more noisy with attribute decorations, but the trade off is
you don't have to worry about writing the serialization plumbing to
and from XML.
E.g.

[Serializable]
[XmlRoot("PAGE")]
public class Page
{
private string _guid;

[XmlAttribute("guid")]
public string Guid
{
get { return _guid; }
set { _guid = value; }
}

....

In the PageService you can do something quick like this then:

XmlDocument document = new XmlDocument();
document.LoadXml(_service.ExecuteString(rqlCommand));
XmlNode node = document.SelectSingleNode("//PAGE");
if (node == null)
{
return null;
}

ISerializer<Page> serializer = new
TextSerializer<Page>();

using(XmlNodeReader reader = new XmlNodeReader(node))
{
return serializer.DeSerialize(reader);
}

...

The TextSerializer class is really basic and just provides a strongly
typed facade for the XMLSerializer built in .NET type:

public class TextSerializer<T> : ISerializer<T>
{
public void Serialize(T expected, TextWriter writer)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
serializer.Serialize(writer, expected);
}

public T DeSerialize(TextReader reader)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(reader);
}


public T DeSerialize(XmlNodeReader reader)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(reader);
> > > > > >http://groups.google.co.uk/group/RedDot-CMS-Users/web/RustyLogic.zip?...-

Richard Hauer (5 Limes)

unread,
Jun 21, 2008, 9:20:32 PM6/21/08
to RedDot CMS Users
Just to add my 2c worth - I have written a couple of .Net wrappers for
RQL now - the first one utilised XML serialization. I had attempted to
reverse engineer a complere object library from the RQL calls. The
problem I found with that was that the object model that falls out of
the RQL calls seems to be kind of ugly. For example:

To list all pages you could do:

<IODATA loginguid="[!guid_login!]" sessionkey="[!
key!]"><AUTHORIZATION><PAGES action="list"/></AUTHORIZATION></IODATA>
or
<IODATA loginguid="[!guid_login!]" sessionkey="[!
key!]"><PROJECT><PAGES action="list"/></PROJECT></IODATA>

While these calls do not have exactly the same purpose they are a
usefdul illustration. The "Pages" collection is a property of both a
"Project" and an "Authorization".
I found that the construction of objects required to support making
and receiving RQL calls was not at all natural and made the API
counter-intuitive and difficult to use.

The second library I wrote worked much better fo me and my team. We
created an RQLHelper static class which constructed RQL and processed
the results (trapping context on the way like language, project,
logon, session, etc) and the provided static access methods to the
various functions. The static class can handle logging on and off
when necessary, you can send a batch of commands, and so on.

The third time round I used the same approach but refined many of the
similar calls into overloads and added the ability to switch between
the COM model and the webservice model automatically depending on the
code's proximity to the server (i.e. on the same machine or not). I
have experimented with the DCOM model but have found that webservices
are just as good with far fewer configuration issues.

So, if you are inclined to embark on this path I reccommend a
functional approach to the API rather than an object-model mapping
approach.

But that's just me.

HTH.

Regards,
Richard Hauer
====================
5 Limes Pty Limited
www.5Limes.com.au
> ...
>
> read more »- Hide quoted text -

mitch

unread,
Jun 23, 2008, 12:08:55 AM6/23/08
to RedDot CMS Users
Nice work! Sounds like you have lots of experience working with if you
are on your third wrapper.

If I understand your implementation correctly, some of it sounds
similar to what I ended up doing as well for our RQL like API. I ended
up wrapping RQL calls into a service layer similar to how your static
class acts like a data gateway. I didnt make them static however for
unit testing and mocking reasons though.

I really like the context idea as well, the method calls are becoming
really noisy. I am thinking of making the API work similar to how
nHibernate uses SessionScope.

I ended up doing something really similar with the RQL end point
service calls. I created a plugin model where different
implementations could be used. This needed to be setup this way for
unit testing anyways, but it ended up that there were 3
implementations that could be created. The COM version, the .NET Web
Service version and the .NET Remoting version. I only have created the
latter 2 thus far. The remoting version could be another option for
you if you wanted to implement something a little faster than Web
Services remotely. (Of course you may run into firewall issues, as
from what I could tell the RQL service only listens on a TCP channel).

The objects returned are anemic data transfer objects so the real
value of the OO approach comes in the seperation of concerns, and
single responsibility. Mind you I am relatively new to RQL, as with
anything my approach should change and evolve the deeper I get into
the technology.

Cheers,

Mitch R.

On Jun 21, 7:20 pm, "Richard Hauer (5 Limes)"
Reply all
Reply to author
Forward
0 new messages