Laden...

Forenbeiträge von S.R. Ingesamt 221 Beiträge

15.09.2008 - 12:20 Uhr

Hallo,

ich stehe gerade vor einem kleine Problem und ralle einfach nicht, wieso das ein Problem ist und nicht klappt 🙂

Ich habe eine Test-Datenstruktur wie folgt angelegt:

    public struct TestItem
    {
        public int TestID;
    }

Von dieser Struktur benötige ich eine Liste. Diese fülle ich dann mit Daten. Soweit klappt das. Dann möchte ich ein Eintrag in der Liste nehmen und dort die TestID ändern. Der Code sieht wie folgt aus:

            TestItem neu = new TestItem();
            neu.TestID = 3;
            test.Add(neu);

            test[0].TestID = 4;

Allerdings erhalte ich dann die Meldung: Der Rückgabewert "System.Collections.Generic.List<WindowsFormsApplication1.TestItem>.this[int]" kann nicht geändert werden, da er keine Variable ist.

=> Dies ist die letzte Zeile in meinem Code - die Zuweisung der 4. Allerdings ralle ich nicht, wieso das nicht klappt. Ich wähle doch eine Zeile in der Liste aus, wähle davon dann die Variable TestID und der weise ich was zu. Dann habe ich doch eine Variable, oder was sehe ich daran falsch?

Vielen Dank für eure Mühen

Stefan

18.08.2008 - 13:18 Uhr

Hallo,

so eine Antwort hatte ich befürchtet aber auf etwas positiveres gehofft. Dann werde ich mal ein bisschen die Tasten schwingen lassen und die wichtigsten Pattern umsetzen. Wie weit ich das dann treibe, werde ich dann sehen 🙂

Vielen Dank für's Feedback

Stefan

18.08.2008 - 07:41 Uhr

Hallo,

bisher hatte ich immer einen String und wenn ich prüfen wollte, ob dieser ein bestimmtes Format hat, habe ich dies immer per RegEx (http://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck) gemacht. Dies hat auch immer einwandfrei funktioniert.

Jetzt habe ich aber genau das umgekehrte Problem und weiß nicht weiter. Ich habe also einen beliebigen Regulären Ausdruck. Nun möchte ich per Zufall einen String erzeugen, der genau diese Bedingung erfüllt.

Hat jemand dort eine Idee, wie ich dies hinbekomme?

Vielen Dank für eure Hilfe

Stefan

01.08.2008 - 00:10 Uhr

Hallo,

das ganze funktioniert reibungslos, wenn man folgenden Code verwendet:

this.WebBrowser.Document.Body.InnerText = "";
WebBrowser.Document.Write(ClientUtils.CmsUtils.Forum_GetPostText(this.postID));

Dann gibt es bei mir keine Probleme. Hoffe, das hilft mal jemandem.

Stefan

31.07.2008 - 20:11 Uhr

Hallo,

habe ein Problem in einem Delphi-Programm (hier beschrieben: http://www.delphiforum.de/topic_Unterscheiden+zwischen+Vista+und+W2K8_85390.html). Allerdings ist das kein Delphi-Spezifisches und daher würde mich auch interessieren, wie dies in C# zu lösen ist. Hier der Text aus dem Beitrag:

Mein Programm muss beim Start wissen, auf welchem Betreibssystem es läuft. Dafür habe ich bisher folgende drei Werte ausgelesen:

Label1.Caption := IntToStr(Win32Platform);  
Label2.Caption := IntToStr(Win32MajorVersion);  
Label3.Caption := Win32CSDVersion; 

Damit konnte ich bisher alle Versionen unterscheiden. Jetzt habe ich allerdings das Problem mit Windows Vista (SP1) und Windows Server 2008 (SP1). Für beide Versionen kommen hier die gleichen Werte raus:
2
6
Service Pack1

Stellt sich für mich jetzt die Frage: Wie unterscheide ich zwischen den beiden Betriebssystemen.

Vielen Dank für eure Hilfe

Stefan

31.07.2008 - 18:18 Uhr

Hallo,

vielen Dank. Das scheint prinzipiell zu klappen, allerdings gibt es dann folgende Probleme:

  1. die Pfeil-Tasten werden nicht berücksichtigt

  2. wenn ich zu einem späteren Zeitpunkt den Text noch ein Mal mit Document.Write("xx") ändere, dann ergeben sich zwei Probleme
    2.1) Es erscheint eine Meldung "Das Dokument wurde geändert. Möchten Sie die Änderungen speichern? "ja, nein, abbrechen".
    2.2) Nach Klick auf nein wird der neue Inhalt geladen. Danach reagiert das KeyPress (und auch KeyDown) nicht mehr.

zu 1)
habe ich schon gelöst, in dem ich auf KeyDown reagiere und nicht auf KeyPress.

zu 2)
habe ich keine Ahnung, was ich dort machen soll 🙂

Vielen Dank für eure Unterstützung

