Laden...
G
GarlandGreene myCSharp.de - Member
Softwareentwickler .NET / ABAP Emmerich, NRW Dabei seit 18.08.2006 497 Beiträge
Benutzerbeschreibung

Forenbeiträge von GarlandGreene Ingesamt 497 Beiträge

12.01.2009 - 15:54 Uhr

Auszug ausm WIKI

Unter 32-Bit-Systemen gibt es mit PSE36 und PAE Möglichkeiten, die 4-GB-Grenze zu überschreiten.

bringt nur was für wenige MS-Serverprodukte (2000 Advanced Server und DataCenter, 2003 Enterprise und DataCenter), da Microsoft für die meisten 32 Bit-Systeme 4 GB als Grenze für den adressierbaren Speicherbereich festgelegt hat. Auch wenn PAE aktiviert ist (was bei Nutzung des NX-Bits der Fall ist), werden maximal 4 GB abzüglich der bekannten Speichermappings für Erweiterungskarten genutzt.

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

€: mein Arbeitsrechner hat übrigens 8 GB Arbeitsspeicher, die brauch ich allein schon für meine virtuellen Maschinen. Und dementsprechend brauchte ich ein 64 Bit-Betriebssystem, also Vista Business x64. Ich mags nicht, aber es läuft.

12.01.2009 - 10:34 Uhr

in der neuen Express-Version "SQL Server 2008 Express with Tools" ist das "SQL Server Management Studio Basic" enthalten: http://www.microsoft.com/downloads/details.aspx?FamilyId=7522A683-4CB2-454E-B908-E805E9BD4E28&displaylang=en

10.01.2009 - 11:45 Uhr

Klar kann man binäre Inhalte in Datenbanken ablegen. Dafür gibts Blob (Binary Large Object)-Felder. Man kann eine Datei prinzipiell auch in ein Textfeld ablegen.

€: was die Felder angeht: du legst nicht wirklich eine Datei, sondern nur den Dateiinhalt ab. Wie man eine Tabelle für binäre Inhalte aufbaut, ist einem selbst überlassen. Üblicherweise werden neben dem Dateiinhalt auch noch ein paar Metadaten (Dateiname, Dateityp, Dateigröße, Speicherdatum, Änderungsdatum etc.) abgelegt - das ist einem aber selbst überlassen.

€2: das ist übrigens ganz üblich. Sharepoint macht das zum Beispiel so. Es ist aber nicht sonderlich schnell - handelt es sich um eine große Datenbank mit großen Dateien, ist es sinnvoller, die Dateien neben der Datenbank im Dateisystem abzulegen und in der Datenbank nur die Metadaten nebst Verweis auf die echte Datei abzulegen.

07.01.2009 - 15:59 Uhr

die Nachricht muss uralt sein, denn R/3 heisst schon lange MySAP ERP. Aktuellster R/3-Release war 4.7, 3.1 und 4.0 sind steinalt.

SAP hat für .Net den schon angesprochenen .Net-Connector bereitgestellt. Die Visual Studio-Integration läuft leider nur in VS 2003, aber die Komponente selbst kann man auch in .Net 2.0 (und 3.0, 3.5)-Projekten nutzen. Man muss dann halt die sonst vom Connector erzeugten Proxyklassen selbst erzeugen - ist mühselig, funktioniert aber.

07.01.2009 - 10:23 Uhr

man kann im Code ja leider nicht erkennen, ob er immer auf denselben Projektnamen testet.

07.01.2009 - 10:19 Uhr

was ich grad sehe:


alleDaten.VersionSet.Where(vs => vs.ProjektName.Trim() == Projektname) //geht

wenn das geht, liegt das wahrscheinlich an Leerzeichen entweder in vs.ProjektName oder in der Variable Projektname.

Das sollte dann funktionieren:


alleDaten.VersionSet.Where(vs => vs.ProjektName.Trim() == Projektname.Trim())

E: das könnte u.a. durch die Verwendung von char/nchar statt varchar/nvarchar im Datenbankfeld für den Projektnamen auftreten.

07.01.2009 - 10:08 Uhr

ohne EF oder Linq jetzt jemals eingesetzt zu haben würde ich schätzen, daß das "==" bei einer Variablen auf der rechten Seite die Objektreferenz prüft, da String ein Referenztyp ist (anders als Double, das ist ein Werttyp). Und da das Objekt "vs.ProjektName" nicht gleich der lokalen Variable "Projektname" ist, werden keine Daten gefunden.

Funktionierts denn, wenn du statt des Variablennamens die ToString()-Methode des Variablennamens benutzt? Also:


alleDaten.VersionSet.Where(vs => vs.ProjektName == Projektname.ToString())

29.12.2008 - 11:50 Uhr

Stichwort Reflection, einfaches Beispiel. Du hast ein Objekt des Typs "myclass" und willst einen beliebigen Eigenschaftswert setzen:



private void setValue(myclass target, string propertyName, object value)
{
Type classType = typeof(myclass);
PropertyInfo pi = classType.GetProperty(propertyName);
if (pi != null)
{
pi.SetValue(target, value, null);
}
}


