Resolving DevExpress ASPX HtmlEditor error

Recently I got the following error when using the DevExpress.com HTML editor control for ASP.NET.

Message: Invalid argument.
Line: 1147
Char: 3
Code: 0
URI:
http://www.zeta-producer.com/modules1-admin/DXR.axd?r=1_103

This error only occurred only in Internet Explorer and only in our production environment, not with Firefox or Google Chrome, not in the test environment.

After some searching, I found out:

  • The issue occurs somewhat near the „_aspxCreateStyleSheet“ function.
  • A poster in the DevExpress forum experiences a similar issue when using too much style sheets.

Since I am using the ASP.NET „App_Themes“ folder with a lot of style sheets, I thought that this may be my issue, too.

Resolution

By placing the following keys in the „appSettings“ section of the „web.config“ file on our production servers, I resolved the issue.

<add key=“DXEnableCallbackCompression“ value=“true“/>
<add key=“
DXEnableResourceCompression“ value=“true“/>
<add key=“DXEnableResourceMerging“ value=“true“/>
<add key=“DXEnableHtmlCompression“ value=“true“/>

I assume that the „DXEnableResourceCompression“ key probably merges multiple CSS files into one CSS, thus resolving the issue.

Please note that these „appSettings“ keys requires you to have a newer version of the DevExpress.com libraries (9.2 if I recall correctly).

Hund entlaufen, was tun?

Gestern hatten wir, meine Tierärztin Jana und ich, ein leider unschönes Erlebnis:

Janas Hunde Jonas und Jasper (zwei sog. „Whippets„) sind beim Spazierengehen abgehauen.

Um anderen, die irgendwann mal in einer ähnlichen Situation sind, ggf. einen Tipp zu geben, fasse ich nachfolgend die Erlebnisse zusammen.

(Spoiler: Es gibt ein Happy-End!)

Freitag, 20. November 2009, 16 Uhr

Jana ist mit den Hunden spazieren bei Altbach/Deizisau.

Kurz vor Ende waren die Hunde alleine auf dem Feld unterwegs, und hatten wohl plötzlich einen Hasen-Geruch in der Nase (obwohl kein Hase da war).

Wie der Blitz waren sie auf und davon, zuerst über die Wiese und dann im Wald verschwunden.

Jana hat zwei Stunden lang erfolglos gesucht und nichts gefunden. Wir haben die Suche dann zunächst abgebrochen, da es auch dunkel wurde und wir noch einen Termin hatten.

Freitag, 20. November 2009, 22:30 Uhr

Zurück vom Krimi-Dinner waren wir dann gemeinsam nochmals 2 Stunden im Wald und sind alles erfolglos abgelaufen.

Hier wiederum ein Abbruch der Suche um ca. 00:00 Uhr.

Samstag, 21. November 2009, 06:30 Uhr

Ich bin alleine erneut in den Wald und 2 Stunden lang abseits der Wege durchs Gestrüpp gezogen, ständig die Hunde gerufen, leider ebenfalls erfolglos.

Erneuter Abbruch der Suche.

Samstag, 21 November 2009, 08:30 Uhr

Zusammen mit Jana sind wir noch ein paar Wege abgelaufen, ebenfalls erfolglos.

Unterwegs habe ich (mit dem iPhone, logisch) recherchiert was das Internet bei entlaufenem Hund so empfiehlt.

Grob gesagt waren folgende Punkte für uns wichtig:

  • Polizei informieren (falls jemand Hunde findet/sieht).
  • Forstamt informieren (warum genau weiß ich ned).

Das haben wir dann so gemacht.

Beim Polizeirevier Esslingen habe ich eine nette Frau erreicht, die alles aufgenommen hat und weitergegeben hat (hoffentlich).

Beim Forstamt ging keiner ran.

Samstag, 21 November 2009, 09:00 Uhr

Janas Kollegin, die Elke, kam nach einem Anruf bei ihr freundlicherweise auch vorbei zum Suchen helfen. Elke (bzw. ihre Hündin) ist bei der Rettungshundestaffel und hat auch ihre Hündin dabei gehabt.

Wir haben nochmals die wahrscheinlichsten Stellen durchkämmt, in unmittelbarer Umgebung vom ursprünglichen Startplatz im Wald, abseits der Wege.

Aufgeteilt in 3 Gruppen (à eine Person) sind wir losgezogen.

Samstag, 21 November 2009, 09:30 Uhr

