Laden...
Avatar #avatar-2834.jpg
Rainbird myCSharp.de - Experte
Fachinformatiker (AE) Mauer Dabei seit 28.05.2005 3.728 Beiträge
Benutzerbeschreibung
Ich mag Tee lieber als Kaffee.

Forenbeiträge von Rainbird Ingesamt 3.728 Beiträge

23.04.2010 - 08:14 Uhr

Hallo Wyatt,

Du darfst keinen TcpServerChannel verwenden sondern musst einen TcpChannel verwenden. Sonst kann der Server nicht selber wieder Client sein. Clientseitig solltest Du auch den TcpChannel verwenden (Falls der Client in einem Szenario mal kurz Server spielen muss).

Es kann auch sinnvoll sein serverintern über einen zusätzlichen IpcChannel zu kommunizieren. Ist schneller und muss nicht über den TCP-Stack.

P.S.: Super Buch! Allerdings teile ich z.B. die Auffassung nicht, daß Remoting bevorzugt im IIS gehostet werden sollte.

22.04.2010 - 02:31 Uhr

bei "securityServiceProxy.IsInRole" der Aufruf nicht zurückkehrt. Der Aufruf komm im Debug-Modus garnicht erst im Security Service an. Finde den Grund nur leider nicht. Ist das nicht seltsam, zumahl es von Client-Seite aus funktioniert? Es funktioniert ja seltsamerweise auch auf Server-Seite, sobald ich wieder die Config-Datei verwende.
Haste du vielleicht spontan ne Idee dazu?

Schau Dir mal den Code der Eigenschaft ApplicationServer.SeverURL an. Der URL wird aus dem Aufrufkontext bezogen. Der URL des Applikationsservers an dem sich ein Benutzer anmeldet ist Teil der Sitzungsinformationen, die im Aufrufkontext (Siehe MSDN: CallContext-Klasse) abgelegt werden (das passiert in ApplicationServer.Logon). Die Daten im Aufrufkontext werden automatisch und stillschweigend bei JEDEM Remoting-Aufruf übertragen und dort in den Datenslots des Arbeitsthreads abgelegt (Man kann an einen Thread einfach irgendwelche Daten hängen. Siehe MSDN: Lokaler Threadspeicher).

Warum der ganze Zirkus?

Wenn ein Client einen Service A aufruft und dieser einen anderen Service B aufruft, passiert der Aufruf von Service B nicht im Benutzerkontext des Aufrufers von Service A (also dem Client-Benutzer), sondern mit dem Benutzerkonto unter dem der Thread von Service A läuft. Und das ist das Dienstkonto des Applikationsservers. Service B würde z.B. statt 'DOMÄNE1\MaxMustermann' plötzlich 'DOMÄNE1\AppServerKonto' als aufrufender Benutzer gemeldet bekommen. Das ist aber doof, da die Rollenprüfung eigentlich auf den ursprünglichen Aurufer der Aufrufkette erfolgen soll.
Der Aufrufkontext löst dieses Problem, da die Daten im Threadspeicher abgelegt udn dort auch wieder herausgenommen werden. Daten im CallContext werden also über die KOMPLETTE AUFRUFKETTE durchgereicht, egal wie tief die Kette verschachtelt ist oder über wie viele Server kommuniziert wird.
Statt die Identität des Aufrufers direkt zu prüfen, wird die Identität der Sitzung geprüft, deren Sitzungsschlüssel im Aufrufkontext abgelegt ist.

Wenn der Client keine Windows.Forms-Anwendung sondern eine ASP.NET-Webanwendung ist, muss man den Aufrufkontext zusätzlich noch mit dem ASP.NET-Sitzungsstatus synchronisieren (ApplicationServer.LoadContextDataFromWebSessionState und ApplicationServer.SaveContextDataInWebSessionState). Bei einer Windows.Forms-Anwendung braucht man das nicht, da der GUI-Thread die ganze Zeit am Leben bleibt und die Daten in seinem Threadspeicher nicht vergisst.

Wenn Du einen Dienstaufruf aus einem manuell erzeugten Thread machst, wirst Du standardmäßig eine Ausnahme bekommen, in der sich der Server beschwert, dass Du nicht angemeldet bist. Neue Thread heißt auch neuer - und damit leerer -Threadspeicher. Also Logon aufrufen oder Daten im Aufrufkontext in den Threadspeicher der zusätzlichen Threads replizieren.
Bisher hat das scheinbar noch keiner gemacht. Da wir das Thema aber gerade sowieso haben, wollte ich es gleich erwähnt haben.

Ursache Deines Problems im Speziellen: Du hast versucht eine Rollenprüfung durchzuführen, ohne den Benutzer vorher mit Logon anzumelden.

Dieses Verhalten ist so gewollt. Ohne Login geht gar nix. Das ist ein Sicherheitsaspekt. 8)
Ich habe sehr auf Sicherheit geachtet. Mir ist es bisher nicht gelungen, meinen eigenen Sicherheitsdienst auszutricksen.

Es macht ja auch keinen Sinn, die Rolle des Applikationsserver-Dienstkontos zu prüfen. Es soll ja geprüft werden, ob ein Client-Benutzer eine bestimmte Dienstmethode aufrufen darf oder nicht.

20.04.2010 - 18:55 Uhr

Hallo Wyatt,

das ist ganz einfach:

Den Kanal konfiguriere ich in der App.config (da sich Port etc. ja ohne Neukompilierung ändern lassen sollen) und den Sicherheitsdienst manuell über Direct Remoting. Du findest Die Codezeile in der Core.cs:


// Sicherheitsdienst veröffentlichen
RemotingServices.Marshal(SecurityService.Instance, "Rainbird.AppServer.API.ISecurityService");

Mehr ist nicht nötig. Marshal veröffentlicht die bestehende Singleton-Instanz unter dem angegebenen URI. Wenn Du keinen URI bei Marshal angibst, erzeugt Remoting einen zufälligen (den Du dann aber nicht weisst). Also entweder RegisterWellknownServiceType ODER Marshal, aber nicht beides zusammen!

Der Unterschied ist, dass Marshal eine bereits erzeugte Instanz veröffentlicht und RegisterWellkownServiceType nur einen Typ (Remoting kümmert sich dann um die Erzeugung einer Instanz). Ich wollte in diesem Fall die Erzeugung der Sicherheitsdienst-Instanz komplett selbst in der Hand haben, darum habe ich diesen Weg gewählt.

Eine normale Singleton-Veröffentlichung hätte es auch getan. Das war einfach nur Kontrollzwang.

Remoting hat für die meisten Probleme ganz einfache und gute Lösungen (im Gegensatz zu WCF).

08.04.2010 - 08:16 Uhr

Hallo BeZi,

meinst Du mit Gruppenkalender einen Kalender in einem öffentlichen Ordner?
Oder meinst Du die Outlook-Funktion, eine Übersicht der Termine verschiedener Benutzer anzuzeigen?

Letzteres wird - soweit mir bekannt - von Outlook aus den einzelnen Benutzer-Kalendern zusammengetragen.

29.03.2010 - 08:11 Uhr

Hallo Turtle,

na über den Indexer.


User user=myuserlist[0];

Das ist jetzt nicht Dein Ernst? Du entwickelst verteilte Anwendungen mit WCF und weißt nicht, wie eine popelige Auflistung in C# angesprochen wird?
Oder habe ich Dich da falsch verstanden?

25.03.2010 - 07:34 Uhr

Hallo BeZi,

auf die Termine eines Benutzers kannst Du nur zugreifen, wenn dieser seinen Kalender explizit freigegeben hat.

Du kannst aber abfragen, ob er in einem bestimmten Zeitraum schon Termine hat (Frei/Gebucht-Zeiten abfragen). Das geht über die Exchange 2007 WebService-API: MSDN: Getting User Availability

Ansonsten kannst Du auch beliebige Exchange-Objekte über die Webservice-API abrufen: MSDN: Finding Items

24.03.2010 - 00:02 Uhr

Was spricht denn gegen die Benutzung von NamedPipes?

Gegen Named Pipes spricht nichts, nur gegen die Implementierung zu Fuss. Der Remoting IpcChannel verwendet auch Named Pipes. Du musst Dich dabei aber nicht um Streams und dergleichen selber kümmern. das macht dann die Remoting Infrastruktur.

Hier ein Beispiel: Using Remoting IPC Channel

Das Ganze hat noch einen weiteren Vorteil. Mit ein paar Handgriffen kannst Du bei Remoting den IpcChannel durch einen TcpChannel austauschen (oder zusätzlich registrieren). Dann kannst Du die einzelnen Programmteile auf verschiedene Computer im Netzwerk verteilen. Am Code Deiner Geschäftslogik ändert sich nichts.

Es kann natürlich trotzdem Gründe geben, das alles von Hand zu bauen, aber man sollte wenigstens die Möglichkeiten kennen.

23.03.2010 - 08:15 Uhr

Hallo MuhammedC#,

hier findest Du eine Anleitung für Windows 2003 und Windows Vista/Windows7:
MSDN: Konfigurieren von HTTP und HTTPS

23.03.2010 - 08:11 Uhr

Hallo GenesisCL,

warum programmierst Du die Pipes zu Fuß an? Wäre es nicht wesentlich einfacher auf eine fertige und bewährte Implementierung wie Remoting (IpcChannel) oder WCF (NetNamedPipesBinding) zurückzugreifen?

21.03.2010 - 12:08 Uhr

Hallo Wyatt,

hier noch eine Antwort zu den konkreten technischen Details Deiner Frage am Ende (SOAP):

Wie sieht es denn eigentlich bei der Übertragung von Geschäftsobjekten über einen Webservice aus? Lassen sich DataTable oder DataSet über jeden Webservice übertragen.

DataSets und DataTables können sowohl mit ASP.NET-Webdiensten als auch mit WCF verwendet werden. Allerdings ist das serialisierte XML von DataSets und DataTables nicht für Interoperabilität entworfen worden. In Verbindung mit anderen Plattformen (z.B. Java) kann sich das als holprige Stolperfalle erweisen. Dann sollte man manuell Datenobjekte erstellen (vorzugsweise MessageContracts mit WCF, da man da sehr genau steuern kann, wie die erzeugten SOAP-Nachrichten aussehen sollen). Wenn Du in einer reinen .NET-Umgebung arbeitest, kannst Du DataSets/DataTables aber ohne Probleme verwenden. Ausnahme ist hier Silverlight! Silverlight unterstützt keine DataSets/DataTables.