Du holst dir das PropertyInfo-Objekt - wenn es existiert, ansonsten ist das Feld NULL - und benutzt dessen setValue-Methode, um den Wert zu setzen. Darin nicht inbegriffen ist eine Fehlerbehandlung, wenn die Typkonvertierung fehlschlägt - was bei Typen, die nicht String sind, höchstwahrscheinlich der Fall sein wird. Du wirst von Hand die Umwandlung des Attributwerts in den Datentypen der jeweiligen Eigenschaft vornehmen müssen.

28.12.2008 - 10:15 Uhr

wenn du eine WSDL hast, kann VS dir daraus Proxyklassen generieren. Die kannst du zwar erst aufrufen, wenn der Webservice existiert, aber du kannst schonmal gegen die Teile programmieren.

Hab mich übrigens vertan: wsdl.exe war das Tool für die alten ASP.Net-Webdienste. Für WCF-Clientproxys heisst das Tool SvcUtil.exe: http://msdn.microsoft.com/en-us/library/ms733133.aspx

Kleiner Tip, wenn du WCF verwendest: vergiss nicht, die Client-Verbindung per Hand zu schliessen (oder die generierte Client-Klasse, die IDisposable implementiert, zu disposen). Die alten Webdienst-Clientklassen haben das selbst bei jedem Aufruf gemacht, die neuen machen das nicht mehr. Ergebnis ist ein ansonsten unerklärbarer Timeout (am Server passiert scheinbar gar nichts), wenn man ein paar mal hintereinander Verbindungen aufmacht und Remote-Methoden aufruft.

28.12.2008 - 00:02 Uhr

Nullables werden im WSDL üblicherweise als optionale Parameter gekennzeichnet. Das sollte sprachunabhängig funktionieren. Wenn der Null-Wert zurückgeliefert werden soll, lässt der Webdienst dieses optionale Element einfach weg. Wenn du den Webdienst über automatisch generierten Client-Code (wsdl.exe oder Visual Studios "Dienstverweis hinzufügen"-Funktion) benutzt, wird das entsprechende Element dann NULL enthalten. Übernimmst du die clientseitige Behandlung selbst, musst du das optionale Element natürlich entsprechend behandeln.

Ich nutze übrigens nie Basistypen. Ich bau mir für alle Abfragen und alle Antworten jeweils Klassen, in die ich dann die entsprechenden Parameter einhänge. Bei den alten ASP.Net-Webdiensten war das sogar nötig, da die Dienstmethode über die Methodensignatur ermittelt wurde. Man konnte da in einem Webdienst nicht zwei Methoden mit denselben Parametern definieren (z. B. Input String, Rückgabe Int). Mit WCF geht das, soweit ich weiß.

23.12.2008 - 08:29 Uhr

warum so aufwändig? Wenn die Update-Versionsnummer höher ist als die Versionsnummer der installierten Anwendung, ist das Update noch nicht installiert. Da muss man sich dann "nur" noch darum kümmern, bei inkrementellen Updates (nur ein Teil der Anwendung enthalten, beispielsweise eine einzelne Bibliothek) nicht eines der Updates auszulassen. Ginge zum Beispiel über eine Prüfung in der Updateroutine, die eine bestimmte Vorversion voraussetzt.

22.12.2008 - 15:10 Uhr

halte ich für sehr undurchsichtig. Eine Update-Versionsnummer sollte im Idealfall der im Update enthaltenen Version entsprechen. So kann man anhand der Programmversion herausfinden, welche Updates einem fehlen. Bei deinem Beispiel könnte zum Beispiel folgendes passieren:

Programmversion 2.3, es kommen mehrere Updates raus.

Zuerst 2.3.1.1, ein Sicherheitspatch. Dann 2.3.2.2, ein kritisches Update. Dann 2.3.8.3, ein Featurepack - und zu guter letzt 2.3.1.4, ein weiterer Sicherheitspatch. Anhand der Nummer kann jemand, der das "übliche" Versionierungsschema gewohnt ist, nicht erkennen, daß der Patch 2.3.1.4 der letzte Patch ist. Und je mehr Patches es gibt, desto verwirrender wird es werden.

19.12.2008 - 11:07 Uhr

jQuery enthält eine Unmenge nützlicher Tools und Funktionen, die zudem noch intensiv getestet und tausendfach eingesetzt werden. MS liefert jQuery schon in der Beta des ASP.Net MVC-Frameworks mit, von daher würde ich mir jQuery auf jeden Fall mal gut anschauen und es selbst erstellten Skripten soweit möglich vorziehen.

14.12.2008 - 09:59 Uhr

will man da ein bisschen mehr machen, wären 4 GB sicherlich nicht verkehrt. Spätestens, wenn man einen virtuellen Webserver oder Datenbankserver einsetzen möchte. Aber für ganz normale Anwendungsentwicklung mit VS reichts.

02.12.2008 - 23:08 Uhr

die Internetverbindung ist ansonsten beidseitig unbelastet? Lokale Anmeldung ist ja schon mal gar keine Referenz, da ist ja nicht mal ein einziger Netzwerkadapter dazwischen. Bei einer Internetverbindung sind Netzwerkkarten und haufenweise Router dazwischen. Wenn dann noch über die Leitung runtergeladen wird (P2P-Programme sind da ganz besonders böse) oder die Gegenstelle (ich vermute, ein Hosting-Provider?) grad gut belastet ist, kann so eine Anmeldung schon eine ganze Zeit dauern.

02.12.2008 - 11:50 Uhr

Hallo GarlandGreene,