Anruf von Jana bei mir, dass Elke den Hund Jonas gefunden hat. Er kam aus einem dichten Tannenwald-Abschnitt.

Ich eile zurück zu den anderen. Auf dem Rückweg hat Jana dann noch den Jasper gefunden, er hatte sich mit dem Halsband/Flexi-Leine im Gestrüpp verfangen gehabt.

Samstag, 21 November 2009, 10:00 Uhr

Alle Hunde sind wieder vollzählig, beide quasi unverletzt.

44248628

Wir zogen dann vollständig, mit 3 Personen und 4 Hunden, zurück zum Parkplatz.

Resümee

  • Ich bin bei meiner Suche ewig weit über Felder und durch den Wald gelaufen; was mich verwundert hat war, dass sich die Hunde dann doch relativ nahe, vielleicht 600 Meter vom Auto entfernt, aufgehalten haben.
  • Meiner Meinung nach hat es geholfen, dass wir mit zwei anderen Hunden zum Suchen waren; ggf. haben die entlaufenen Hunde auch durch die Anwesenheit von Artgenossen die Deckung aufgegeben.
  • Durchhalten und positiv denken hilft die Situation effektiv zu meistern. Heulen und jammern kann ich auch wenn wir die Hunde gefunden haben (tot oder lebendig), hilft aber beim Suchen selbst nicht weiter.

Epilog

Ein spannendes Erlebnis, mit nassen Socken und Schuhen, ging zum Glück positiv zu Ende.

Welche Konsequenzen die Hundehalterin aus der Aktion zieht weiß ich noch nicht, ich hoffe gute!

Krimi-Dinner

Gestern war ich mit meiner Freundin Jana beim Krimi-Dinner in Esslingen.

Ein „Krimi-Dinner“ (auch Krimispiel genannt) ist eine Veranstaltung bei der ca 50-80 Leute in einem Speisesaal sitzen und nebenbei wird von ein paar Schauspielern ein Theaterstück aufgeführt, direkt um die Tische herum.

44091989

In unserem Fall war das Stück:

Mord au Chocolat
Ein Zartbitter DinnerKrimi mit edlem 3-Gang-Menü

Schokoladenfabrikant Fritz von Reevenstein liegt im Sterben. Noch vor dem Ableben des Patriarchen entbrennt bei den übrigen Familienmitgliedern ein erbitterter Nachfolgestreit. Die Situation eskaliert, als ein hinterhältiger Mord geschieht. Und urplötzlich sind alle Anwesenden in eine Mordermittlung verwickelt…

Es ging insgesamt mit Essen ca. 2-3 Stunden lang.

Die Schauspieler spielten immer eine Weile, das Publikum wurde auch mit einbezogen (einige zuvor ausgewählte Personen spielten ab und an in ihrer zugeteilten Rolle mit). Zwischendurch wurde auch gesungen, das war witzig.

Essen gab’s für mich als Vegetarier natürlich auch was Leckeres!

Mein Fazit

Positiv war:

  • Es war eine originelle Veranstaltung.
  • Das Essen war lecker.
  • Die Schauspieler warten teilweise originell.
  • Es hat Spaß gemacht.

Negativ war:

  • (Zu) teuer: 79 Euro pro Person, Getränke extra (25 Euro bei uns für 2 Personen).
  • Mein Vegetarisches Essen wurde trotz Vorabsprache zunächst vergessen.
  • Die Kommunikation mit unseren anderen Tischnachbarn war sehr gering.

Als Resümee ist meine Meinung, dass es schön war, aber für ein weitere solche Veranstaltung reicht meine Motivation nicht aus, dazu hätte es noch brillanter sein müssen.

Den service-bw-SOAP-Webdienst von PHP aus aufrufen

Vor Kurzem waren wir in der glücklichen Lage, dass wir auf das Portal von service-bw.de programmatisch via SOAP/WSDL zugreifen durften.

In .NET war das dank dem automatischen Proxy-Generierungs-Werkzeug von Visual Studio.NET 2008 sehr einfach.

In PHP war es etwas trickreicher. Danke viel Ausprobieren und vor allem dank diesem Posting konnten wir es lösen.

Um ein Bisschen was „ins Internet“ zurückzugeben, stelle ich nachfolgend zwei kurze Beispiele vor.

Beispiel 1, Aufruf der SOAP-Funktion getLebenslageTree()