Über .Net Remoting dürfte es möglich sein. Aber wie steht es da bspw. mit SOAP? Selbst wenn .Net die Serialiserung dieser Typen unterstützt, so hat der Client doch das Problem diese auf seiner Seite wieder zu deserialisieren und sich zusätzlich mit allen Spaltennamen herumschalgen zu müssen. Wäre es hier nicht besser konkrete Typen übertragen zu können. Also "Lieferant", "Artikel"...?

Für diesen Fall gibt es typisierte DataSets. Das sind konkrete Typen. Es gibt aber Szenarien (Suche, Listen, Berichte), bei denen die Spalten nicht fest definiert sind, sondern z.B. vom Benutzer zur Laufzeit festgelegt werden können. Dann nützen konkrete Objekte nichts, da ja zur Entwurfszeit noch nichts konkretes feststeht. Die Alternativen zu DataTables sind dann XML, Konstrukte wie List<Dictionary<string,object>> oder eigene Klassen (was aber am Ende auf eine ähnliche Struktur wie DataTable hinausläuft).

17.03.2010 - 06:43 Uhr

Hallo Frisch12,

ich würde die Remoting-Kommunikation in separaten Assemblies kapseln und auslagern. Diese Assemblies dann z.B. mit monodevelop entwickeln. Dann hast Du korrekte mono-Assemblies. Diese kannst Du dann wieder in Deinem VS-Projekt einbinden.

Ist etwas mehr Aufwand, sollte so aber funktionieren.

17.03.2010 - 06:35 Uhr

Die Items-Eigenschaft ist VB spezifisch. In C# übernehmen Indexer diese Funktion.

VB.NET:

Dim subfolder As MAPIFolder = folder.Folders.Item(1)

C#

MAPIFolder subfolder = folder.Folders[1];

Je nach verwendeter PIA-Version, kann der Aufruf in C# auch so aussehen:


int index=1;
MAPIFolder subfolder = folder.Folders.get_Item(ref index);

17.03.2010 - 06:30 Uhr

Sprichst du eine .dll an?){gray}

Wenn zwei Programme (klassisch Client & Server) miteinander kommunizieren, brauchen sie gemeinsame Datenstrukturen und Schnittstellen. Diese lassen sich unter dem Begriff Kontrakt (Vertrag, engl. contract) zusammenfassen. Eine Contract Assembly ist eine DLL, die diese Kontrakt-Typen enthält. Geschäftlogik sollte möglichst nicht in eine Contract Assembly gepackt werden. Alle Programme/Programmteile, die miteinander kommunizieren müssen, brauchen einen Verweis auf die gemeinsame Contract Assembly.

Wenn also der Server eine Funktion hat um ein Login zu überprüfen (auf einer Datenbank, die nur lokal auf dem Server läuft), kann ich also die Methode ansich dem Client übergeben, und der kommuniziert dann mittels der Servermethode mit der Datenbank?

So ist es. Nennt sich Trusted Server Prinzip. Nur der Applikationsserver hat Zugriff auf die Datenbank.
Aber könntest du mir noch die Frage zum Remoting beantworten? 😃Gerne. Sobald ich die Frage kenne. Sonst muss ich mit 42 antworten.

16.03.2010 - 07:33 Uhr

Hallo BeZi,

welche Version von Exchange Server wird eingesetzt?
Das ist wichtig, da der Zugriff auf Exchange 2000/2003 komplett anders funktioniert, als auf 2007+.

MSDN: Exchange Server Developer Refernce

16.03.2010 - 07:29 Uhr

Hallo Rimm,

das geht über das Word Objektmodell: MSDN: Word 2007 Developer Reference

Weitere Informationen zum Thema Office Integration findest Du hier: [FAQ] Office (Word, Excel, Outlook, ...) in eigenen Anwendungen verwenden

16.03.2010 - 07:20 Uhr

Hallo oli001,

bitte benutze den Excel Makro-Recorder.
[Erledigt] NamedRange.RowHeight Property

16.03.2010 - 07:18 Uhr

Hallo satisfact,

folgende Sammlung von Beispielen beschreibt auch den Zugriff auf Öffentliche Ordner: Programmierbeispiele, die das Verweisen auf Elemente und Ordner in Outlook mithilfe von Visual C# .NET illustrieren

16.03.2010 - 07:13 Uhr

Hallo Terrakotta007,

welche Outlook-Version benutzt Du?
Verwendest Du klassische Outlook-Formulare oder Outlook Form Regions (nur Outlook 2007+)?

Klassische Outlook-Formulare musst Du mit VBScript programmieren.
MSDN: Using VBScript
MSDN: Create custom Forms by using VBScript [Outlook 2003]

Ansonsten kannst Du nur auf Properties zugreifen und musst diese entsprechend an die Controls binden.

Mit Outlook 2007 geht das alles direkt mit Windows.Forms .NET Controls. MSDN: Creating Outlook Form Regions

Wenn es eine größere Applikation werden soll, würde ich die Migration auf Outlook 2007/2010 sehr empfehlen (falls derzeit noch eine ältere Outlook-Version im Einsatz ist).

16.03.2010 - 07:01 Uhr

Hallo Joey86,

das wundert mich nicht. Die Office CommandBar unterstützt keine CheckBoxen. Du wirst in keinem Office Programm Checkboxen auf der Symbolleiste finden. Welche Controls unterstützt werden, kann man an der MsoControlType-Enumeration sehen: MSDN: MsoControlType-Enumeration

Wie Du siehst: Keine CheckBoxen.