tu dir selbst einen Gefallen und schau dir in aller Ruhe ein Tutorial zu regulären Ausdrücken an. Ich kann das hier als Einstieg empfehlen.

PS: Ja ich hab das Regex-Tutorial hier im Forum schon gelesen, komme aber leider trotzdem nicht weiter...

herbivore

das Tutorial behandelt aber speziell Charakterklassen aber nur relativ kurz, von daher habe ich ein etwas ausführlicheres und weniger auf die Programmierung mit C# bezogenes Tutorial verlinkt.

02.12.2008 - 08:33 Uhr

@"([0-99]*$)" + //Hier happerts

tu dir selbst einen Gefallen und schau dir in aller Ruhe ein Tutorial zu regulären Ausdrücken an. Ich kann das hier als Einstieg empfehlen.

01.12.2008 - 09:08 Uhr

wenn die einzelnen Threads autark laufen, scheinen sie ja nicht viel miteinander zu tun zu haben. Was haben die dann in demselben Service verloren? Das ist eine Abhängigkeit, die einem nur Ärger machen kann. Jede Änderung an einem einzelnen Teilstück dieser später mal sehr umfassenden (vielleicht nicht mal im Code, aber in ihrer Tätigkeiten) Anwendung bedeutet, daß der Service gestoppt werden muss. Und man hat eine große, monolithische Anwendung, wo es gar nicht nötig wäre (und wo man auch gar keinen Vorteil davon hätte).

Keep it simple. Kleine Konsolenanwendungen, per Taskplaner aufgerufen, sind zwar nicht so elegant, aber auf lange Sicht viel einfacher zu warten und zu pflegen. Ich mach manche einfache Sachen (z. B. ein paar Backup-Skripte für MSSQL Express-Server) nicht mal in C# sondern in Perl, da kann ich schnell mal Anpassungen vornehmen.

Und wenn du alles in einer Anwendung halten willst: Such dir einen Scheduler (Quartz.net zum Beispiel, ist auch im Spring-Framework enthalten) und bau dir einen eigenen Taskplaner, der dann zum gegebenen Ereignis deine Verarbeitungsmethoden mit dem ThreadPool aufruft. So hast du nicht permanent einen Haufen Threads, die auf Arbeit warten.

28.11.2008 - 11:39 Uhr

Datei, Öffnen, URL der Sharepoint-Liste angeben, Dokument auswählen, öffnen. Speichern funktioniert genauso.

27.11.2008 - 14:30 Uhr

kann man machen. Man muss WCF aber um einen Protokollhandler für das benutzte Protokoll erweitern: http://code.msdn.microsoft.com/WcfBinaryTcpExt

25.11.2008 - 14:53 Uhr

ja, ich prüfe in meinem Code direkt gegen einen DC. Aber es gibt anscheinend auch Möglichkeiten, den DC vom Framework ermitteln zu lassen.

€: vor den Namen das Protokoll "ldap://" setzen (Beispiel: "ldap://dc1.company.local")

Ich müsste jetzt selber nachschauen, was bei nicht erfolgreicher Authentifizierung passiert. Eine Ausnahme wird anscheinend nicht geworfen, aber entweder ist dirEntry NULL oder dirEntry verweist auf einen "leeren" Account. Du kannst ja mal prüfen, ob dirEntry.Name den Usernamen enthält (oder überhaupt etwas enthält - unter Umständen enthält er nämlich nicht 1:1 den übergebenen Usernamen (der wohl eher der Anmeldename ist), den du angibst, sondern liest ihn aus dem Verzeichnis aus)

25.11.2008 - 14:47 Uhr

da kommts gar nicht so sehr auf die Tabellen an sich an, mehr auf das allgemeine Vorgehen beim Ansprechen von RFC-Bausteinen im SAP-System. Das Vorgehen ist immer dasselbe, nur die Parameter und der Baustein ändern sich. Von daher ist dieses Beispiel genauso gut oder schlecht wie jedes andere auch.

Ich hab mir das ganze damals mehr oder weniger aus den Beispielen, die beim SAP .Net-Connector dabei waren, erarbeitet. Die Beispiele sind nicht der Hammer, aber für erste Gehversuche reichts. Wenn man dann einmal verstanden hat, wie man damit arbeitet, kann man relativ problemlos eigene Wege gehen.

Es ist aber immer auch wichtig zu wissen, was im SAP-System vor sich geht. Speziell was die Datentypen im SAP-Dictionary angeht, muss man sich ein bisschen informieren. Sowas wie NUMC (ein numerischer Wert, gespeichert in einem String) gibts im Grunde nicht in der .Net-Welt. Da gibts dann noch QUAN (Mengenfeld, immer abhängig von einer Mengeneinheit, der Verweis auf das dazugehörige Mengenfeld muss im Dictionary angegeben sein), DATS (Datumsfeld, im Grunde aber ein 8 Zeichen langes Characterfeld) und diverse andere. Die meisten sind im Endeffekt nur Characterfelder mit irgendeiner Form von Eingabeprüfung, von daher wirst du fast alle Daten in Form von Zeichenketten aus dem SAP-System bekommen. Dazu gibts dann aber auch Append-Strukturen, hier können ganze Strukturen in eine Tabelle eingehängt werden.

25.11.2008 - 13:43 Uhr