Folgendes Beispiel ruft eine Funktion des Lebenslagen-Webdienst auf. Es wird gezeigt wie mehrere Parameter die auch komplexe Typen enthalten, korrekt übergeben werden.

$client = new SoapClient(
    'https://www.service-bw.de/zfinder-core-ws/lebenslage?wsdl');

$profilData = new stdClass();
$profilData->ags = "0";
$profilData->plz = "0";
$profilData->sprache = "deu";
$profilData->kategorienUndVerknuepfung = false;

$pkey = new stdClass();
$pkey->id = 93256;
$pkey->mandantenId = 0;
$pkey->sprachId = "deu";

$param = new stdClass();
$param->lebenslageKey = $pkey;
$param->kategorieIds = array(783160, 783161);
$param->mandantenIds = array(0);
$param->operatorAnd = false;
$param->profilData = $profilData;

$result = $client->getLebenslageTree($param);

Der folgende Download enthält den vollständigen Quelltext des Beispiels:

Download Beispiel 1

Beispiel 2, Aufruf der SOAP-Funktion getStichwoerterAndSynonymeByNamePrefix()

In diesem Beispiel wird eine Funktion des Stichwort-Webdienst aufgerufen. Es werden erneut komplexe Parameter, inklusive Felder („Arrays“) an die Funktion übergeben.

$client = new SoapClient(
    'https://www.service-bw.de/zfinder-core-ws/stichwort?wsdl');

$searchParameters = new stdClass();
$searchParameters->alphaBlockModus = false;
$searchParameters->hitRestriction = false;
$searchParameters->numberOfHits = 100;
$searchParameters->regionIds = array(0);
$searchParameters->mandantenIds = array(0);
$searchParameters->sprachId = "deu";
$searchParameters->value = "A";

$profilData = new stdClass();
$profilData->ags = "0";
$profilData->plz = "0";
$profilData->sprache = "deu";
$profilData->kategorienUndVerknuepfung = false;

$param = new stdClass();
$param->searchParameters = $searchParameters;
$param->profilData = $profilData;

$result = $client->getStichwoerterAndSynonymeByNamePrefix($param);

Der folgende Download enthält wiederum den vollständigen Quelltext des Beispiels:

Download Beispiel 2

Ich wünsche allen Entwicklern viel Erfolg und freue mich, falls ich ein Bisschen weiterhelfen kann! Rückmeldung wie immer willkommen 🙂

Vergangenheit, Gegenwart und Zukunft

Heute habe ich festgestellt, dass ich alt, wahlweise „erwachsen“ bin:

Der aktuelle FDP-Gesundheitsminister ist im selben Jahr wie ich geboren, 1973. Jetzt bin ich also schon im Alter für Ministerposten, WTF?!

Außerdem bin ich jetzt älter, als mein Papa es jemals war:

todesanzeige-guenther-keim-1978

Das fühlt sich irgendwie seltsam an. Aber so ist’s halt.

Ich habe einen schönen Beruf, eine tolle Freundin, eine klasse Mama, eine liebe Hündin. Das ist ja schon ne ganze Menge Tolles 🙂

(Die Mama möge mir die Veröffentlichung der Anzeige verzeihen, aber war ja eh ein öffentliches Dokument)

In diesem Sinne: Fröhlich weiter zu den (mindestens) nächsten 36 Jahren!

Ordner und Dateien mit abschließendem Leerzeichen löschen

Via ROBOCOPY hatte ich versehentlich einen Ordner mit Leerzeichen am Ende erstellt („D:\MyFolder „). Über den Windows Explorer konnte ich diesen dann nicht mehr löschen, weil ein Leerzeichen am Ende des Namens eigentlich unzulässig ist.

Im Microsoft-Knowledge-Base-Artikel „Entfernen von Dateien mit reservierten Namen in Windows“ steht beschrieben wie es doch geht.

In meinem Fall war folgender Befehl hilfreich:

rmdir „\\?\d:\MyFolder „

Ggf. ist diese Information ja mal für Euch nützlich.

XCOPY/ROBOCOPY like class in C#

During the process of moving some command scripts to a more robust solution that involved C# Script, I was in the need to replace an XCOPY call with an equivalent in C#.

What I wanted to avoid is to simply start a CMD.EXE process and call the XCOPY command.

Instead I looked for a class/function in .NET/C# that can serve as a replacement. Although I found some solutions, none of them worked the way I wanted them.

Bring your own code