Du wirst Dir was anderes überlegen müssen.

16.03.2010 - 06:55 Uhr

Hallo ai0508,

mit dem Tool ProcessMonitor (TechNet) kannst Du alle Registry-Änderungen während einer Installation protokollieren. Im Protokoll findest Du dann den benötigten Registry-Schlüssel. Am besten nur die Office-Programmierunterstützung einzeln deinstallieren/installieren, da sonst das Protokoll unübersichtlich groß wird. Über die Filter-Funktion kannst Du die Ergebnismenge gut eingrenzen (z.B. nur Schreibzugriffe).

16.03.2010 - 06:34 Uhr

Hallo Regenwurm,

so funktioniert das nicht. Der BinaryFormatter überträgt nicht nur Klassenname und Namespace, sondern auch den voll qualifizierten Assemblynamen (inkl. Version). Es muss also GENAU der SELBE Typ sein. Es genügt nicht, dass Code und Name gleich sind.

Die Lösung des Problems ist aber ganz einfach. Du packst alle Typen, die zum Datenaustausch zwischen Client und Server verwendet werden in eine separate Assembly (Contract Assembly). Diese kopierst Du auf den Server und auf den Client. So kennen Client und Server beide die gleichen Typen und es klappt mit der Serialisierung.

Warum schreibst Du die Kommunikation eigentlich zu Fuß mit Sockets? Das würde mit .NET Remoting bestimmt viel einfacher gehen.

Hier ein Beispiel für den schnellen Einstieg in Remoting: Remoting-Helfer

15.03.2010 - 17:56 Uhr

Hallo Yheeky,

generell geht das ganz einfach. Hier findest Du das nötige Grundlagenwissen dazu:
MSDN: Integration in Windows-Sicherheit Teil 1
MSDN: Integration in Windows-Sicherheit Teil 2
MSDN: Integration in Windows-Sicherheit Teil 3

Hier noch ein How-To für Windows-Sicherheit mit ASP.NET: MSDN: Using Windows Authentication with ASP.NET

Achtung!
Der Webserver ++muss ++Mitglied in der AD-Domäne sein, damit das alles funktioniert! Bei gehostetem Webspace ist das meistens nicht möglich!

Eine Beispielapplikation, die Windows-Sicherheit verwendet (Single Sign On im LAN) findest Du hier (allerdings kein ASP.NET): .NET Applikationsserver

11.03.2010 - 00:59 Uhr

WCF ist eine von Haus aus interoperable Technologie, daran lässt sich nichts deuten. Das wird schon daran deutlich, dass Serialisierung und DataContracts zwei paar Stiefel sind. Nicht alles was serialisierbar ist eignet sich für DataContracts.

Da gibt es auch noch den NetDataContractSerializer. Den muss man zwar manuell aktivieren, dafür schaufelt er aber .NET Objekte ++mit ++properitären .NET Typinformationen durch die Gegend.

Hier noch eine genaue Aufstellung, welche Typen der normale DataContractSerializer von WCF unterstützt: Vom Datenvertragsserialisierer unterstützte Typen

Es ist ++leider ++so, dass WCF den SOA-angehauchten Weg quasi vorgibt. Für Azure mag das okay sein, für geschlossene Systeme ist es eine Quälerei. Remoting oder Sockets sind für solche Systeme deshalb immer noch eine Alternative. Welchen Mehrwert bringt WCF noch für ein Projekt, bei dem man nicht interoperabel sein muss und sich guten Gewissens auf binäre TCP-Kommunikation festlegen kann?

10.03.2010 - 07:51 Uhr

Hallo serial,

das klappt ganz so einfach nicht. Du kannst Remoting-Events nicht einfach wie lokale Events implementieren. Da gibt es eine Menge Stolpersteine.

Schau Dir mal die folgende Implementierung an: NotificationService als Erweiterung zu Rainbirds ApplikationServer Beispiel

So funktionierts.

Es ist sehr zu Empfehlen einen zentralen Benachrichtigungsdienst für die eigene Remoting-Anwendung zu schreiben, statt in jedes einzelne Remoting-Objekts manuell Events einzubauen.

Klassisches objektorientiertes Vorgehen (Objekt hat Methoden, Eigenschaften und Ereignisse) ist bei verteilten Applikationen definitiv fehl am Platze. Statuslos sollte man seine Remoting-Objekte halten!

10.03.2010 - 07:42 Uhr

Bitte keine .NET-spezifischen Klassen in DataContracts.

Wenn Interoperabilität für das Projekt eine Rolle spielt, hast Du Recht. In einer reinen .NET zu .NET Kommunikation sind .NET spezifische Typen völlig in Ordnung.

Pauschalaussagen halte ich grundsätzlich für gefährlich.

08.03.2010 - 07:29 Uhr

"Auf den Typ System.Runtime.Remoting.ObjRef kann aufgrund von
Sicherheitseinschränkungen nicht zugegriffen werden".

Deine Client-Klasse ist falsch implementiert! Entweder von MarshalByRefObj erben ODER als Serializable markieren. NIEMALS beides. Außerdem hast Du die Objektlebenszeiten (Lease) nicht geregelt. Vermutlich stehen die Objekte deshalb plötzlich nicht mehr zur Verfügung, weil ihre Lease abgelaufen ist.