du kannst rfc_read_table schon benutzen, aber musst dir im Klaren sein, daß es da Probleme gibt. yrfc_read_table ist ein Funktionsbaustein, der im SAP Service-Center unter der angegebenen Hinweisnummer 758278 zu finden ist. Kann da runtergeladen und installiert werden.

BAPIRfcStruct_YTAB4000 ist eine Struktur (genauer gesagt: ein Proxy für eine Struktur im SAP-System), kein Funktionsbaustein. Und wie erwähnt unterscheidet sich da wahrscheinlich nur die Benennung der Proxyklassen, die das SAP-Tool im Visual Studio generiert. YTAB4000 ist eine Struktur, die man für YRFC_READ_TABLE im ERP-System anlegen muss, die Struktur im C#-Projekt dient als Gegenstück zu dieser Struktur.

Wenn man minimale Abap-Kenntnisse hat, kann man sich auch einen RFC-fähigen Baustein schreiben, der diese spezielle Aufgabe erledigt. Das muss man dann aber im SAP-System selbst machen. Und es ist äußerst unüblich und daher von der SAP nicht gern gesehen, wenn man direkt Tabellendaten ausliest. In vielen Fällen gibts BAPIs (Business API) für Zugriffe auf SAP-Daten, die beachten dann auch die Businessregeln des ERP-Systems. Obs jetzt was für diesen Fall gibt, kann ich nicht sagen. Das Vorgehen wäre aber sehr ähnlich. Da kann dir wahrscheinlich eher ein SAP-Berater Auskunft geben.

25.11.2008 - 12:47 Uhr

RFC_READ_TABLE ist eine interne Funktion und nicht für die Kundenverwendung freigegeben. Zudem hat der Baustein Probleme in Unicode-Systemen. Es gibt dazu einen Hinweis 758278, der einen angepassten, vom Kunden zu implementierenden Baustein enthält (YRFC_READ_TABLE). Muss man bei auftretenden Fehlern einfach wissen, daß SAP diesen Baustein anscheinend selbst nur noch spärlich verwendet und die Funktion nicht garantiert.

Ich selbst habe den Baustein YRFC_READ_TABLE im System implementiert und über den Proxygenerator die Klassendefinitionen für die Parameter erzeugt. Dazu braucht man dann noch den SAP-Klienten (bei mir eine von SAPClient abgeleitete Klasse). Das sieht dann beispielseweise so aus (Klasse BAPITableAccess):


    [Serializable]
    public class BAPITableAccess: SAPClient
    {

        /// <summary>
        /// Exception constant for ABAP-Exception DATA_BUFFER_EXCEEDED
        /// </summary>
        public const string Data_Buffer_Exceeded = "DATA_BUFFER_EXCEEDED";

        /// <summary>
        /// Exception constant for ABAP-Exception FIELD_NOT_VALID
        /// </summary>
        public const string Field_Not_Valid = "FIELD_NOT_VALID";

        /// <summary>
        /// Exception constant for ABAP-Exception NOT_AUTHORIZED
        /// </summary>
        public const string Not_Authorized = "NOT_AUTHORIZED";

        /// <summary>
        /// Exception constant for ABAP-Exception OPTION_NOT_VALID
        /// </summary>
        public const string Option_Not_Valid = "OPTION_NOT_VALID";

        /// <summary>
        /// Exception constant for ABAP-Exception TABLE_NOT_AVAILABLE
        /// </summary>
        public const string Table_Not_Available = "TABLE_NOT_AVAILABLE";

        /// <summary>
        /// Exception constant for ABAP-Exception TABLE_WITHOUT_DATA
        /// </summary>
        public const string Table_Without_Data = "TABLE_WITHOUT_DATA";
   

        [RfcMethod(AbapName = "YRFC_READ_TABLE")]
        public void rfc_read_table(
           [RfcParameter(AbapName = "DELIMITER", Direction = RFCINOUT.IN, RfcType = RFCTYPE.RFCTYPE_CHAR, Length = 1, Length2 = 2, Optional = true)] string delimiter,
           [RfcParameter(AbapName = "DISTINCT", RfcType = RFCTYPE.RFCTYPE_CHAR, Optional = true, Direction = RFCINOUT.IN, Length = 1, Length2 = 2)] string distinct,
           [RfcParameter(AbapName = "FIX", RfcType = RFCTYPE.RFCTYPE_CHAR, Optional = true, Direction = RFCINOUT.IN, Length = 1, Length2 = 2)] string fix,
           [RfcParameter(AbapName = "NO_DATA", Direction = RFCINOUT.IN, RfcType = RFCTYPE.RFCTYPE_CHAR, Length = 1, Length2 = 2, Optional = true)] string nodata,
           [RfcParameter(AbapName = "QUERY_TABLE", Direction = RFCINOUT.IN, RfcType = RFCTYPE.RFCTYPE_CHAR, Length = 30, Length2 = 60, Optional = false)] string tableName,
           [RfcParameter(AbapName = "ROWSKIPS", Direction = RFCINOUT.IN, RfcType = RFCTYPE.RFCTYPE_INT, Optional = true, Length = 4, Length2 = 4)] int rowskips,
           [RfcParameter(AbapName = "ROWCOUNT", Direction = RFCINOUT.IN, RfcType = RFCTYPE.RFCTYPE_INT, Optional = true, Length = 4, Length2 = 4)] int rowcount,
           [RfcParameter(AbapName = "DATA", Direction = RFCINOUT.INOUT, RfcType = RFCTYPE.RFCTYPE_ITAB, Optional = false)] ref BAPIRfcTab_YTAB4000 data,
           [RfcParameter(AbapName = "FIELDS", Direction = RFCINOUT.INOUT, RfcType = RFCTYPE.RFCTYPE_ITAB, Optional = false)] ref BAPIRfcTab_RFC_DB_FLD tabFields,
           [RfcParameter(AbapName = "OPTIONS", Direction = RFCINOUT.INOUT, RfcType = RFCTYPE.RFCTYPE_ITAB, Optional = false)] ref BAPIRfcTab_RFC_DB_OPT tabOptions)
        {
            object[] results = null;
            object[] pars = new object[] { delimiter, distinct, fix, nodata, tableName, rowskips, rowcount, data, tabFields, tabOptions};
            results = this.SAPInvoke("rfc_read_table", pars);

            if (results.Length >= 1)
                data = results[0] as BAPIRfcTab_YTAB4000;
        }



        public BAPIRfcTab_YTAB4000 Read_Table(string tableName, string delimiter, BAPIRfcTab_RFC_DB_OPT options, BAPIRfcTab_RFC_DB_FLD fields)
        {
            BAPIRfcTab_YTAB4000 result = new BAPIRfcTab_YTAB4000();

            rfc_read_table(delimiter, " ", "X", " ", tableName, 0, 0, ref result, ref fields, ref options);

            return result;
        }


        public BAPIRfcTab_YTAB4000 Read_Table(string tableName, string delimiter, BAPIRfcTab_RFC_DB_OPT options, BAPIRfcTab_RFC_DB_FLD fields, int rowSkips, int rowCount)
        {
            BAPIRfcTab_YTAB4000 result = new BAPIRfcTab_YTAB4000();

            rfc_read_table(delimiter, " ", "X", " ", tableName, rowSkips, rowCount, ref result, ref fields, ref options);

            return result;
        }
    

    }