So I decided to develop my own small solutions that is no rocket science code but fulfills my requirements.

It has fewer features as XCOPY and is intended for copying folders (the original XCOPY works for both files and folders). In addition it is being designed to be used in a console environment (i.e. the operations are synchronously and blocking).

An example call looks like:

var options =
    new ZetaFolderXCopyOptions
        {
            FilesPattern = "*.*",
            RecurseFolders = true,
            CopyEmptyFolders = true,
            CopyHiddenAndSystemFiles = true,
            OverwriteExistingFiles = true,
            CopyOnlyIfSourceIsNewer = false,
            FoldersPattern = "*"
        }
        .AddExcludeSubStrings(
            "\\.svn\\",
            "\\_svn\\",
            "\\_Temporary\\" );

var xc = new ZetaFolderXCopy();
xc.Copy(
    sourceFolderPath,
    destinationFolderPath,
    options );

The full code consists of a single .CS file and can be downloaded from here for free.

Hopefully this code is of some basic usage to you, keep the feedback coming!

Update 2015-11-25

I’ve uploaded a greatly enhanced version which adds wildcard and Regex exclude support  as well as retry options.

This is another step towards a native C#/.net version of robocopy.

Creating an XtraReports report that works both with Microsoft SQL Server and VistaDB

Currently I am extending and enhancing the reporting system for our test management tool Zeta Test.

In this article I will describe the issues I discovered (and solved) when trying to design one single report that works with both Microsoft SQL Server and VistaDB.

Creating a report

I decided to go with XtraReports from DevExpress as the reporting system.

The basic design steps creating and deploying a report with XtraReports is similar to methods when working with e.g. Microsoft SQL Server Reporting Services:

  1. Create a new report in the designer of XtraReports.
  2. Specify connection string/settings (using the SqlClient namespace classes).
  3. Specify tables/SQL queries to use as the data source for the report.
  4. Design your report graphically.
  5. Save the report to a .REPX file.
  6. Pack the .REPX file into the deployment setup.
  7. Ship the setup to the customers.

Displaying a report

In Zeta Test I had to perform the following steps when displaying a report:

  1. Load the report.
  2. Replace the design-time connection string by the connection string to the currently used database of the currently loaded project in Zeta Test.
  3. Display the report in a print-preview form.

Two databases

Since a project in Zeta Test can either use Microsoft SQL Server or VistaDB as the back-end database, I wanted to design a single report so that it can be used with both back-end databases.

Inially I planned to simply design the reports with an OleDB connection to the SQL Server database and then later when displaying the report for a VistaDB database, simply switch the connection string to the VistaDB database.

Unfortunately there is no OleDB provider for VistaDB. Therefore this solution did not work. Another idea was to simply leave the SqlClient classes that were used when designing the report as they are, only changing the connection string. This did not work, either.

So I did come up with another solution that works quite well as of writing this article:

Rewriting the .REPX report

A .REPX report file is a C# source code file that gets compiled when loading the report with the XtraReport.LoadLayout method.

I decided to give the following „algorithm“ a try:

  1. Load a .REPX file that was designed with the SqlClient classes as a string into memory.
  2. Do some string replacements to replace all SqlClient classes by their VistaDB counterparts.
  3. Call XtraReport.LoadLayout on the replaced string.
  4. Display the report in a print-preview form.

Luckily, after some try and error I actually was able to get this working!

In the following chapter I outline some of the methods I created in order to hopefully give other developers some ideas to use in their own applications:

Code to rewrite a .REPX report

The following method is the main method that is being called in order to load and display a report. It is a member of the print-preview form:

public void Initialize(
    FileInfo reportFilePath,
    Pair<string, string>[] parameters)
{
    var report = new XtraReport();

    if (Host.Current.CurrentProject.Settings.IsVistaDBDatabase)
    {
        var rawContent = UnicodeString.ReadTextFile(reportFilePath);

        var replacedContent = replaceSqlClientForVistaDB(rawContent);

        using (var ms = new MemoryStream(
            Encoding.Default.GetBytes(replacedContent)))
        {
            report.LoadLayout(ms);
        }
    }
    else
    {
        // Assumes that the report was designed with SQL Server.
        // If not, one would have to replace the other way, i.e.
        // from VistaDB to SQL Server.
        // I am leaving this out until really needed.
        report.LoadLayout(reportFilePath.FullName);
    }

    // --
    // Change connection string.

    var da = report.DataAdapter as DbDataAdapter;

    if (da != null)
    {
        adjustConnectionString(da.SelectCommand);
        adjustConnectionString(da.InsertCommand);
        adjustConnectionString(da.DeleteCommand);
        adjustConnectionString(da.UpdateCommand);
    }

    // --
    // Adjust parameters.

    if (parameters != null && parameters.Length > 0)
    {
        foreach (var parameter in parameters)
        {
            if (containsParameter(report.Parameters, parameter.First))
            {
                report.Parameters[parameter.First].Value = parameter.Second;
            }
        }
    }

    // --
    // Bind the report's printing system to the print control.

    printControl.PrintingSystem = report.PrintingSystem;

    // Generate the report's print document.
    report.CreateDocument();
}