Den Ansatz den Du gewählt hast, halte ich - unabhängig von diesem Fehler - nicht für sehr glücklich. Du drehst den Spieß um und machst Deine Clients zu Servern, indem sie dem Server das MarshalByRefObj abgeleitete Objekt "Client" übergeben. Der Server steuert dann die Clients fern. Das ist viel zu statusbehaftet. Du solltest wenn irgend möglich statuslos programmieren. Der Server bietet bestimmte Funktionalität an, die von den Clients konsumiert wird. So sollte es ablaufen. Callbacks, Events etc. sollte man nur dann einsetzen, wenn es unbedingt sein muss.

Eine Sitzungsverwaltung lässt sich viel einfacher bauen. Der Client ruft Logon auf und übergibt seine Anmeldedaten. Der Server prüft diese und erstellt einen Sitzungsschlüssel (z.B. eine GUID). Diesen Sitzungsschlüssel gibt er an den Client zurück. Der Client muss nun den Sitzungsschlüssel bei jedem entfernten Methodenaufruf mitgeben, um seine korrekte Anmeldung nachzuweisen. Der Server muss auf diese Art keine entfernten Objekte der Clients pflegen. Deine Anwendung wird so wesentlich schneller und robuster.
Wenn Du den Sitzungsschlüssel nicht bei jeder Methode als Parameter übergeben willst, kannst Du ihn auch im CallContext ablegen. Dann wird er automatisch zum Server übertragen.

Eine Remoting-Beispielanwendung mit Sitzungsverwaltung findest Du hier: .NET Applikationsserver

02.03.2010 - 07:03 Uhr

Hallo elbak,

nein, sperren kannst Du das nicht. Aber Du könntest die Anlagen erst dann einfügen, wenn der Benutzer auf Senden klickt. Dazu musst Du den Standard Senden-Knopf verstecken und einen eigenen Senden-Knopf einfügen (selbiges natürlich auch im Menü).

01.03.2010 - 18:12 Uhr

Hallo seatfahrer,

Du musst zuerst im Browser auf "about:blank" navigieren und dann alle Excel-Objekte aufräumen. Wenn der Browser Excel im Hintergrund offen lässt, müsste das Dokument ja noch in der ROT stehen.

27.02.2010 - 10:07 Uhr

Hallo pollito,

das Control wird automatisch mit dem kostenfreien Adobe Reader installiert. Wenn immer PDF-Dateien innerhalb des Internet Explorers angezeigt werden, kommt dabei dieses ActiveX-Control zum Einsatz. Der Adobe Reader - und damit auch dessen ActiveX-Control - kann gebührenfrei genutzt werden. Details dazu kannst Du dem Lizenzvertrag des Adobe Readers entnehmen.

Kostenpflichtig ist Adobe Acrobat. Mit Acrobat kann man PDFs erstellen. Der Adobe Reader kann nur PDFs anzeigen. Wenn Du PDFs mit C# erstellen willst, gibt es eine kostenfreie Alternative zu Adobe Acrobat: iTextSharp

Du kannst ein neues Visual Studio Projekt erstellen, den COM-Verweis für das ActiveX-Control einfügen und Dir die Methoden ganz normal im Visual Studio Objektbrowser ansehen.

Ansonsten gibt es das Adobe Reader Developer Center: http://www.adobe.com/devnet/reader/

Danke für die Blumen.

26.02.2010 - 19:57 Uhr

Hallo Bastor,

Du versuchst mit Deinem Webservice so zu prorammieren, wie Du es sonst auch lokal tust. Das klappt so nicht. Webservices sind statuslos. Die Webservice-Instanz wird vom Webserver pro Client-Aufruf erzeugt und anschießend sofort wieder entsorgt.

Da ist nix drin, mit Schleifen über Collections vom Client aus. Man ruft keinen Webservice 1000x in einer Schleife auf! Ein Webservice-Aufruf geht übers Netzwerk und ist ungelogen tausende Male langsamer als ein lokaler Methodenaufruf. Außerdem müssen alle Parameter und Rückgabewerte serialisiert, versendet und wieder deserialisiert werden. Am anderen Ende der Leitung kommen dann "neue" Objekte raus.

Man packt alle 1000 Objekte in eine Liste und schickt die Liste in einem Rutsch zum Webservice.

Die Frage ist, ob Webservices das ideale Kommunikationsmittel für Dein Projekt sind. Wenn Deine Anwendung übers Internet kommuniziert, wird Dir bei .NET 2.0 nicht viel anderes übrig bleiben, als Webservices zu verwenden.
Wenn Deine Anwendung aber nur im LAN läuft, dann gibt es etwas viel Besseres. .NET Remoting lautet das Zauberwort. Remoting ist einfacher, schneller und leichtgewichtiger als Webservices. Dafür nicht interoperabel, also nur für Kommunikation von .NET zu .NET. Wenn Du mit dieser Einschränkung leben kannst solltest Du mit Remoting viel besser klar kommen, als mit Webservices.

Hier findest Du weitere Informationen zu .NET Remoting: .NET Remoting (MSDN)

25.02.2010 - 08:14 Uhr

Hallo Stipo,

wenn die Haupt-Geschäftslogik der Anwendung (Middle Tier) auf einem anderen Computer (Applikationsserver) läuft, ist der EF Kontext im Client nicht verfügbar. Der Client muss entfernte Dienste/Komponenten auf dem Applikationsserver konsumieren, um Daten abzufragen und wieder speichern zu können.