Definition von BAPIRfcTab_YTAB4000


    public class BAPIRfcTab_YTAB4000: SAPTable
    {

        public override Type GetElementType()
        {
            return typeof(BAPIRfcStruct_YTAB4000);
        }

        public override object CreateNewRow()
        {
            return new BAPIRfcStruct_YTAB4000();
        }

        public BAPIRfcStruct_YTAB4000 this[int index]
        {
            get
            {
                return ((BAPIRfcStruct_YTAB4000)(List[index]));
            }
            set
            {
                List[index] = value;
            }
        }

        public int Add(BAPIRfcStruct_YTAB4000 value)
        {
            return List.Add(value);
        }

        public void Insert(int index, BAPIRfcStruct_YTAB4000 value)
        {
            List.Insert(index, value);
        }

        public int IndexOf(BAPIRfcStruct_YTAB4000 value)
        {
            return List.IndexOf(value);
        }

        public bool Contains(BAPIRfcStruct_YTAB4000 value)
        {
            return List.Contains(value);
        }

        public void Remove(BAPIRfcStruct_YTAB4000 value)
        {
            List.Remove(value);
        }

        public void CopyTo(BAPIRfcStruct_YTAB4000[] array, int index)
        {
            List.CopyTo(array, index);
        }

    }

Definition von BAPIRfcStruct_YTAB4000


    [RfcStructure(AbapName = "YTAB4000", Length = 4010, Length2 = 8020)]
    public class BAPIRfcStruct_YTAB4000: SAPStructure
    {

        private string m_WorkArea;

        [RfcField(AbapName = "WA", RfcType = RFCTYPE.RFCTYPE_CHAR, Length = 4010, Length2 = 8020, Offset = 0, Offset2 = 0)]
        [XmlElement("WA", Form = XmlSchemaForm.Unqualified)]
        public string Wa
        {
            get { return m_WorkArea; }
            set { m_WorkArea = value; }
        }

    }