The actual method to replace the string is the following:

private static string replaceSqlClientForVistaDB(string content)
{
    if (string.IsNullOrEmpty(content))
    {
        return content;
    }
    else
    {
        var result = content;

        // Add reference.
        result =
            result.Replace(
                Environment.NewLine + @"///   </References>",
                string.Format(
                    Environment.NewLine + @"///     <Reference Path=""{0}"" />" +
                    Environment.NewLine + @"///   </References>",
                    typeof (VistaDB.IVistaDBValue).Assembly.Location
                    ));

        // Change class and namespace names.
        result =
            result.Replace(
                @"System.Data.SqlClient.Sql",
                @"VistaDB.Provider.VistaDB");

        // Comment out non-available VistaDB properties.
        result = Regex.Replace(
            result,
            @"(^.*?FireInfoMessageEventOnUserErrors.*?$)",
            @"//$1",
            RegexOptions.Multiline);

        return result;
    }
}

And the method to replace the connection string is defined as follows:

private static void adjustConnectionString(DbCommand command)
{
    if (command != null)
    {
        var conn = command.Connection;

        if (conn != null)
        {
            if (conn.State == ConnectionState.Open)
            {
                conn.Close();
            }

            conn.ConnectionString = getConnectionString();
        }
    }
}

Other methods are left out for simplicity. If you want to see them, simply drop me a note, e.g. by e-mail.

Epilog

In this short article I’ve shown you a way to modify an XtraReports report during runtime of your application to work with both a Microsoft SQL Server and a VistaDB database without the need to design separate reports.

As of writing this article the reports I tested work quite well, probably/possible I will have to do further adjustments when getting to more complex reports. I will update the article then.

I am looking forward for lot of feedback! 🙂

Zeta Test 1.0 ist da!

Hurra! Nach 1½ Jahren Entwicklungszeit ist Version 1.0 unserer Test-Management-Umgebung „Zeta Test“ nun verfügbar.

Das, zugegebenermaßen erklärungsbedürftige, Produkt ist hervorragend geeignet um Testpläne und Testfälle für Software-Tests zu erstellen.

Kurzer Auszug aus der Website zum Produkt:

Zeta Test ist eine integrierte Test-Management-Umgebung, mit der Sie Black-Box-Tests, White-Box-Tests, Regressionstests und Change-Management-Tests (Release-Wechsel) von Software durchführen können.

Zeta Test unterstützt Sie dabei bei der Planung, Durchführung, Monitoring, Protokollierung und Dokumentation der Tests sowie beim Auswerten der Ergebnisse.

Schreiben und verwalten Sie mit Zeta Test Ihre Testfälle, Testpläne und Vorlagen. Testen Sie Ihre Software nach Testdrehbüchern, die Sie mit Zeta Test erstellt haben.

Ich bin gespannt wie ein Flitzebogen, wie die Software einschlägt! Alle Beta-Tester waren hellauf begeistert, jetzt heißt es den Vertrieb ordentlich anlaufen zu lassen.

Hier die direkten Download-Hyperlinks (für Microsoft Windows):

Handbücher gibt’s auch:

Weil wir nett sind (und uns viel Verbreitung versprechen), ist die Software für Privatanwender, Institutionen wie Schulen und Universitäten, sowie für den Einsatz im Open-Source-Kontext komplett kostenlos erhältlich.

Freue mich über viel Feedback Eurerseits zum Programm!

(Vom Webdesign und -Layout haben wir uns übrigens von den Freunden bei TeamViewer und Mozilla inspirieren lassen. Dank geht auch an Brian von „Lost in Deutschland“ für die hervorragenden Übersetzungen ins Englische!)