Memory-Leaks in ADO.NET mit NumberOfReclaimedConnections protokollieren

Eine Bibliothek von mir macht irgendwie Connections falsch zu.

Selbst mit ANTS Memory Profiler bin ich nicht so richtig weiter gekommen, um zu sehen, ob meine Annahme mit den nicht geschlossenen Connections überhaupt zutrifft.

Dann bin ich auf den Leistungsindikator (englisch „Performance Counters“) gestossen, der mir hilft: NumberOfReclaimedConnections. MSDN schreibt:

The number of connections that have been reclaimed through garbage collection where Close or Dispose was not called by the application. Not explicitly closing or disposing connections hurts performance.

In Deutsch:

Anzahl der Verbindungen, die durch die Garbage Collection (automatische Speicherbereinigung) wieder verfügbar gemacht wurden, bei denen die Anwendung weder Close noch Dispose aufgerufen hat. Nicht mehr benötigte Verbindungen, die weiterbestehen, weil sie nicht explizit geschlossen oder gelöscht wurden, beeinträchtigen die Arbeitsgeschwindigkeit.

Den wollte ich also analysieren. Ich bin gescheitert, dies via Leitungsüberwachung-MMC-Tool zu machen und fand auch keine konkreten Code-Beispiele um in der Anwendung selbst den Counter auszulesen.

Also habe ich selbst Code geschrieben, der auf meinem deutschen Windows auch funktioniert:

private static void logPerfCounter()
{
    var ina = new PerformanceCounterCategory(
        @".NET-Datenanbieter für SqlServer").GetInstanceNames();

    var pc = new PerformanceCounter
    {
        CategoryName = @".NET-Datenanbieter für SqlServer",
        CounterName = @"NumberOfReclaimedConnections",
        InstanceName =
            ina.FirstOrDefault(
                n =>
                    n.ToLowerInvariant()
                        .StartsWith(Assembly.GetEntryAssembly()
                            .GetName().Name.ToLowerInvariant()))
    };

    var nv = pc.NextValue();
    Console.Write(@" {0} ", nv);
}

Damit konnte ich dann verifizieren, dass über die Zeit hinweg der Counter stets gewachsen ist und nie gesunken.

In einer anderen Vergleichs-App war der Wert stets 0, dort habe ich die Connections also korrekt geschlossen bzw. via Dispose-Aufrufe (oder implizit via using) freigegeben.

Bubble Mouse Move events from child controls up the hierarchy in Windows Forms

Windows Forms (or „WinForms“ for short) does not know the concept of event bubbling (also called „event propagation“ sometimes). To solve this in terms of command routing, I’ve written some small classes earlier.

To bubble up events from child controls to parent controls (or the form itself), the idea is to hook into the child control creation and hook up for those specific events and manually forward them.

Based on this idea and with the help of a forum answer on MSDN, I’ve written a small class that you can attach to a control and get all child control MouseMove events. The class looks like:

public sealed class MouseEventBubbler
{
    private readonly Control _attachTo;

    public MouseEventBubbler(Control attachTo)
    {
        _attachTo = attachTo;

        _attachTo.MouseMove += _attachTo_MouseMove;

        _attachTo.ControlAdded += _attachTo_ControlAdded;
        _attachTo.ControlRemoved += _attachTo_ControlRemoved;

        foreach (Control control in _attachTo.Controls)
        {
            AttachToControl(control);
        }
    }

    public void _attachTo_MouseMove(object sender, MouseEventArgs e)
    {
        OnMouseMove(e);
    }

    public event MouseEventHandler MouseMove;

    private void _attachTo_ControlAdded(object sender, ControlEventArgs e)
    {
        AttachToControl(e.Control);
    }

    private void _attachTo_ControlRemoved(object sender, ControlEventArgs e)
    {
        DetachFromControl(e.Control);
    }

    private void AttachToControl(Control c)
    {
        c.MouseMove += Child_MouseMove;
        c.ControlAdded += Child_ControlAdded;
        c.ControlRemoved += Child_ControlRemoved;
        AttachToChildren(c);
    }

    private void AttachToChildren(Control parent)
    {
        foreach (Control child in parent.Controls)
        {
            AttachToControl(child);
        }
    }

    private void DetachFromControl(Control c)
    {
        DetachFromChildren(c);
        c.MouseMove -= Child_MouseMove;
        c.ControlAdded -= Child_ControlAdded;
        c.ControlRemoved -= Child_ControlRemoved;
    }

    private void DetachFromChildren(Control parent)
    {
        foreach (Control child in parent.Controls)
        {
            DetachFromControl(child);
        }
    }

    private void Child_ControlAdded(object sender, ControlEventArgs e)
    {
        AttachToControl(e.Control);
    }