Zu guter letzt hab ich mir eine Funktion geschrieben, die das ganze etwas kapselt und mir die zurückgegebenen Zeilen in einer generischen Liste List<string> zurückgibt. Die darin benutzte Klasse SAPConnector.Main.ConnectionHelper ist nur eine Hilfsklasse, die mir eine Verbindung zu einem SAP-System anhand eines Systemalias erzeugt. Die Proxys für die Tabellen OPTIONS, FIELDS und DATA heissen bei mir nur anders, sollten von der Struktur her aber deinen entsprechen.


        public static List<string> Read_Table(string systemAlias, string tableName, string delimiter, string abapQueryOptions, List<string> fieldNames, int rowSkips, int rowCount)
        {
            List<string> rows = new List<string>();
            BAPIRfcTab_YTAB4000 result = new BAPIRfcTab_YTAB4000();

            // Verbindung zum R/3
            SAP.Connector.SAPConnection connection = SAPConnector.Main.ConnectionHelper.OpenConnection(systemAlias);

            if (connection != null)
            {
                BAPIRfcTab_RFC_DB_OPT tabOpt = new BAPIRfcTab_RFC_DB_OPT();
                if (abapQueryOptions != string.Empty)
                {

                    if (abapQueryOptions.Length > 72)
                    {
                        int counter = 0;
                        while (counter < abapQueryOptions.Length)
                        {
                            int length = abapQueryOptions.Length - counter;
                            if (length > 72)
                                length = 72;
                            BAPIRfcStruct_RFC_DB_OPT rowOpt = tabOpt.CreateNewRow() as BAPIRfcStruct_RFC_DB_OPT;
                            rowOpt.Text = abapQueryOptions.Substring(counter, length);
                            tabOpt.Add(rowOpt);
                            counter += length;
                        }
                    }
                    else
                    {
                        BAPIRfcStruct_RFC_DB_OPT rowOpt = tabOpt.CreateNewRow() as BAPIRfcStruct_RFC_DB_OPT;
                        rowOpt.Text = abapQueryOptions;
                        tabOpt.Add(rowOpt);
                    }
                }

                BAPIRfcTab_RFC_DB_FLD tabFields = new BAPIRfcTab_RFC_DB_FLD();
                foreach (string fieldName in fieldNames)
                {
                    BAPIRfcStruct_RFC_DB_FLD rowFields = tabFields.CreateNewRow() as BAPIRfcStruct_RFC_DB_FLD;
                    rowFields.Fieldname = fieldName;
                    tabFields.Add(rowFields);
                }

                BAPITableAccess bapiClass = new BAPITableAccess();
                bapiClass.Connection = connection;

                result = bapiClass.Read_Table(tableName, delimiter, tabOpt, tabFields, rowSkips, rowCount);

                // Verbindung schliessen
                SAPConnector.Main.ConnectionHelper.CloseConnection(systemAlias);

                foreach (BAPIRfcStruct_YTAB4000 row in result)
                {
                    rows.Add(row.Wa);
                }

            }


            return rows;
        }

du müsstest das für dich etwas verändern, da ich z. B. den Distinct-Parameter nicht von aussen annehme und immer leer an den RFC-Baustein übergebe.

25.11.2008 - 11:45 Uhr

mist, da hatte der Serverausfall meinen Post geschluckt.

Prüfung gegen ein Active Directory:


using System.DirectoryServices;
...
DirectoryEntry dirEntry = new DirectoryEntry(adServerName, username, password, AuthenticationTypes.Secure);
...

wenn dirEntry gefunden wurde, konnte der Benutzer gefunden und mit dem übergebenen Passwort authentifiziert werden.

23.11.2008 - 20:25 Uhr

der Webservice muss ja von irgendeinem HTTP-Webserver gehostet werden. Wenn du das Projekt im Debugger aufrufst, wird standardmäßig der im VS integrierte Testserver benutzt. Du kannst aber auch den IIS-Webserver von Windows so einrichten, daß er deinen Webdienst hostet. Dann kannst du den Webdienst auch von anderen C#-Projekten aus (und von überall aus dem Netzwerk) aufrufen, solang der IIS bei dir läuft.

22.11.2008 - 23:15 Uhr

Naja dann legt man die Binärdaten eben in ne extra Tabelle und holt die bei bedarf über ein join mit.

auch suboptimal. SQL-Datenbanken sind generell einfach nicht dazu gedacht, große binäre Datenmengen zu handhaben. Die dafür nötige IO-Leistung geht auf die Performance, der Cache wird belastet und generell ist die Geschwindigkeit ein Witz, da diese Blobs halt keine feste Größe haben und der Server für jeden Datensatz in der Tabelle rumspringen muss. Lad mal spasseshalber ein paar 20 MB-Elemente (in Mediendatenbanken landen ja meist die HQ-Dateien, die dann bei Bedarf ins gewünschte Format runtergerendert werden) vom Dateisystem und vom SQL-Server und schau dir an, was schneller ist. Das Dateisystem kann mehr oder weniger die volle Leistung des Plattensubsystems abrufen, der SQL-Server sucht erstmal den Datensatz und fängt dann an, den Blob-Inhalt zu suchen und nachzuladen. Und Mediendatenbanken haben neben den großen Bildern auch die Thumbs irgendwo abgelegt, um in Verzeichnissen eine Vorschau anzubieten. Die müssen dann zwangsweise in größeren Paketen runtergeladen werden. Auch jeweils "nur" 5-10 kb pro Thumb, das sind im Vergleich zu "normalen" Datenzeilen aber trotzdem ganz ordentliche Datenmengen. Und bei einer Anzeige von 20 Thumbs auf einer Seite müssen nur ein paar Anwender parallel ein bisschen rumblättern, um den Server ganz ordentlich ins Schwitzen zu bringen.

Nebenbei gehts bei sowas ja meist auch nicht um das Laden eines einzelnen Elements. Belaste so ein System mal etwas stärker, am besten mit Batchkonvertierung mehrerer Images oder als Webserver-Backend. Der Server geht bei vielen Anfragen derart in die Knie, das muss man sich nicht antun.

22.11.2008 - 19:18 Uhr

Und genau darum gehts beim Filestream Datentyp.
Wieso die Datenbank großartig langsamer sein soll ob da jetzt 10gb Binärdaten drin sind oder nicht ist mir auch nicht klar.

anscheinend greift das Caching da nicht mehr. MS warnt aber selber davor, zu viele und zu große binäre Daten in seinen SQL-Servern abzulegen. Für Sharepoint gibt es da zwar keine fertige Lösung (auch der FileStream wird da bisher nicht unterstützt), aber ein Interface für einen externen Storageprovider.

22.11.2008 - 16:36 Uhr