Stefan

31.07.2008 - 16:56 Uhr

Hi,

vielen Dank für deinen Rat. Allerdings ist bei mir Body immer null, auch nachdem ich über

WebBrowser.DocumentTest = "<html><head></head><body>Stefan</body></html>"

einen Body lade. Muss dafür eventuell noch etwas anders gemacht werden?

Dankend

Stefan

31.07.2008 - 16:41 Uhr

Hallo,

in meiner kleinen .net 2.0 Test-Anwendung habe ich ein WebBrowser liegen. Dort habe ich den Design-Modus aktiviert und kann jetzt Veränderungen vornehmen. Das klappt soweit.

Jetzt möchte ich aber bestimmte Events abfangen, z.B. onKeyPress, um dann z.B. ausgeben zu können, ob an dieser Stelle der Text fett gedruckt ist. Leider klappt dies aber nicht mit dem Event abfangen. Hab folgenden Code aus einem Beispiel aus dem Netz:

private IHTMLDocument2 doc = null;this.doc = (IHTMLDocument2)this.WebBrowser.Document.DomDocument;
this.doc.designMode = "On";

HTMLDocument doc2 = (HTMLDocument)this.WebBrowser.Document.DomDocument;
HTMLDocumentEvents2_Event htmlEvent;
htmlEvent = (mshtml.HTMLDocumentEvents2_Event)doc2;
htmlEvent.onkeypress += new HTMLDocumentEvents2_onkeypressEventHandler(htmlEvent_onkeypress);

...

private bool htmlEvent_onkeypress(IHTMLEventObj e)
{
  label1.Text = "hallo"; // (*)
  return true;
}

An die Stelle (*) habe ich einen Break-Point gesetzt und dahin komme ich nie, wenn ich n' Taste drücke. Ebenso kann ich auch keine Aktionen mehr im WebBrowser durchführen. Der tut so, als würde nix passieren.

Hat jemand einen Tipp, wie ich hier vorgehen kann.

Dankend

Stefan

31.07.2008 - 12:33 Uhr

Hallo,

vielen Dank für deinen Beitrag. Der hat mich noch Mal dazu bewogen alles genau durchzugehen und siehe da... durch irgendeine Genialität habe ich es geschafft, die Option "AllowNavigation" in den Eigenschaften auf "false" zu setzen. Damit ist dann klar, wieso nichts neues angezeigt wird.

Vielen Dank - läuft jetzt alles prima

Stefan

31.07.2008 - 10:51 Uhr

Hallo,

ist man hier zu einer Lösung gekommen? Hänge nämlich auch vor dem Problem und wäre an einer Lösung sehr interessiert.

Dankend

Stefan

31.07.2008 - 10:42 Uhr

Hallo,

eigentlich möchte ich was ganz simples machen:

  • beim Öffnen eine Programms sollt in einen WebBrowser eine html-Seite geladen werden
  • beim Klick auf einen Button soll eine andere html-Seite geladen werden

Der Quellcode der html-Seite liegt mit als string vor (stringVar1, stringVar2). Beim Laden mache ich nun folgendes:

WebBrowser.DocumentText = stringVar1

Dies klappt auch ohne Probleme. Dann mache ich das gleiche bei OnButtonClick mit stringVar2, aber der Text wird nicht angezeigt. Nach einer Suche in Google wurde gesagt, dass ein Bug in der Componente besteht, wenn man pro Funktion mehrfach den DocumentText setzt, aber dies mache ich ja nicht.

Hat jemand n' Ahnung, was ich hier falsch mache?

Dankend

Stefan

19.07.2008 - 11:30 Uhr

Hallo,