    private void Child_ControlRemoved(object sender, ControlEventArgs e)
    {
        DetachFromControl(e.Control);
    }

    private void Child_MouseMove(object sender, MouseEventArgs e)
    {
        var pt = e.Location;
        var child = (Control)sender;
        do
        {
            pt.Offset(child.Left, child.Top);
            child = child.Parent;
        }
        while (child != _attachTo);

        var newArgs = new MouseEventArgs(e.Button, e.Clicks, pt.X, pt.Y, e.Delta);
        OnMouseMove(newArgs);
    }

    private void OnMouseMove(MouseEventArgs newArgs)
    {
        var h = MouseMove;
        if (h != null)
        {
            h(this, newArgs);
        }
    }
}

I’ve also saved it as a PasteBin.

The class can be adjusted to match other events than the MouseMove event, if required.

CryptographicException bei Verwendung von Oracle.ManagedDataAccess lösen

Gestern hatte ein Kollege beim Aufsetzen einer Website ASP.NET MVC 4 auf einem IIS unter Windows Server 2008 R2 eine Fehlermeldung:

[CryptographicException: Unbekannter Fehler -1073741766.]
   System.Security.Cryptography.ProtectedData.Protect(Byte[] userData, Byte[] optionalEntropy, DataProtectionScope scope) +504
   Oracle.ManagedDataAccess.Client.ConnectionString.Secure() +493
   OracleInternal.ConnectionPool.PoolManager`3.Initialize(ConnectionString cs) +1760
   OracleInternal.ConnectionPool.OraclePoolManager.Initialize(ConnectionString cs) +21
   OracleInternal.ConnectionPool.OracleConnectionDispenser`3.GetPM(ConnectionString cs, PM conPM, ConnectionString pmCS, Byte[] securedPassword, Byte[] securedProxyPassword, Boolean& bAuthenticated, Boolean& newPM) +296
   OracleInternal.ConnectionPool.OracleConnectionDispenser`3.Get(ConnectionString cs, PM conPM, ConnectionString pmCS, Byte[] securedPassword, Byte[] securedProxyPassword) +1576
   Oracle.ManagedDataAccess.Client.OracleConnection.Open() +3756
   OracleInternal.EntityFramework.EFOracleProviderServices.GetDbProviderManifestToken(DbConnection connection) +274
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +91

[ProviderIncompatibleException: Der Anbieter hat keine ProviderManifestToken-Zeichenfolge zurückgegeben.]
   System.Data.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection) +10947809
   System.Data.Entity.ModelConfiguration.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection) +48

[ProviderIncompatibleException: An error occurred while getting provider information from the database. This can be caused by Entity Framework using an incorrect connection string. Check the inner exceptions for details and ensure that the connection string is correct.]
   System.Data.Entity.ModelConfiguration.Utilities.DbProviderServicesExtensions.GetProviderManifestTokenChecked(DbProviderServices providerServices, DbConnection connection) +242
   System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) +82
   System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) +88
   System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input) +248
   System.Data.Entity.Internal.LazyInternalContext.InitializeContext() +524
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +26
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +71
   System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator() +21
   System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +446
   System.Linq.Enumerable.ToList(IEnumerable`1 source) +80

Zunächst war es eine Herausforderung, statt den „normalen“ Oracle.DataAccess-Klassen die Oracle.ManagedDataAccess-Klassen zum Laufen zu bringen. Hier haben uns zwei Artikel geholfen:

Wir haben dann zum Lösen des eigentlichen Fehlers lange rumgesucht, viel ausprobiert und schließlich beim Weblog-Artikel „SOLVED: Windows Identity Foundation – “The system cannot find the file specified”“ fündig geworden.

Die Lösung bestand dann schlicht darin, im Anwendungspool (App Pool) für die Anwendung die Option „Benutzerprofil laden“ auf „True“ zu stellen:

IIS App Pool - Benutzerprofil laden

Danach lief alles wie gewünscht.

Shopware-4-REST-API von .NET 4 aus ansprechen

Zurzeit arbeite ich an einem Projekt bei dem aus Microsoft Navision („Dynamics Nav“ oder wie das jetzt heißt) heraus Daten nach Shopware geschrieben werden sollen.

Dazu scheint mit die REST-API von Shopware gut geeignet zu sein. Aus diesem Grund habe ich ein Beispielprojekt geschrieben. Das ganze ist eine .NET-4-Konsolenanwendung mit einer einzigen Datei.

Den Quelltext findet Ihr nachfolgend (alternativ auch bei Pastebin):

namespace ShopwareRestApiTest01
{
    using System;
    using System.Globalization;
    using System.Net;
    using Newtonsoft.Json;
    using RestSharp;