wenns datenbankunabhängig bleiben soll: Bilder auf jeden Fall ins Dateisystem. Datenbanken werden ziemlich langsam, wenn große Mengen Binärdaten darin abgelegt werden. Wir haben bei uns ein DMS (Celum Imagine, wen's interessiert) im Einsatz, das als DB einen MySQL-Server nutzt. Anfangs waren die Bilddaten in der Datenbank, bei einer Datenbankgröße von knapp 10 GB hat das Teil schon ziemlich geächzt. Mit dem (leider optionalen) Filesystem-Modul kann man die Bilddaten aufs Dateisystem auslagern, was einen extremen Performanceboost gebracht hat. Von daher: Metadaten in die Datenbank, Bilddaten aufs Dateisystem.

21.11.2008 - 22:04 Uhr

das ist ein modales Dialogfenster. Ein Tutorial dazu gibts u.a. hier: http://luke.breuer.com/tutorial/javascript-modal-dialog.aspx

20.11.2008 - 15:05 Uhr

darauf wird u.a. in der MSDN eingegangen: http://msdn.microsoft.com/en-us/library/ms734691.aspx

20.11.2008 - 14:02 Uhr

prinzipiell sollte WCF vollständig SOAP-kompatibel sein und sowohl auf Serverseite fremde Clients bedienen als auch auf Clientseite fremde Dienste in Anspruch nehmen können.

20.11.2008 - 09:04 Uhr

die Schemadatei muss in den Ordner

%PROGRAMFILES%\Microsoft Visual Studio XYZ\Xml\Schemas

17.11.2008 - 15:25 Uhr

das ist c#, nicht VB. In C# kannst du eine Zeile einfach umbrechen, dafür gibt es kein Steuerzeichen.

17.11.2008 - 14:23 Uhr

was hat das mit ASP.Net zu tun?

17.11.2008 - 11:29 Uhr

für den Fall, dass man mal nicht ein Bool als Prüfergebnis braucht:


string a;
a = Methode() == 1 ? "OK" : "NICHT OK";

17.11.2008 - 09:16 Uhr

r = SmsSender.SendMessage()

12.11.2008 - 16:09 Uhr

Hallo Community,
Java: Plattformunabhängig, langsam

warum sollte Java langsam sein? Vor allem im Vergleich zu ASP.Net? Die meisten der bekannten Open Source-Bibliotheken und Tools im .Net-Umfeld haben ihren Ursprung in Java-Bibliotheken (log4j, ant, hibernate, spring) und Java ist, was die Entwicklung von MVC-Anwendungen fürs Web angeht, noch einige Kilometer voraus. Geschwindigkeitstechnisch haben mich die Java-Anwendungen, die wir hier mit Tomcat hosten, im Vergleich zu einigen .Net-Anwendungen (im speziellen Dotnetnuke) nicht enttäuscht, ganz im Gegenteil.

Einer der ganz wenigen Bereiche, in denen .Net einen ernsthaften Vorteil hat, ist die Anbindung an eine Active Directory-Domäne mit SSO-Unterstützung. Da haben viele Java-Anwendungen große Probleme, in komplexeren AD-Strukturen fehlerfrei zu arbeiten, zumindest mit NTLM. .Net hat da allein durch den IIS schon einen großen Vorteil.

07.11.2008 - 12:16 Uhr

du willst die Skripte per sqlcmd aufrufen? Dann würd ich das auszuführende Skript jeweils in eine temporäre Datei speichern und dann über

sqlcmd -i "\pfad\zum\skript\skript.sql"

ausführen.

Du kannst die Skripte auch über eine SQLConnection und ein SQLCommand ausführen.

Beispiel:


...
    string queryString = 
        "Update Tabelle set Feld = 1;";
    using (SqlConnection connection = new SqlConnection(
               connectionString))
    {
        SqlCommand command = new SqlCommand(
            queryString, connection);
        connection.Open();
        command.ExecuteNonQuery();
    }


06.11.2008 - 17:10 Uhr

entnommen von hier


/// <summary>
/// Extracts an embedded file out of a given assembly.
/// </summary>
/// <param name="assemblyName">The namespace of you assembly.</param>
/// <param name="fileName">The name of the file to extract.</param>
/// <returns>A stream containing the file data.</returns>
public static Stream GetEmbeddedFile(string assemblyName, string fileName)
{
    try
    {
        System.Reflection.Assembly a = System.Reflection.Assembly.Load(assemblyName);
        Stream str = a.GetManifestResourceStream(assemblyName + "." + fileName);
           
        if(str == null)
            throw new Exception("Could not locate embedded resource '" + fileName + "' in assembly '" + assemblyName + "'");
        return str;
    }
    catch(Exception e)
    {
        throw new Exception(assemblyName + ": " + e.Message);
    }
}

06.11.2008 - 10:20 Uhr

da Smart Clients immer noch mit extrem wenig Speicher auskommen müssen und die SQL-Engine mit jedem Feature (besonders, wenn es um Transaktionen geht) mehr Speicher verbrät, ist es relativ normal, daß die kleinen Datenbanken für CE- und WM-Geräte das nicht oder nur in geringem Maße unterstützen. Bringt ja auch nix, wenn die Datenbank zwar alles kann, dafür aber nur auf Highend-Geräten läuft. Wir haben hier Scanner, die insgesamt 64 MB Speicher zur Verfügung haben, davon stehen nur rund 28 MB für Anwendungen zur Verfügung (Aufrüsten des Datenspeichers ist zwar möglich, aber der ist dann ziemlich langsam). Wenn da jetzt noch die Datenbank dazukommt (und im gegebenen Fall liegt alles im Speicher der Anwendung, ansonsten ginge für den Datenbankcontainer auch noch Speicher im Object Store drauf), ist schnell Schicht. Da ist mir ein sehr abgespecktes SQLite sehr recht.

04.11.2008 - 17:03 Uhr

du willst, daß zum Beispiel die id als Int optional ist? Dann müsstest du ein Nullable<int> verwenden. Denn Int und Float selbst können nicht NULL sein.

04.11.2008 - 13:48 Uhr

ein String kann immer NULL sein. Wenn du das XmlElement-Attribut IsNullable auf true setzt, muss der Client zwar das Element schicken, kann es aber immer noch mit dem xsi:nil-Attribut im Feld als NULL senden.

siehe hier

31.10.2008 - 09:02 Uhr

XML ist aus zwei Gründen eher ungeeignet:

zum einen muss ein XML-Dokument als ganzes validiert werden. Das ist auf einem schnellen Server kein großes Problem, auf einem mobilen Gerät wird es jedoch sehr schnell zu einem Problem. Es gibt, wie du festgestellt hast, auch keine einfache Möglichkeit, einfach nur Daten anzuhängen. Man liest und schreibt immer die gesamte Datei.

Zum anderen produziert XML einen gewaltigen Overhead, der die reine Datenmenge ganz schnell auf ein vielfaches aufbläst. Auf einem Desktop oder Server sind ein paar MB XML-Daten kein Problem, der mobile Client hat daran aber ziemlich zu schlucken.

Wenn du eine Datenbank benutzen möchtest, kannst du u.a. SQLite ausprobieren. Speichert ebenfalls alles in eine Datei, ist relativ einfach zu benutzen und bietet zudem SQL-Datenbankabfragen, man muss also nicht selbst in der Datei navigieren.

Ansonsten kommt es stark auf die Art der Daten an. Wenn die Datenstruktur simpel genug ist, kann man auch ganz einfach eine Textdatei benutzen und die Daten im CSV-Format darin ablegen. Ob das im Vergleich zu SQLite aber sinnvoll ist, hängt davon ab, wie viele verschiedene Daten du speicherst und wie du darauf zugreifen musst.

27.10.2008 - 09:14 Uhr

laut MSDN gibt DirectorySearcher.FindOne() ein NULL zurück, wenn nichts gefunden wurde.

Ein


if (result != null)
{
 // was gefunden
}

sollte daher funktionieren.

22.10.2008 - 12:17 Uhr

eine Variante wäre, über die Winapi die laufenden Fenster zu holen und zu prüfen, ob eines mit demselben Titel und anderer Prozessnummer läuft. Die einfachere Variante, die ich meistens wähle, wäre eine Lock-Datei. Beim Start eine temporäre Datei mit einem festgelegten Namen erstellen und im Schreibmodus geöffnet halten. Gibts die Datei beim Start schon und kann man sie nicht löschen, läuft die Anwendung bereits.

19.10.2008 - 19:22 Uhr

wo soll der Fehler denn auftreten? Da wird nur in einer Zeile die Klasse Shell32.ShellClass angesprochen - und da wird sie explizit instanziert. Ich seh gar nicht, wo das Objekt shell eingesetzt wird.

17.10.2008 - 10:38 Uhr

das ASP.Net MVC-Framework bietet einen etwas anderen Ansatz als die klassischen WebForms zur Entwicklung von Webanwendungen mit ASP.Net. WebForms verhalten sich teilweise ja wie Windows Forms - es gibt serverseitige Events über Postback, du kannst im Viewstate Daten ablegen und beim Postback wieder nutzen. MVC arbeitet da etwas anders. Bei einem Aufruf wird über Routing-Vorgaben ein Controller identifiziert, der den Request bearbeiten soll. Der bereitet dann die Daten vor und gibt diese nur noch an eine View (im Prinzip ein stark abgespecktes Webform). Anstelle des Postback, der mit normalen WebForms ja im WebForm selbst behandelt wird, erhält hier der Controller (bzw. EIN Controller - welcher das ist, wird wiederum übers Routing ermittelt) die POST-Daten und bearbeitet sie. Das ganze trennt die Datenbearbeitung von der Datenanzeige. Man kann darüber sehr viel einfacher Unit-Tests durchführen, da der Controller unabhängig von der View ist.

hier gibts einige Tutorials, die die Neuerungen häppchenweise erklären.

16.10.2008 - 16:52 Uhr

schau mal hier: CAPI-Wrapper

16.10.2008 - 16:42 Uhr

wie gesagt, die Speicherverwaltung vom SQL-Server scheint da ihre Tücken zu haben. 32 Bit-Prozesse haben die Begrenzung auf 2 GB, die CLR läuft ebenfalls in diesem Prozess, damit muss sich alles zusammen die 2 GB teilen. Und anscheinend gibts da ein Problem mit dem virtuellen Adressbereich, unabhängig von der tatsächlichen Speicherauslastung. Mit dem SQL Server für 64 Bit-Systeme ist das übrigens kein Problem mehr, da hat der Prozess dann 8 TB virtuellen Adressraum zur Verfügung.