hab jetzt noch folgende Möglichkeit gefunden:

 [DllImport("GDI32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
int test = GetDeviceCaps(this.Handle, 90);

Lieder ist test immer gleich 0, auch wenn ich statt 90 110 einsetze. Will alles net so, wie es soll 🙂

Vielen Dank für eure Tipps

Stefan

19.07.2008 - 10:58 Uhr

Hallo,

ich möchte gern erfahren, welchen DPI-Wert der Benutzer meiner Software eingestellt hat. Normalerweise ist dieser ja 96, kann aber auch schon mal 120 oder noch größer sein.

Habe in google gesucht und bin immer wieder auf ähnliches gestoßen:

this.m_caps = Manager.GetDeviceCaps( 0, DeviceType.Hardware );

Leider finde ich aber nicht, was dieser Manager ist. Bin ich damit überhaupt auf dem richtigen Wege oder geht das viel einfacher, den DPI-Wert zu ermitteln?

Vielen Dank

Stefan

17.07.2008 - 22:06 Uhr

Hi,

deine Erklärung ist absolut richtig. Um aber genau das zu verhindern, bin ich ja von der Einheit dpi auf pixel gegangen. Und die sollte ja unabhängig von der dpi Anzahl sein - so wie ich das verstehe.

Daher wunder das mich gerade alles etwas 🙂

Stefan

17.07.2008 - 21:31 Uhr

Hallo,

vielen Dank für den Tipp. Habe unter Font den Wert Unit auf Pixel gesetzt. Demzufolge müsste ja auf jedem Rechner das Ergebnis gleich sein.

Auf der 120dpi-Version wird die Schrift allerdings trotzdem noch etwas größer dargestellt also auf der 96dpi-Version. Somit passt das leider immer noch nicht so, wie's eigentlich soll.

Hat jemand noch n' Tipp, wie ich das Problem in den Griff kriege?

Vielen Dank

Stefan

17.07.2008 - 19:11 Uhr

Hallo,

ich habe eine Applikation, die ziemlich pixelgenau gebaut ist - aus diversen Gründ. Jetzt habe ich einen Anwender, der die DPI Zahl nicht 96 (wie bei mir) sondern 120 hat. Dies hat natürlich zur Folge, dass das Design komplett zerschossen wird.

Daraufhin habe ich alle Forms auf "AutoScaleMode=inheritet" gesetzt. Soweit so gut. Jetzt sind die Forms wenigstens schon mal wieder in der richtigen Größe und auch die Controls werden an der richtigen Stelle positioniert.

ABER:
die Schriten (Label, CheckBox, usw.) werden alle noch zu groß gezeichnet. Das möchte/muss ich auch noch unterbinden. Ich weiß, dass das geht, denn unter Delphi war dies mit "Scale=false" auch möglich.

Hab leider nichts gefunden, was mir weiter hilft. Vielen Dank für eure Hilfen.

Stefan

14.07.2008 - 19:50 Uhr

verwendetes Datenbanksystem: Access 97

Hallo,

ein Kunde von uns verwendet für sein VB6 Programm eine lokale Access 97 Datenbank. Jetzt steht die Überlegung im Raum, dass wir mit unserem Tool (C# mit .NET 2.0) ein paar Werte aus der Datenbank lesen - damit der Endkunde gewisse Daten nicht doppelt eingeben muss.

Besteht da Grundsätzlich die Möglichkeit? Im schlimmsten Fall müssten wir halt erst die Daten mit dem VB6-Programm in ein XML-File exportieren und dieses dann importieren - diesen Umweg versuchen wir allerdings zu umgehen.

Habe im Netz leider nichts gefunden - Access 97 ist einfach zu alt 🙂

Vielen Dank

Stefan

14.07.2008 - 08:21 Uhr

Hallo,

bei der TextBox kannst du doch einfach die Methode OnTextChanged abgreifen und darein dann deine Speicherfunktion schreiben - fertig.

Hab grad kein VisualStudio am Start, aber bei ListBox müsste die Funktion OnSelectionChanged (oder so ähnlich) heißen. Auch diese abfangen, darin speichern - fertig.

Ich hoffe das hilft.

Stefan

13.07.2008 - 09:40 Uhr

Hallo,

und erst Mal einen herzlichen Dank für deinen Tipp. Damit habe ich mir im Web einen Überblick schaffen können, was mich zu erwarten hat - ist ja schon mal viel wert 🙂

Allerdings kriege ich es aufs Verrecken nicht hin, die Klasse zu erstellen:

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] 
    public class WsmsTabControlDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        //public override GetHitText()
        //{

        //}
    }

Fehlermeldung von VisualStudio:
The type or namespace name 'ControlDesigner' does not exist in the namespace 'System.Windows.Forms.Design' (are you missing an assembly reference?)

So steht's doch eigentlich auch bei MSDN:
http://msdn.microsoft.com/en-us/library/0fd17t9s.aspx

Bin total verdutzt, wieso das nicht klappt... Hat jemand n' Tipp, was ich falsch machen. Vielen Dank

Stefan

12.07.2008 - 14:08 Uhr

Hallo,

ich habe ein UserControl erstellt und darauf einen Button gelegt. Wenn ich zur Laufzeit dort drauf klicke, dann wird eine Aktion durchgeführt. Im "Design-Modus" in VisualStudio allerdings wirkt sich der Klick nicht auch - es wird auch kein MouseOver oder ähnliches angezeigt.

Was ich sozusagen möchte: Ein Verhalten wie beim TabControl. Hier kann man ja auch während der Design-Zeit auf die Reiter klicken und dann wird eine neue Seite aufgerufen.

Vielen Dank für eure Hilfe

Stefan

09.07.2008 - 12:04 Uhr

Hi,

@JAck30lena:
leider nützt das nix - auch wenn ich Serializable noch weiter nach vorne setze - immer das gleiche Problem.

JunkyXL:

[DesignerSerializationVisibility.Content]
        public List<MyTabPage> TabPages
        {
            get
            {
                return this.tabPages;
            }
            set
            {
                this.tabPages = value;
            }
        }

das meinst du doch, oder? Dann kriege ich von VB aber beim Kompilieren gesagt, dass "The type name 'Content' does not exist in the type 'System.ComponentModel.DesignerSerializationVisibility'"

Vielen Dank für eure Hilfe

Stefan

09.07.2008 - 11:49 Uhr

Hi,

habe den Code jetzt wie folgt abgeändert:

using...
using System.ComponentModel.Design;

namespace WindowsApplication1
{
    [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
    public partial class MyControl : UserControl
    {
        private List<MyTabPage> tabPages = new List<MyTabPage>();

        public List<MyTabPage> TabPages
        {
            get
            {
                return this.tabPages;
            }
            set
            {
                this.tabPages = value;
            }
        }

        public MyControl()
        {
            InitializeComponent();
        } 

Wenn ich dann im Property-Editor die Collections ändern möchte, kriege ich beim Hinzufügen eines neuen Controls die Meldung, dass MyTabPage nicht als serializable ist. Daraufhin habe ich [Serializable] vor die MyTabPage Klasse gesetzt und dann verschwand die Meldung, dafür wurde jetzt allerdings gesagt, dass UserControl nicht serializable ist und da hörte es dann mit meinem Wissen auf 🙂

Was mache ich denn jetzt noch falsch?

Dankend

Stefan

09.07.2008 - 11:32 Uhr

Hi,

danke für deinen Tipp, leider klappt es nicht so, wie erhofft 🙂 Hier erst mal mein Code:

using...
using System.ComponentModel.Design;

namespace WindowsApplication1
{
    [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
    [Serializable]
    public partial class MyControl : UserControl
    {
        private List<MyTabPage> tabPages = new List<MyTabPage>();

        [Serializable] // Fehler
        public List<MyTabPage> TabPages
        {
            get
            {
                return this.tabPages;
            }
        }

        public MyControl()
        {
            InitializeComponent();
        }

Wenn ich an der Stelle "//Fehler" den Eintrag mache, dann sagt der Compilier mir, dass dies an dieser Stelle nicht erlaubt ist. Wenn ich diese Zeile dann weg lasse, dann funktioniert das leider nicht - gibt keinen Unterschied zum vorigen Verhalten.

Was mache ich falsch? Bzw. welche Property meinst du?

Dankend

Stefan

09.07.2008 - 11:20 Uhr

Hi,

ich bin jetzt auf die Listen umgestiegen. Allerdings ergibt sich dann folgendes Problem:

Im Property-Editor kann ich dann die Collection ja durch Klick bearbeiten. Dann erscheint ein Fenster, wo ich Einträge zu dieser Liste hinzufügen und löschen kann. Das klappt auch soweit.

Wenn ich dann allerdings compiliere und dann den Editor wieder öffne, dann sind diese Einträge nicht mehr da. Die hinzugefügten Controls sind aber weiterhin über den Property-Editor aufrufbar - allerdings scheint jede Verknüpfung verlohren gegangen zu sein.

Weiß da jemand einen Rat, wie ich an dieser Stelle weiter machen muss.

Dankend

Stefan

09.07.2008 - 11:03 Uhr

Hi,

das mit den List ist ja genial - das macht ja alles, was ich brauche - ich bin begeistert. Dafür brauch ich dann net mal den Umweg über diese Strings.

War zwar nicht die direkte Antwort auf meine Frage, aber diese Antwort hat mich auf ganz andere Gedanken gebracht, die mir das Leben VIEL leichter machen wird.

Ich danke aus ganzem Herzen

Stefan

09.07.2008 - 10:58 Uhr

Hi,

evtl. noch zur Verdeutlichung:

wenn ich mir jetzt mal eine Windows-Form anschaue, dann hat diese ja auch die Eigenschaft "StartPosition" und dort erscheint dann ja auch so n' DropDown-Liste mit ein paar Einträgen. Genau das möchte ich halt auch haben - und zwar von allen Namen der Objekte, die mein UserControl hat.

Hilft das bei der Klärung meine Frage?

Dankend

Stefan

09.07.2008 - 10:57 Uhr

Hi,

nein, eigentlich nicht - außer ich verstehe mich selbst net 🙂

Ich habe diese Liste, auf der alle Objekte velinkt sind, auf die die Komponente zugreifen kann. Jedes dieses Objekte hat einen String Name.

Jetzt möchte jetzt im VS Property Editor einfach nur eine Drop-Down Liste aller Namen haben, die ich dann auswählen kann und dem Control wird dann übermittelt, was ausgewählt wurde.

Wenn ich das doch richtig sehe, besteht dann doch keine Kommunikation zwischen UserControl und Form, oder doch? Eigentlich soll doch dann auch die Form dem UserControl nichts mitteilen, oder sehe ich das falsch?

Dankend

Stefan

09.07.2008 - 10:43 Uhr

Hallo,

ich habe mir mal wieder ein UserControl geschrieben. Dieses hat eine ArrayListe mit ein paar internen Objekten:

private ArrayList tabPages = new ArrayList();

Jedes dieser Objekte ist vom Typ MyControl und hat die Eigenschaft "string: Name". Soweit so gut.

Was ich jetzt möchte:
In der Laufzeitumgebung in dem Eigenschafts-Fenster eine DropDown, wo man dann einen Namen auswählen kann. Nach dem Auswählen muss der Komponente nur noch mitgeteilt werden, wie der neue (ausgewählte) Name ist.

Jemand n' Ansatz, wie ich dies am besten angehe.

Dankend

stefan

09.07.2008 - 10:19 Uhr

Hallo,

hänge gerade vor dem selben Problem und wollte mal fragen, ob ihr hier weiter gekommen seid? Ich gehe 200%ig davon aus, dass man diese Funktion für die Pfeile und Hinzufügen/Entfernen anpassen kann.

Dankend

Stefan

08.07.2008 - 21:35 Uhr

Hi,

gerade in einem anderen Forum gefunden:

http://support.microsoft.com/kb/813450

Trotzdem danke 🙂

Stefan

08.07.2008 - 21:30 Uhr

Hallo,

ich habe mir ein UserControl geschrieben. An einer Stelle hat diese Komponente ein Panel. In dieses soll der Entwickler später per VS eigene Kontrols hinzufügen können. Aber VS verweigert mir, in dieses Control z.B. einen Button zu legen.

Also eigentlich möchte ich die neue Komponente als normalen Container benutzen - so wie man auch üblich ein Panel hin legt und darein dann wieder normale Controls legen kann.

Vielen Dank für eure Hilfe

Stefan

08.07.2008 - 16:03 Uhr

Hi,

die Bilder sind oben - hatte nur n' falschen Link eingegeben und direkt danach editiert - warst also verdammt schnell 🙂

Dankend

Stefan

08.07.2008 - 15:57 Uhr

Hallo,

wir setzten bei uns in der Applikation mehrere TabControls aus. Diese sehen grafisch/optisch wie folgt aus:

siehe Anhang

Dies stoßt bei einem Kunden "zu Augenschmerzen" und er ist bereit für eine optische Aufbesserung zu bezahlen. Die finale Version soll dann wie folgt aussehen:

siehe Anhang übernächster Beitrag

Leider habe ich keinen Plan, wie ich dieses umsetzen soll. Klar ist, dass es dann ein neues "MeinTabControl" geben wird, dass dann eingesetzt wird. Kann mir jemand sagen, wie ich sowas am besten angehe.

Dankend

Stefan

30.06.2008 - 13:41 Uhr

Hallo,

ich habe ein Basis-Panel, in welche verschiedene User-Panels, die wiederum irgendwelche Controls (Labels, Buttons usw.) haben, geadded werden. Grundsätzlich läuft das bisher wie folgt ab:

this.BasisPanel.Controls.Clear();
for (int i = ClientUtils.CmsUtils.ForumThemes.Length - 1; i >= 0; i--)
{
  UserPanel userPanel = new UserPanel(irgendwelche Optionen);
  this.BasisPanel.Controls.Add(userPanel);
}

Bisher wurde diese Funktion nur ein paar Mal aufgerufen. Jetzt aber läuft das Tool auf einer Workstation, auf der das Programm "nie" neugestartet wird und damit ergibt sich das PRoblem, dass die Benutzer-Objekte nicht freigegeben werden.

Im Task-Manager werden nach einer gewissen Zeit rund 2500 Benutzer-Objekte angezeigt und dann macht Windows dicht - verständlicherweise.

Die Frage ist, wie gebe ich vernünftig diese Benutzer-Objekte frei. Das Controls.Clear(); das nicht macht, ist mir bewusst. Hab auch schon mit Dispose(); mein Glück versucht, aber es werden immer weiter Objekte erzeugt. Stehe da gerade etwas auf dem Schlauch.

Dankend

Stefan

10.06.2008 - 21:22 Uhr

Hallo,

hab mich heute noch mal länger mit dieser Problematik befasst und komm einfach keinen Schritt weiter. Bin mittlerweile echt was am verzweifeln 🙂

Die Frage die mich am meisten beschäftigt: Wieso klappt das Verfahren 100 Mal (und auch noch mehr) aber nach einem Neustart des Clients geht's in die Hose. Das kann's doch echt net sein. Hierfür hab ich einfach 0 Erklärungen am Start.

Hab den Client auch mal testweise auf einem anderen Rechner gestartet. Same Procedure. Auch dort - gleiches Phänomen.

Meiner momentanen Ansicht nach ist es mit dieser Methode überhaupt nicht möglich einen "SSL-Server" zu betreiben, weil das Ding die ganze Zeit abraucht - und das kann's ja eigentlich net sein. Das muss doch n' Haken haben.

Ich danke euch für jeden Rat - bin echt auf euch angewiesen. Dankend

Stefan

PS: bin mittlerweile sogar soweit: Wenn jemand meint, dass Problem in Griff zu kriegen, dafür aber was Zeit benötigt, dann bin ich auch gerne bereit, ihn dafür mit paar EUR zu entschädigen. Bei Interesse einfach auch melden... Danke

09.06.2008 - 12:23 Uhr

Hallo,

ich möchte eine Client-Server TCP-Verbindung aufbauen, die über SSL abgesichert ist. Dafür verwende ich die Klasse SslStream. Folgend der Code für Client und Server...

Server:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;

namespace Server
{
    public partial class Form1 : Form
    {
        private ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
        public Form1()
        {
            InitializeComponent();

            TcpListener listener = new TcpListener(IPAddress.Any, 10000);
            listener.Start();

            while (true)
            {
                this.tcpClientConnected.Reset();
                listener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptTcpClientCallback), listener);
                this.tcpClientConnected.WaitOne();
            }
        }
        private void DoAcceptTcpClientCallback(IAsyncResult ar)
        {
            TcpListener listener = (TcpListener)ar.AsyncState;
            TcpClient newClient = listener.EndAcceptTcpClient(ar);
            
            X509Certificate2 cert = new X509Certificate2("d:\\cert.pfx");

            SslStream ssl = new SslStream(newClient.GetStream(), false);
            ssl.AuthenticateAsServer(cert, false, SslProtocols.Tls, false); // *HIER*

            TextWriter writer = new StreamWriter(ssl);
            writer.WriteLine("Hallo...");
            writer.Flush();

            this.tcpClientConnected.Set();
        }
    }
}

Client:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.IO;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;

namespace Client
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            TcpClient client = new TcpClient();
            client.Connect("localhost", 10000);

            SslStream ssl = new SslStream(client.GetStream(), false, 
                new RemoteCertificateValidationCallback(CertificateValidationCallback));
            ssl.AuthenticateAsClient("localhost");

            TextReader reader = new StreamReader(ssl);
            textBox1.Text += reader.ReadLine();

            client.Close();
            ssl.Dispose();
            reader.Dispose();

            client = null;
            ssl = null;
            reader = null;
        }

        private bool CertificateValidationCallback(object sender, X509Certificate certificate,
            X509Chain chain, SslPolicyErrors sslPolicyErrors)
        {
            return true;
        }
    }
}

Was klappt:

  1. Server starten
  2. Client starten
  3. Verbindung aufbauen mittels button1_Click
    Ich kann ebenso jetzt immer wieder Punkt 3 ausführen - das klappt 1a.

ABER:
Wenn ich den Client schließe und dann neu starte und dann wieder einen Verbindung aufbauen möchten, dann knallt es im Server an der Stelle HIER - und zwar in 90% aller Fälle. Wenn es mal nicht knallt und ich den Client wieder schließe und den Vorgang wiederhole, dann knallt es halt dann.

Komisch ist das 🙂

Meine Vermutung: ich hab keine - bin total ratlos und weiß net weiter.

Hier noch die Fehlermeldung:
Fehler bei SSPI-Aufruf, siehe interne Ausnahme.

Die InnerException sagte: Die lokale Sicherheitsautorität (LSA) ist nicht erreichbar.

Mein Freund Google konnte mich leider noch nicht auf den richtigen Weg bringen. Ich hoffe, ihr habt eine Idee.

Dankend

Stefan

03.06.2008 - 14:20 Uhr

Hallo,

das Tool speedtrace war mir neu und, zugegebenermaßen, hatte ich dort n' bissle Schiss vor mich auch da auch noch rein arbeiten zu müssen. Ich gebe dir aber 200%ig Recht: Ein guter PRogrammierer muss auch mit Profiler-Programmen umgehen können und daher werde ich's auf meiner Liste setze, mich mit sowas mal intensiver auseinander zu setzen - denn schaden kann's auf keinen Fall!

Dankend

Stefan

03.06.2008 - 14:15 Uhr

Hallo,

nur damit wir uns nicht falsch verstehen - ich will doch gar kein Zertifikat erstellen.

Ich habe doch

  • den privaten Key
  • den public Key
  • offizielles Zertifikat von Thawte

Ich muss diese drei Werte nur irgendwie in .NET laden, damit ich diese dort weiter nutzen kann, also den SslStream. Also von Erstellen ist aus meiner Sicht hier gar keine Rede, oder verstehe ich das falsch?

Dankend

Stefan

03.06.2008 - 14:05 Uhr

Hallo,

hab den Kram mit Thread.Sleep rausgenommen und wie vorgeschlagen ersetzt. Bin gerade fleißig am Testen aber bis jetzt kann ich den Fehler auch nicht mehr reproduzieren... Es wär zu schön, wenn's damit behoben wär 🙂 Ich hoffe es zumindest... sonst lasse ich vo mir hören 🙂

Stefan

03.06.2008 - 13:51 Uhr

Hi,

es ist gewollte, dass mehrere Rechner gleichzeitig per TCP/IP auf den Service zugreifen können. Daher nehme ich für jede Verbindung den TcpClient und übergebe den dem ConnectionHander. Dieser erzeugt dann einen neuen Thread in dem dann auf die Anfrage, die über TCP komme antwortet und sich dann sofort beendet. Dieser Thread sorgt dann auch dafür, dass der übergebene TcpClient geschlossen wird.

Stefan

03.06.2008 - 13:23 Uhr

Hi,

nein, das erwarte ich nicht. Ich erwarte aber, wenn die 100 Verbindungen beendet sind, dass dann die Last auch wieder weg geht - und das tut sie nicht (auch nach mehreren Minuten) - nur wenn ich halt n' Breakpoint setze.

Keine Sorge, heute ist net der 1. Mai und ich hab schon n' Menge Zeit an dem Problem verbracht und bin mittlerweile auch was von diesem Problem genervt - immerhin hat's mich schon viel Zeit und Nerven gekostet.

03.06.2008 - 12:48 Uhr

Hallo,

grundsätzlich habe ich ja keine Lust, nur wenn ein paar Hundert Verbindungen liefen, dann hab ich Last. Wenn ich dann' Breakpoint setzen (und dann meinetwegen auch direkt wieder rausnehme) ist die Last auch wieder weg.

Zugegebenermaßen, dass mit dem Thread.Sleep() gefällt mir auch nicht, habe aber bisher keine andere Möglichkeit gefunden. Habe mal nach begin/end Funktionen gesucht aber nichts gefunden, was auch nur ansatzweise Sinn macht. Magst du mir da vielleicht noch ein paar Zeilen Code mitteilen, damit ich das Grundprinzip ralle und eventuell bessere Möglichkeiten zum Suchen hab.

Dankend

Stefan

03.06.2008 - 12:28 Uhr

HAllo,

vielen Dank für deine Info. Folgend wird vorgegangen: Es wird ein Thread für den TcpListener gestartet:

this.mainThread = new Thread(new ThreadStart(Start));
            this.mainThread.Start();

Die Start-Funktion sieht wie folgt aus:

private void Start()
        {
            this.listener = new TcpListener(this.ip, this.port);

            try
            {
                this.listener.Start();
                
                while (this.forceStop == false)
                {
                  while (this.listener.Pending() == false)
                    {
                        Thread.Sleep(SleepTime); // 200

                        if (this.forceStop == true)
                        {
                            break;
                        }
                    }
                    if (this.forceStop == true)
                    {
                        break;
                    }

                    TcpClient NewConnection = this.listener.AcceptTcpClient();
                    if (NewConnection != null)
                    {
                        try
                        {
                            ConnectionHandler newConnection = new ConnectionHandler(ref NewConnection);
                        }
                        catch
                        {
                        }
                    }
                }
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
            }

            this.listener.Stop();
            this.listener = null;
        }

Die Variable "this.forceStop" kann von außen gesetzt werden und besagt, dass der Service (z.B. durch die Diensteverwaltung) beendet wurde. Der "ConnectionHandler" erhält dann die neue TCP-Verbindung und arbeitet (in einem neuen Thread) ein paar Sachen ab und beendet dann die Verbindung.

Wie man sieht, verwende ich Thread.Sleep. Ist das ein Problem oder wieso kommst du darauf zu sprechen?

Vielen Dank

Stefan

03.06.2008 - 11:51 Uhr

Hallo,

ich muss hier doch noch mal nerven und den Beitrag was nach oben pushen, bin nämlich leider in diesem Bereich immer noch net weiter gekommen und langsam drenkt das Thema doch was 🙂

Bin für jeden Tipp dankbar.

Stefan

03.06.2008 - 11:50 Uhr

Hallo,

nachdem ich die Problematik mit GC in den Griff bekommen hatte, war ich ja hoch erfreut darüber, dass die hohe Prozessor-Last nicht mehr auftritt. Dies entsprach aber leider nicht der Wahrheit. Das Problem trat weiterhin auf - schade 🙂

Nach Analyse des Codes habe ich eine Stelle im Code gefunden, die tatsächlich in eine Endlosschleife laufen konnte. Nach einem Fix war dies nun auch im Griff und das Problem tritt jetzt fast gar nicht mehr auf. Daraus folgere ich, dass mindestens noch eine weitere Stelle Probleme bereitet.

ABER:
Ich starte das Programm, trinke einen Kaffee, danach ist die Prozessor-Last hoch. Ich beende alle TCP/IP-Verbindungen (=> der Service hat nichts mehr zu, müsste sich langweilen) und die Prozessor-Last bleibt weiterhin oben. Ich warte und warte und warte (egal wie lange) immer hohe Prozessor-Last. Dann mach ich an irgendeine Stelle im Service einen Breakpoint (auch da, wo der Service gar nicht mehr hinkommt), die Prozessor-Last fällt sofort nach unten, alles ist normal.

Kann sich das einer erklären? Ich steh das echt wie'n Ox vorm Berg. Das kann doch net sein. Bin echt gespannt, wie ihr euch das erklären könnt 🙂

Dankend

Stefan

27.05.2008 - 09:34 Uhr

Hallo,

ich habe soeben noch mal intensiv nach der Umwandlung von pem to pfx gesucht und stoße dabei immer wieder auf folgende OpenSSL-Variante:

openssl pkcs12 -export -in cert.pem -inkey key.pem -certfile cacert.pem -out cert.pfx 

key.pem wäre in meinem fall der privateKey und cert.pem mein Zertifikat. Diese Dateien liegen mir vor. Wie zu sehen, wird aber auch noch das CA-Zert benötigt - in meinem Fall ja das von Thawte - aber da komm ich natürlich nicht dran.

Weiter auf der Suche...

Stefan

27.05.2008 - 08:06 Uhr

Hallo,

wie wandel ich denn meine Dateien in eine pfx-Datei um? So wie ich das nämlich verstanden haben, ist das Untereinanderschreiben der beiden Abschnitte in einer Datei das sogenannte pem-Format. Um dieses Pem in pfx umzuwandeln, wird aber der private Schlüssel der CA benötigt - und den habe ich natürlich nicht, da das Zertifikat ja von extern kommt.

Sehe ich das so richtig und wenn ja, was bleiben mir noch für Optionen?

Vielen Dank

Stefan

26.05.2008 - 23:06 Uhr

Hallo,

ich habe hier ein offizielles Zertifikat von Thawte. Dies soll dazu verwendet werden, eine TCP-Verbindung üer SSL/TLS zu verschlüsseln. Ich habe einmal das Zertifikat und zusätzlich natürlich noch den privaten Schlüssel vorliegen. Der Aufbau der beiden Dateien ist wie folgt:

[PRE]certificate:
-----BEGIN CERTIFICATE-----
MIIDYD...
-----END CERTIFICATE-----[/PRE]
[PRE]privateKey:
-----BEGIN RSA PRIVATE KEY-----
MIICXg...
-----END RSA PRIVATE KEY-----[/PRE]

Im Code lade ich das Zertifikat wie folgt:

X509Certificate2 cert = new X509Certificate2("D:\\Zertifikat.crt");

Damit ist natürlich der private Schlüssel noch nicht geladen. Ich finde aber keine Möglichkeit, den Wert "PrivateKey" zu setzen. Der ist bei mir immer Null und daher kann die Authentifizierung später gar nicht funktionieren.
Habe schon versucht, die beiden Dateien in eine zu kopieren und dann zu laden. Dies geht aber schief, wenn der PrivateKey oben ist. Ist er unten, dann wird er auch nicht berücksichtigt.

Hat jemand von euch einen Tipp, wie ich das hinbekomme.

Dankend

Stefan

26.05.2008 - 17:44 Uhr

Hi,

hab da jetzt doch noch eine Detail-Frage:

Ich verwende die Klasse TcpClient (namespace System.Net.Sockets). Diese ich auch von IDisposable abgeleitet => ich muss die mit Dispose(); freigeben - oder?

Bei mir ist das jetzt so definiert:
private TcpClient Connection = null;
und wenn ich dann this.Connection.Dispose(); eingebe, dann wird gemeckert:

System.Net.Sockets.TcpClient.Dispose(bool) is inaccessible due to its protection level.

Auch Dispose(true) und Dispose(false) bringen die gleiche Fehlermeldung. Stehe da jetzt echt was auf'm Schlauch 🙂

Dankend

Stefan

25.05.2008 - 11:53 Uhr

Hi,

ich glaube ich habe den Fehler schon gefunden und zwar dadurch, dass ich einen anderen gefixed habe 🙂

Ich war bis vor zwei Tagen davon ausgegangen, dass die GC jegliche Speicher-Arbeit abnimmt und da lag ich offensichtlich weit daneben (OutOfMemory und GC). Daher bin ich den gesamten Service durchgegangen, und habe an vielen Stellen die Funktion Dispose() aufgerufen. Dadurch steigt der Speicherbedarf auch nicht mehr an und wird immer wieder freigegeben, wenn er nicht gebraucht wird.

Seid ich diesen Task erledigt habe und den Service auf dem Server aktualisiert habe, ist auch die Prozessor-Last auch nach langer Laufzeit auf dem erwarteten Wert.

Meine Vermutung ist, dass die GC nach langer Laufzeit mit meinem Speicherumgang einfach überfordert war (die ist dafür ja auch nicht ausgelegt) und daher wurde so viel Prozessor-Last benötigt. Ich werde am Montag den Server noch mal was stressen (sehr sehr viele Verbindungen/Tasks pro Sekunde) und dann mal schauen, wie's dann aussieht. Momentan bin ich aber sehr guter Dinge, dass der Task sich sozusagen von selbst gelöst hat 🙂

Einen schönen Sonntag.

Stefan