    internal class Program
    {
        static void Main()
        {
            const string user = "demo";
            const string pass = "NtMd3OIouT2sr0aJcllBIx1fH3SgxmRr0T6r7D4P";

            // http://restsharp.org/
            var client =
                new RestClient(@"http://192.168.147.169/api")
                    {
                        Authenticator = new DigestAuthenticator(user, pass)
                    };

            var request = new RestRequest("articles/{id}", Method.GET);
            request.AddUrlSegment("id", 3.ToString(CultureInfo.InvariantCulture)); // replaces matching token in request.Resource

            // easily add HTTP Headers
            request.AddHeader("Content-Type", "application/json; charset=utf-8");

            // or automatically deserialize result
            // return content type is sniffed but can be explicitly set via RestClient.AddHandler();
            var response = client.Execute(request);

            if (response.ErrorException != null)
            {
                Console.WriteLine(@"################ ERROR ################");
                Console.WriteLine(response.ErrorException.Message);
            }
            else
            {
                var content = response.Content; // raw content as string

                dynamic json = JsonConvert.DeserializeObject(content);
                Console.WriteLine(json);
            }
        }
    }

    public class DigestAuthenticator : 
        IAuthenticator
    {
        private readonly string _user;
        private readonly string _pass;

        public DigestAuthenticator(string user, string pass)
        {
            _user = user;
            _pass = pass;
        }

        public void Authenticate(IRestClient client, IRestRequest request)
        {
            request.Credentials = new NetworkCredential(_user, _pass);
        }
    }
}

In dem Projekt verwende ich auch zum ersten Mal NuGet, dem wirkliche eleganten Paket-Manager für Visual Studio. Damit lade ich Json.NET und RestSharp als Referenz in das Projekt.

Subclassing the FileOpen dialog in .NET

If you are looking for a way to subclass a standard file open dialog from .NET, take a look at the Vista Bridge Sample Library from Microsoft.

„Subclassing“ (or „Extending“, „Customizing“) refers to adding new controls to the bottom of the standard Windows dialog like following, to extend it:

Although the examples are for WPF, I guess it is rather simple to migrate them to WinForms (.NET 2.0).

Solving „Exception of type ‚System.ComponentModel.Design.ExceptionCollection‘ was thrown.“ error messages in Visual Studio .NET 2010 Windows Forms Designer

Recently I got an error message

---------------------------
Microsoft Visual Studio
---------------------------
Exception of type 'System.ComponentModel.Design.ExceptionCollection' was thrown.
---------------------------
OK
---------------------------

when trying to edit a form in the Windows Forms Designer of Visual Studio .NET 2010. Searching Google for this error brought up some results but didn’t help me.

There was one hint that stated:

Sometimes I get the message „Exception of type ‚System.ComponentModel.Design.ExceptionCollection‘ was thrown“ When trying to open a Form in designer view.

The real problem of the „ExceptionCollection“ being thrown is that when there is a WSOD (White Screen of Darn) indicating a designer load issue, the designer gets unloaded. These get caught by the unload method and get displayed in the dialog box you see.

So, to fix this you should:

  • Attach a visual studio debugger to VS. Turn on exception catching when first thrown (in the Debug|Exceptions menu).
  • Open the designer with the debugger attached
  • Determine what component is throwing the exception.

This was actually a copy from a Microsoft Connect bug report. I tried this, but the error message still popped up and the debugger never stopped at this message (although it stopped at other native errors).

Steps to solve

Since all this didn’t help, I did another approach that was finally successfully:

  1. Make a SVN commit for the file.
  2. Open the „*.designer.cs“ file of the form that shows the error in source view.
  3. Remove larger blocks of form element declarations.
  4. Fix all compilation errors with ReSharper (i.e. ensure that nothing is red anymore on the side-indicator).
  5. Save the file. No need to compile.
  6. Open the Windows Forms Designer of the form.
  7. If the error still shows up, do a SVN revert to go back to the initial state.
  8. Repeat steps 2 to 7 until the error does not show up anymore.
  9. Now you’ve encircled the erroneous child control that causes the error.
  10. Repeat steps 2 to 7 with a smaller amount of controls you remove, until you have only one control left.

In my case it was a user control inside a group control inside a tab control, so I first identified the tab control, then the group control and then the user control.

You could isolate the user control inside a new form to further investigate. In my case it was rather easy; I put checks for design mode around most of the functions inside my control to ensure the code only gets executed if the control is not in design mode.

This fixed my error.

See also:

Handling WM_MOVING in Windows Forms

Just a quick snippet:

public class FormWithWmMoving :
    Form
{
    private const int WM_MOVING = 0x0216;

    private static readonly object EVENT_MOVING = new object();

    public event EventHandler Moving
    {
        add { Events.AddHandler(EVENT_MOVING, value); }
        remove { Events.RemoveHandler(EVENT_MOVING, value); }
    }

    public class MovingEventArgs : EventArgs
    {
        private readonly Rectangle _rectangle;

        public MovingEventArgs(
            Rectangle rectangle)
        {
            _rectangle = rectangle;
        }

        public Rectangle Rectangle
        {
            get { return _rectangle; }
        }
    }

    protected virtual void OnMoving(MovingEventArgs e)
    {
        var h = (EventHandler)Events[EVENT_MOVING];
        if (h != null)
        {
            h(this, e);
        }
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOVING)
        {
            var r = (Win32NativeMethods.RECT)Marshal.PtrToStructure(m.LParam, typeof(Win32NativeMethods.RECT));
            var rectangle = new Rectangle(r.left, r.top, r.Bounds.Width, r.Bounds.Height);

            var args = new MovingEventArgs(rectangle);
            OnMoving(args);
        }

        base.WndProc(ref m);
    }
}

Hope this is helpful someday to me or others.

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.

Den Microsoft Scripting Host in C# verwenden

Nachfolgend ein paar Anmerkungen zum den Erlebnissen und Erkenntnissen die ich beim Einbinden des Microsoft Scripting Host in eine C#-Windows Forms-Anwendung hatte.

Ressourcen

Zunächst sind folgende Ressourcen hilfreich:

  • Das Dr. Dobb’s Journal hat einige Artikel dazu veröffentlicht. Fragmente dazu stehen noch im Netz und sind bei Google zu finden.
  • Das Weblog von Eric Lippert enthält gute Infos zum Scripting Host im Allgemeinen.
  • Die Usenet-/Google-Group „microsoft.public.scripting.hosting“ enthält ebenfalls gute Infos.
  • Die eigentliche Schnittstellen-Definition ist z.B. im Platform-SDK-Ordner „c:\Programme\Microsoft SDK\Include\ActivSP.idl“ (so heißt er bei mir) zu finden.

Fehlermeldung „Klasse unterstützt keine Automatisierung“

Diese Fehlermeldung habe ich erhalten, als ich eigene C#-Klassen via IActiveScript.AddNamedItem hinzufügen wollte und diese Klassen nicht public waren oder nicht das ComVisible( true )-Attribut gesetzt hatten.

Als einfache Lösung also einfach schauen, dass die Klassen (inklusive aller Basisklassen) ComVisible( true ) und public sind.

Fehlermeldung „FatalExecutionEngineError“

FatalExecutionEngineError was detected
Message: Die Laufzeit hat einen schwerwiegenden Fehler entdeckt. Fehleradresse: „0x7a0b2d09“ in Thread „0x29c“. Fehlercode: 0xc0000005. Bei diesem Fehler könnte es sich um ein Problem in der CLR oder in den unsicheren oder nicht verifizierbaren Teilen des Benutzercodes handeln. Übliche Ursachen dieses Bugs sind Marshallerfehler für COM-Interop oder PInvoke, die den Stapel beschädigen können.

Diese Fehlermeldung habe ich erhalten, weil ich einen falschen Parameter für die Funktion IActiveScript.AddNamedItem übergeben hatte.

Und zwar habe ich das Flag „SCRIPTITEM_ISSOURCE“ angegeben. Als ich das Flag weggelassen habe, lief alles korrekt.

Dieses Flag gibt laut MSDN-Dokumentation an, dass das hinzugefügte Objekt als Senke für Skript-Ereignisse agieren soll. Scheinbar geht das nicht oder zumindest nicht so wie ich es gedacht habe.

Macht aber nix, brauche ich in meinem Fall nicht. Deshalb habe ich einfach das Flag weggelassen und gut war’s.

Generische Typen in COM verwenden

Klassen die direkt von generischen Basisklassen ableiten sind nicht in COM (also in Skripten im Windows Scripting Host) sichtbar. Es kommen dann seltsame Fehler wie „Method not found“ beim Aufruf von Methoden solcher Klassen.

Deshalb Klassen die von COM aus ansprechbar sein sollen immer von nicht-generischen Basisklassen ableiten.

Was bei mir funktioniert hat ist, wenn solche Klassen generische Schnittstellen implementieren (z.B. IComparable<T>). Die Klasse selbst ist also nicht generisch, nur eine implementierte Schnittstelle. Solch eine Klasse konnte ich erfolgreich von COM aus ansprechen.

Hier einige weiterführende Hinweise zu dem Thema:

Schnittstellendefinition

Weil ich lange gesucht habe, hier der Download der Schnittstellendefinitionen für folgende Schnittstellen und Enumerationen:

  • IActiveScript
  • IActiveScriptParse
  • IActiveScriptSite
  • IActiveScriptError
  • SCRIPTSTATE
  • SCRIPTTHREADSTATE
  • SCRIPTITEMFLAGS
  • SCRIPTINFOFLAGS