Für die EF-Entities heißt das, dass sie vom Kontext "detached" werden müssen. Während ein Objekt detached ist, gibt es kein Change Tracking. Der EF Kontext bekommt die Änderungen nicht mit, da er auf einem anderen Computer lebt.
Natürlich kann man die Änderungen manuell "nachfahren". Dazu muss man aber erst sein eigens Change Tracking für den Client aufsetzen. Besonders performant ist das nachfahren der Änderungen auch nicht.

Mit .NET 4.0 soll sich mit Self Tracking Entities daran etwas ändern. Damit kommt das, was Objekt-Puristen an DataSets nicht mögen, durchs Hintertüchen in EF.

Dann nehme ich lieber gleich DataSets. Die sind von Anfang an für ein verteiltes Szenario (Tiers) entworfen.

Hier noch ein Link zum Thema: http://yellow-rainbird.de/blogs/rainbird/archive/2009/01/09/habe-sehnsucht-nach-dem-rowstate.aspx

24.02.2010 - 09:54 Uhr

Oder gibt es noch ne andere Möglichkeit um Excel in eine Anwendung einzubinden?

Wenn Du mit einbinden meinst, dass die Excel-Oberfläche quasi als "Control" auf einem eigenen Windows.Forms-Form liegt, dann ist der WebBrowser da schon das richtige Mittel.

Generell kannst Du Excel über sein COM-Objektmodell automatisieren. Du kannst so auch eine laufende Excel-Instanz abgreifen. Dazu musst Du den vollständigen Pfad der Excel-Datei wissen, die Du als Instanz über den Browser geöffnet hast. Excel trägt sich nämlich in die sog. Running Object Table ein.

Folgendes Snippet ermöglicht es Dir ganz einfach die ROT abzufragen und bestimmte Objekte abzugreifen: Laufende COM-Objekte abfragen

So kannst Du prüfen, ob eine Excel-Instanz der von Dir verwendeten Excel-Datei geöffnet ist, und diese manuell schließen.

24.02.2010 - 08:16 Uhr

Hallo sundawn,

was für Schichten meinst Du? Layers oder Tiers?

Unterschied:

Layers

Schichten sind in unterschiedlichen Klassen (und ggf. auch in verschiedenen Assemblies) implementiert, aber alle Schichten laufen in einem OS-Prozess!

Tiers

Schichten laufen nicht im selben Prozess (bzw. der selben AppDomain). Die Mittelschicht könnte z.B. auf einem Applikations- oder Webserver liegen.

Für Layers is EF okay, für Tiers denkbar ungeeignet. Darum meine Frage.

24.02.2010 - 08:09 Uhr

(Direkte Exchange-Anprogrammierung NICHT wünschenswert)

Warum nicht?

Die Konstruktion mit dem Outlook-Add-In macht auf mich keinen vertrauenserweckenden Eindruck.
Daten-Synchronisierung macht man von Server zu Server und nicht über einen GUI-Client für Endanwender.

Welche Exchange Server Version hast Du denn vorliegen?

24.02.2010 - 08:04 Uhr

Hallo seatfahrer,

navigiere zu "about:blank" und prüfe dann mal, ob der Excel-Prozess geschlossen wird.

19.02.2010 - 08:12 Uhr

Natürlich kannst Du auch DataContracts verwenden. Allerdings hast Du weit weniger Einflußmöglichkeiten (z.B. SOAP-Header, Verhalten bei Weiterleitungen, usw.). Ich habe dieses Buch nicht gelesen, aber kann es sein, dass der Autor nur in einem bestimmten Zusammenhang davon abrät?

DataContracts sind auch völlig in Ordnung, wenn Du damit auskommst.

Was die Singleton-Implementierung der Logikklassen angeht, ist das natürlich zunächst kein Problem. Es kann aber zum Problem werden, wenn Du Deine Applikation einmal in einem Cluster betreiben willst. Dann sind zustandsbehaftete Instanzen, die im Hauptspeicher eines einzelnen Servers leben, tödlich. Wenn ein Load Balancer z.B. die Client-Anfragen auf die einzelnen Konoten (Server) im Cluster verteilt, ist nicht garantiert dass alle Anfragen von Client XY vom selben Server verarbeitet werden.

Falls Du den Betrieb in einem Cluster langfristig ausschließen kannst, steht Deinen Singletons nichts im Wege. Es ist nur wichtig sich am Anfang des Projekts mit diesen Fragen zu beschäftigen. Sonst ärgert man sich hinterher vielleicht, dass man zu kurzfristig gedacht hat.

Noch ein Frage: Userverwaltung als Singleton leuchtet mir ein, aber Logging? Warum Logging als Singleton?

18.02.2010 - 09:42 Uhr

Hallo LuckStrike,

Ich schließe mich meinem Vorredner an!
Deine Logikklassen sollten ++nicht ++direkt als Service-Implementierung verwendet werden. Du solltest dieWCF-Services separat schreiben. Die WCF-Services rufen dann die eigentliche Funktionalität auf den Logikklassen auf. So können die Logikklassen sogar bis zu einem gewissen Grad zustandsbehaftet bleiben. Wichtig ist, dass die WCF-Services zustandslos sind. Vorzugsweise sollte Du die WCF-Services per Call und nicht als Singleton instanzieren.
Andernfalls verbaust Du Dir die Möglichkeit das Ganze einfach in einem Windows-Cluster laufen zu lassen (z.B. einfaches NLB-Cluster auf TCp/IP-Ebene).

So könnte z.B. eine WCF-Serviceoperation aussehen (fiktiver Code):


public GetAddressResponse GetAddress(GetAddressRequest request)
{
    // Datenbank-Verbindung aus Server-Konfiguration laden
    string dbConnection=ServerConfigHelper.GetSetting("DBConnection");

    // Kundenstamm-Geschäftslogik-Instanz erzeugen
    CustomerManager manager=new CustomerManager(dbConnection)

    // Kundenadresse abrufen
    Address address=manager.GetAddress(request.AddressID);

    // Antwortnachricht erzeugen
    GetAddressResponse response=new GetAddressResponse();

    // Adresse in Antwortnachricht einpacken
    response.Address=address;

    // Antwortnachricht an den Aufrufer zurückschicken
    return response;
}

So müsstest Du Deine Logikklassen vermutlich nicht großartig ändern. WCF wird nur als Kommunikations-Ebene eingezogen. Der hier vorgestellte Ansatz ist nachrichtenorientiert. Dienstoperation haben nur einen Parameter, vom Typ eines WCF-MessageContract (oder DataContract). Das ist die Anfrage-Nachricht. Der Client packt in diese Nachricht alle Details seiner Anfrage an den Dienst. Der Dienst sendet die Antwort wiederum als Nachrichten-Objekt. Alle Details der Antwort sind Eigenschaften der Antwortnachricht.

Selbst wenn neue Details zu einer Nachricht hinzukommen (z.B. soll man die Adresse auch über die Kundennummer abfragen können). Ändernt sich die Dienst-Schnittstelle nicht. Nur die entsprechende Nachrichtenklasse bekommt eine zusätzliche Property. Über diverse Attribute kann man steuern, wie sich WCF verhalten soll, wenn z.B. ein älterer Client eine Nachricht im "alten" Format (also ohen die neue Property) sendet.

Infos dazu findet Du hier:
MSDN: DataContract Versioning
MSDN: Using Message Contracts

Natürlich könnte man die AddressID statt über eine Anfragenachricht auch als int-Parameter übergeben. Aber der Einsatz von Nachrichtenklassen bildet die Natur von WCF im Code ab. Das erinnert alle Entwickler im Team auch ständig wieder daran, dass sie bei WCF langsame Aufrufe übers Netzwerk machen. Wenn sich das genauso anfühlt, wie ein lokaler Aufruf, dann neigen viele Entwickler dazu, auch so zu programmieren, als wäre es ein lokaler Aufruf.

17.02.2010 - 08:43 Uhr

Hallo Stipo,

Zu Frage 1: Das kannst Du pro einstellen. Folgender Artikel sollte da weiterhelfen WCF Instance Management (MSDN-Artikel)

Zu Frage 2: Probleme macht das generell nicht. Allerdings wird jede Client-Anfrage in einem separaten Thread verarbeitet. Du musst bei Singleton-Diensten deshalb threadsicher programmieren. Konstrukte wie lock, Monitor oder AutoResetEvent sind dabei Deine Freunde.

Zu Frage 3: In der Service Klasse sollte generell niemals die Geschäftslogik implementiert werden. Sonst verheiratest Du Deine Geschäftslogik mit dem Kommunikations-Framework. Das ist meistens eine schlechte Idee. Ein WCF-Server sollte wenn immer möglich statuslos sein und nur als entfernt aufrufbarer Wrapper der eigentlichen Geschäftslogik dienen.

Ich bin allgemein kein Freund von IoC-Containern, sondern favorisiere eher das Factory-Entwurfsmuster. Da kann ich selbst entscheiden, wann etwas passieren soll. Aber das ist Ansichtssache. Wenn Du unbedingt eine IoC-Implementierung haben musst, dann gehört die nicht in einen WCF-Service, sondern in die eigentliche Geschäftslogik, welche vom WCF-Service aufgerufen wird. Die Geschäftslogik liegt idealerweise auch in einer anderen Assembly, als der WCF-Dienst. Auch Kontrakte sollten in einer separaten Assembly liegen. Ob WCF-Kontrakte auch von der Geschäftslogik verwendet werden, sollte man sich gut überlegen, da die Kontrakte jede Menge kommunikationsspezifische Attribute enthalten. Die haben mit der Lösung des fachlichen Problems eigentlich nichts zu tun.

Gerade bei einer Internet-Anwendung ist es auch ein Sicherheitsfaktor, wenn über sparate Kontrakt-Klassen geregelt werden kann, was denn wirklich über den Äther geht.

Zu Frage 4: Für eine Internet-Anwendung hat Du im wesentlichen drei Möglichkeiten:
*Standrad-Authentifizierung mit User+Password im Klartext *SSL gestützte Authentifizierung mit Zertifikaten *Eigene Sicherheits-Infrastruktur für WCF schreiben bzw. STS Dienst wie z.B. Geneva einsetzen

Zu letzterem sollte Dir folgender Artikel weiterhelfen: Geneva Framework (MSDN Artikel)

Das ist aber eine recht komplexe Angelegenheit und scheint mir momentan nur für sehr große heterogene Enterprise-Projekte interessant zu sein.

11.02.2010 - 23:46 Uhr

Hallo HappyLi,

vermutlich haben die Benutzer, bei denen es knallt, keine NTFS-Leserechte auf die dynamisch geladenen Assembly-Dateien.

Impersonation sollte man tunlichst vermeiden. Man kann auch die Identität des Aufrufers feststellen und für die Authentifizierung und Authorisierung verwenden, ohne die Identität gleich für den Arbeitsthread zu übernehmen.

Das Problem ist hier vermutlich die Impersonation. Je nach Aufrufer wird der Code dann unter einem anderen Benutzer mit anderen Rechten ausgeführt. Das ist sehr anfällig für Berechtigungsprobleme. Es ist besser den Benutzer des IIS-App-Pools für die Ausführung zu verwenden.

Vor allem: Impersonation bei SharePoint??? Ist das überhaupt supported? Könnte ein Designfehler sein.

Ist das alles im LAN oder auch übers Internet zugänglich?

11.02.2010 - 23:39 Uhr

Hallo LuckyStrike,

damit ich Deine Frage sinnvoll beantworten kann, benötige ich ein paar Infos:

Was tun diese Logikklassen im groben?
Sind diese Logikklassen statuswahrend?
In welcher Art und Weise wurden diese Klassen im bisherigen 2 Tier Model eingesetzt?
Wie sehen die Kontrakte für die Kommunikation aus?

11.02.2010 - 22:06 Uhr

Hallo sebastian_1981,

Du kannst mit dem Excel Makro Recorder alles haarklein als VBA-Code aufzeichnen. Den musst Du dann nur noch 1:1 in C# übersetzen.

Ein kleine Hilfestellung dafür findest Du hier: VBA nach C# übersetzen

11.02.2010 - 22:01 Uhr

Hallo Bundy.NET,

ich kenne das Problem. Wenn Word die Add-ins lädt sind manchmal nicht alle Menüs fertig inizialisiert. Die Objekte sind zwar schon da, aber beim Zugriff knallt es dann unkontrolliert.

Eine Lösung habe ich dafür nicht, aber einen etwas dreckigen Workaround. Du fängst die Ausnahme ab, startest dann einen Timer, der 2 Sekunden wartet und lässt dann per Timer Deine Menü-Erweiterungslogik nochmal laufen. Um ganz sicher zu gehen (es könnte ja auf einem älteren PC laufen) kannst Du eine Schleife bauen, die z.B. maximal zehn Mal versucht, die Menüeinträge zu setzen und erst dann eine Fehler-MessageBox anzeigt.

Wichtig dabei ist, dass Du das asynchron tust, damit Word weiter "hochfahren" kann. Also entweder über Timer oder einen separaten Thread.

Du musst Dich dann auch darum kümmern, dass das Ganze sauber abgebrochen wird, wenn Word während der Menü-Erweiterung beendet wird.

Ich habe das in einem VSTO-AddIn mit einem zusätzlichen Thread gebaut und es läuft einwandfrei. Selbst auf einen stark frequentierten Terminal-Server.

11.02.2010 - 21:50 Uhr

Hallo Doltsche,

das muss nicht komplex werden. Schau Dir mal den Excel XML Writer von CarlosAg an: http://www.carlosag.net/Tools/ExcelXmlWriter/
Kostenlos versteht sich!

11.02.2010 - 21:34 Uhr

Hallo Doltsche,

beim Excel-Objektmodell wird an vielen Stellen nur System.Object zurückgegeben. Das liegt an dem Umstand, dass in der COM-Welt viel mit später Bindung gearbeitet wird.

In Visual Studio hast Du dann keine Intellisense für diese Rückgabewerte und musst sie erst manuell in den richtigen Typ casten. Wenn Du nicht weißt, in welchen Typ Du casten musst, solltest Du die Doku konsultieren.

Rows gibt glabe ich ein Objekt vom Typ Excel.Range zurück.

11.02.2010 - 21:29 Uhr

Plan B: Machs nicht mit COM-Automatisierung, sondern erzeuge per XmlWriter SpreadsheetML-Code. das geht ab Excel 2003.

Das dürfte um ein Vielfaches schneller laufen und ist unabhängig von der Excel-version.

Hier ist ein kleines Beispiel, wie sowas aussehen kann: Excel-Export ohne Excel (Snippet)

11.02.2010 - 21:24 Uhr

Hallo Doltsche,

hast Du schon mal versucht die Aktion mit dem Makro-Recorder aufzuzeichnen?

Der Excel Makro Recorder schreibt automatisch VBA-Code für alles was Du manuell in Excel tust, während der Makro-Recorder läuft.

In 99% der Fälle findet man so heraus, was man tun muss. Du musst den generierten VBA-Code dann nur noch in C# übersetzen.

10.02.2010 - 08:11 Uhr

Hallo ingemar,

Du hast das mit den Schichten nicht richtig verstanden. Die generierten Entities sind nicht die Datenzugriffsschicht, sondern nur Datenkontrakte. Die werden von allen Schichten gemeinsam genutzt.

Es ist auch nicht so: 1 Schicht <=> 1 Visual Studio-Projekt.

Dieses klassische Schichtenmodell, wie es in den Lehrbüchern steht, funktioniert nicht, wenn man es genauso umsetzt, wie es in den Lehrbüchern steht! Das Modell ist eher eine Richtlinie die Dir sagt:

Du solltest Datenzugriff, Geschäftslogik und Darstellungslogik nicht in einer Klasse zusammen wursteln.

Es müssen auch nicht zwingend 3 Schichten sein. Manchmal sind es nur 2. Manchmal vielleicht auch 7. Es kommt immer drauf an.