ja grundsätzlich schon. Das UserControl im anderen Prozess würde dann via CoreRemoting ferngesteuert.
Der ferngesteuerte Prozess (in dem das UserControl eigentlich lebt) wäre der Server, der andere Prozess der Client.
CoreRemoting kommuniziert standardmäßig über Websockets.
Das heißt, dass der Server-Prozess einen festen TCP-Port belegt.
Auf einem normalen Windows PC sollte das kein Problem sein.
Auf einer Remotedesktopserver (RDS) sieht das allerdings anders aus.
Da würden ja dann mehrere Instanzen der Prozesse laufen (1 pro User, der die Anwendung geöffnet hat). Jeder Instanz des Servers brauchte einen eigenen TCP-Port.
Auf einem RDS Server würde es deshalb nicht funktionieren.
Es sei denn, man implementiert einen CoreRemoting-Kommunikationskanal, der keine TCP-Ports braucht.
Also eine zusätzliche Implementierung für IServerChannel und IClientChannel schreiben. Z.B. mit dem Named Pipes-Protokoll.
Bei CoreRemoting bestimmt nicht die Abstammung einer Klasse, ob sie aus der Ferne aufrufbar ist.
Stattdessen werden Klassen serverseitig als Services registriert.
Einzige Voraussetzung dafür ist, dass sie eine Schnittstelle implementieren, welche in einer gemeinsamen Assembly definiert ist, welche sowohl dem Server als auch dem Client bekannt ist.
.NET Remoting ist leider nicht mehr in .NET Core bzw. .NET 5 enthalten.
Microsoft verweist auf gRPC und WebAPI als Alternative.
Wer eine größere Codebasis hat, die auf .NET Remoting aufgebaut ist, für den bedeutet das trotzdem große Teile der Applikation komplett neu zu schreiben,
wenn die Anwendung auf .NET 5 zum Laufen gebracht werden soll.
Für solche Migrationsszenarien und auch für alle, die vom Solgan "Embrace HTTP" nicht ganz so begeistert sind, möchte ich mit dem neuen Projekt CoreRemoting eine Alternative anbieten. CoreRemoting ist kein 1:1 .NET Remoting-Nachbau und auch vom Netzwerkprotokoll her nicht binär-kompatibel, aber die API ist so ähnlich, dass sich Client/Server-Anwendung mit geringem Aufwand migrieren lassen.
Da CoreRemoting mit moderner Technologie und nach modernen Entwurfsmustern gebaut ist, eignet es sich natürlich auch für neue Projekte und nicht nur für Migrationsszenarien. Allerdings nur in reinen .NET-Anwendungen. CoreRemoting ist für möglichst komfortable entfernte Methodenaufrufe von .NET zu .NET. Man kann damit keine REST-Server für Javascript-Clients bauen. Wer das möchte, sollte lieber WebAPI verwenden. In Blazor Server-Anwendungen funktioniert CoreRemoting aber auch (falls man doch einmal einen Webclient braucht).
CoreRemoting wird als .NET Standard 2.0 Assembly kompiliert und lässt sich deshalb sowohl in .NET Framework 4.x als auch in .NET Core / .NET 5 Umgebungen gleichermaßen nutzen. Es läuft auf jeden Fall unter Windows und Linux. Mac sollte auch gehen, aber da ich selbst keinen Mac habe, konnte ich es da leider noch nicht testen.
Die Netzwerkkommunikation läuft über Websockets.
Für die nötige Sicherheit der Netzwerkaufrufe sorgt die integrierte Verschlüsselung und Nachrichtensignierung mit RSA und AES.
Eine Authentifizierungsschrittstelle ist ebenfalls eingebaut.
Für Authentifizierung mit Benutzername und Passwort gegen lokale Betriebssystembenutzer (Windows / Linux wird automatisch erkannt) gibt es bereits einen fertigen Authentifizierungsanbieter: https://www.nuget.org/packages/CoreRemoting.Authentication.GenericOsAuthProvider/
Zur Serialisierung der Aufrufe kommt standardmäßig BSON (Binary JSON) zum Einsatz. Alternativ kann auch der klassische BinaryFormatter verwendet werden, um die größt mögliche Kompatibilität zum klassischen .NET Remoting zu erreichen.
Netzwerktransportschicht, Serialisierer und Authentifizierung sind austauschbar (auch gegen Eigenkreationen).
Eine Dokumentation und einen Migrations-Guide für .NET Remoting bin ich gerade am schreiben: theRainbird/CoreRemoting
Die Migration kann man sich aber bereits jetzt in Form einer kleinen Beispielanwendung ansehen, welche im Original mit .NET Remoting implementiert ist und in einer zweiten Version auf CoreRemoting migriert wurde: theRainbird/CoreRemoting
Ich hoffe das Projekt ist für den einen oder anderen nützlich und beschert vielleicht einem altgedienten .NET Remoting Projekt ein zweites Leben unter .NET 5.
Falls ihr Bugs findet, meldet diese bitte über die GitHUb-Projektseite direkt: theRainbird/CoreRemoting
Viel Spaß mit CoreRemoting.
@Abt
Das Egoismus-Argument ist - finde ich - eine Killerphrase, weil man dagegen praktisch nichts mehr einwenden kann.
Das Egoismus-Argument kommt auch beim Klimaschutz. Ich muss mir z.B. von manchen anhören, dass ich egoistisch bin, weil ich Fleisch esse, ein Auto mit Benzin-Motor fahre und unnötigerweise einen Hund halte, der eine schlechte CO²-Bilanz hat. Ich würde mit meinem Egoismus den zukünftigen Generationen die Lebensgrundlage entziehen.
Beim Rassismus ist es genauso. Es wird unterstellt, dass Menschen, die nicht weiss sind, leiden müssen und benachteiligt werden, weil ich so egoistisch bin.
Wenn wir diese Debatte führen, kommen wir irgendwann an den Punkt, wo man verbindlich festlegen muss, was noch okay ist und ab wann es widerlich egoistisch wird. Und dann ist die Frage, wer darüber entscheidet.
Ich habe intensiv darüber nachgedacht, warum es auch mir persönlich so schwer fällt, eine Umbenennung von master/slave einfach so zu akzeptieren.
Für mich fühlt sich das irgendwie erzwungen an.
Ich weiss, dass es gut gemeint und eigentlich auch richtig ist, aber dieses "Gute" wird irgendwie von außen "verordnet".
Bei anderen Themen habe ich das selbe Gefühl. Z.B. beim Essen, also die Fleisch / kein Fleisch Geschichte, beim Gendering oder bei allem was mit dem Thema Klima zu tun hat. Dieses "Aufgezwungene" erzeugt bei mir den Widerstand (oder ist es Trotz?) dagegen.
Es fühlt sich für mich teilweise an, wie im Film "Demolition Man".
im DuplexChannel, der unter der Haube verwendet wird, ist leider kein Timeout definiert. Deshalb bietet auch das entsprechende ProtocolSetup keine Property dafür an.
Man müsste in die Zyan.Communication.Protocols.Tcp.DuplexChannel.Connection-Klasse einen einstellbaren Timeout einbauen. In dieser Klasse wird der Socket erzeugt, über den die Netzwerkkommunikation läuft. Die Socket-Klasse hat die Eigenschaften SendTimeout und ReceiveTimeout. Die müssen praktisch nur "durchgeschleift" werden.
Ich kann das gerne einbauen. Kann aber ein paar Tage dauern, bis ich dazu komme.
Nun zu Deinem Probelm. Sowohl Tasse als auch Schrank sind auf einem Zyan-Server veröffentlichte Remote-Komponenten. Du versuchst, einen clientseitigen Verweis auf die entfernte Komponente Tasse an die entfernte Komponente Schrank zu übergeben. Das wird so nicht unterstützt.
Zyan trennt strikt zwischen Client und Server. Der Server bietet Funktionalität an, der Client konsumiert sie. Wenn Client und Server Daten austauschen, dann muss dies über Typen gemacht werden, die serialisierbar sind (Also alle Typen, die ISerializable implementieren oder mit [Serializable] gekennzeichnet sind, und primitive Typen wie int, string, byte, etc.)
Es gibt deshalb grundsätzlich zwei Kategorien von Klassen:
Komponenten, die Funktionalität anbieten
Datenklassen, welche zum verseden von Daten übers Netzwerk eingesetzt werden
Damit Dein Beispiel funktioniert, müsste Tasse eine serialisierbare Datenklasse sein und NICHT als Remote-Komponente am Zyan-Server veröffentlicht werden. Es könnte z.B. eine Komponente "TassenFabrik" geben, welche Tassen produziert und die fertigen Tassen als Datenklassen zurückgibt. Die kann man dann mit proxySchrank.StelleRein(datenTasse) auch an den entfernten Schrank schicken.
klingt so, als würde ein asynchroner Callback vom Zyan Server versuchen auf GUI Objekte zuzugreifen. Zugriffe auf GUI Objekte dürfen nur im GUI Thread erfolgen. Du musst im Callback auf den GUI Thread umleiten. Unter Windows.Forms ist dafür Invoke/InvokeRequired das Stichwort. In WPF gibt es auch etwas Vergleichbares, weiss es nur gerade nicht auswendig.
Zyan 2.6 ist da!
Die neue Version bringt folgende Neuerungen mit:
Unterstützung für Android (in Verbindung mit Xamarin Mono for Android!); Bereits ab Zyan 2.5
Automatische Ermittlung laufender ZyanComponentHost-Instanzen im LAN (#2085)
- Findet automatisch und asynchron laufende Zyan-Server im LAN
- Findet Server anhand ihres Namens und/oder der Serverversion
- Verwendet UDP broadcasts (Unabhängig von Adresse und Port des Zyan-Servers)
- Discovery ist standardmäßig ausgeschaltet und muss bei Bedarf explizit aktiviert werden
- Wird durch Aufrufen von "zyanHost.EnableDiscovery()" eingeschaltet
- Clientseitig "ZyanConnection.DiscoverHosts(name, callback)" aufrufen, um lafende Server zu suchen
Registrieren und Deregistrieren von Ereignishandlern erfolgt nun standardmäßig nebenläufig (#2308):
- Altes Verhalten (blockiert den Thread, bis Ereignisregistrierung abgeschlossen ist) kann über "ZyanSettings.LegacyBlockingSubscriptions" wiederhergestellt werden
Unterstützung für Synchronisierungskontext für Callbacks und Ereignisse (#1827):
- Vereinfacht die Ereignisbehandlung in UI-Anwendungen (WPF, Windows.Forms)
- Ist standardmäßig ausgeschaltet und muss bei Bedarf explizit aktiviert werden
- Kann bei Proxyerstellung einzeln aktiviert werden
- ZyanCatalog aktiviert Synchronisierungskontext-Unterstützung standardmäßig für alle Proxies, die er erzeugt
Wiederverbinden von entfernten Ereignissen wird nun mittels schneller Stapelverarbeitung durchgeführt (statt durch Einzelaufrufe in einer Schleife) (#2309)
Gepufferte Übertragung von Dateien komplett als byte[]
Gepufferte Übetragung von Dateien in Segmenten als byte[]
Streaming mit herkömmlichen .NET Streams
Für große Dateien (mehrere Megabyte) sind Streams zu empfehlen. Für kleine Dateien gepufferte Übertragung als byte[].
Die Stream-Lösung hat allerdings den Nachteil, dass der Server statuswahrend implementiert sein muss. Außerdem steuert der Client dabei eine serverseitige Stream-Instanz fern, was dem Server ein Stück weit die Kontrolle entzieht. Wenn das nicht gewünscht ist, ist die gepufferte segmentierte Variante eine Alternative. Aber auch die verlangt statuswahrende Implementierung, da die einzelnen Segmente über mehrere Methodenaufrufe hinweg übertragen werden.
Schau Dir folgenden Testcode am, um zu verstehen, wie Streams mittels Zyan übertragen werden können: Streaming mit Zyan
Die Varianten mit byte[] werden so implementiert:
Datei mittels Stream in ein byte[] einlesen
byte[] ganz normal als Methodenparameter oder Property an den Server senden
Dateiname ebenfalls als Methodenparameter mitgeben
Serverseitig das byte[] in einen FileStream auf die Serverplatte schreiben, oder in eine DB, oder sonst wohin.
Bei der segmentierten Variante wird einfach nicht die komplette Datei auf einen Rutsch übertragen, sondern kleinere Batzen (auch Chunks genannt). So kann der Server bereits bei Erhalt des ersten Bytehaufenbatzen mit dem schreiben auf Platte beginnen (ganz ähnlich wie bei der Strwam-Lösung), was bei großen Dateien, wie z.B. Videos, ein großer Zeitvorteill ist.
Zitat von elTorito
Hab da was gelesen von NegotiateStream ist das der richtige Ansatz?
Nein, NegotiateStream würdest Du verwenden, wenn Du Dich auf Socketebene bewegst.
meine Antwort kommt zwar spät, aber vielleicht ist sie ja trotzdem noch für Dich nützlich. Ich habe eine Beispiel-Applikation geschrieben, wie man einzelne Clients mit Hilfe von Zyan benachrichtigen kann.
Du findest es im aktuellen Zyan Code Repository auf zyan.codeplex.com.
Es liet im Ordner examples und heißt Zyan.Examples.WhisperChat.
der Bug ist nun ab ChangeSet 27989 behoben. Ab Zyan Version 2.4 wurde das Event Handling standardmäßig auf asynchrone Verarbeitung umgestellt. Bis Zyan 2.3 wurden Ereignisse synchron verarbeitet und verhielten sich damit wie lokale Ereignisse. Im Enterprise-Umfeld ist das aber nicht die bevorzugte Methode. Das MiniChat Beispiel wurde aber mit der urspsprünglichen synchronen Ereignisverarbeitung entwickelt.
Bei Verwendung von Zyan 2.4 oder höher muss die synchrone Ereignisverarbeitung explizit eingeschaltet werden. Dies wurde im MiniChat Beispielcode einfach vergessen.
Die synchrone Verarbeitung muss serverseitig mit folgender Zeile eingeschaltet werden:
ZyanComponentHost.LegacyBlockingEvents = true;
Damit läuft das MiniChat Beispiel wieder einwandfrei.
ich konnte Dein Problem reproduzieren. Es handelt sich offensichtlich um einen Bug in Zyan 2.4. Ich habe den Bug im Issue Tracking System erfasst. Hier kannst Du den Status dieses Bugs verfolgen: http://zyan.codeplex.com/workitem/1852
Bitte entschuldige die Unannehmlichkeiten.
Danke dass Du das Problem gleich im Forum gemeldet hast.
das sind ganz spezifische Anforderungen. Die wird in dieser Zusammenstellung wohl außer Dir niemand genau so haben. Wenn Du eine fertige Library einsetzt, musst Du Dich an deren Funktionalität anpassen.
Wenn das nicht geht, wirst Du wohl selber einen passenden XSD Code Generator schreiben müssen, der genau das kann. Mit CodeDOM ist das reine Fleißarbeit.
Du schreibst ein Add-In für Excel. Warum verwendest Du nicht einfach die in Excel bereits vorhandenen Diagramm-Features?
Die kann man standardmäßig in Word als OLE-Objekt einfügen.
Wenn Du das selbst implementieren willst, wirst Du vermutlich Monate dafür brauchen. Du musst dazu einen eigenen COM-Server schreiben und dort entsprechende OLE-Schnittstellen implementieren. Wenn Du das nicht schon früher mit C++ gemacht hast, ist das unter Umständen harter Tobak.
Das lohnt sich nach meiner Einschätzung nicht, vor allem weil Office das ja alles schon kann. Warum etwas nachbauen, was schon da ist? Da Du es eh als Excel Add-In implementieren willst, ist Excel auf jeden Fall verfügbar. Was spricht dagegen, den Werkzeugkasten einzusetzen, den Excel fix und fertig mitbringt?
Diese Seite richtet sich zwar Hauptsächlich an Hersteller von Geräten, die dieses Protokoll implementieren möchten, aber enthält natürlich auch Informationen, die für den Client-Entwickler nützlich sind.
Zuerst möchte ich mich für die über 650 Downloads bei NuGet und über 3400 Downloads auf Codeplex seit der Veröffentlichung von Zyan bedanken.
Viele der Features, die Zyan inzwischen mitbringt, sind durch das rege Feedback der Community angeregt worden.
Ich hoffe, dass auch die neue Version 2.4 so regen Zuspruch findet.
Neben zahlreichen Bugfixes bietet Zyan 2.4 folgende neue Features:
Komprimierung des Datenverkehrs (besonders nützlich bei langsamen Intrnetverbindungen)
Verbesserungen beim Handling von verteilten Ereignissen
- Ereignisse für Single-Call- und Singleton-Komponenten verwenden nun die selbe Semantik
- Ereignisse werden serverseitig nun standardmäßig asynchron verarbeitet
- Alte synchrone Ereignisverarbeitung kann bei Bedarf über ZyanComponentHost.LegacyBlockingEvents eingeschaltet werden
- Registrierung und Deregistrierung von Ereignissen kann nun auch über Call-Interception abgefangen und im Verhalten dynamisch geändert werden
Verbesserungen bei der Clientverbindung (ZyanConnection)
- ZyanConnection.Reconnected-Ereignis benachrichtigt nun bei Verbindungswiederherstellung nach einem abgefangenen Abbruch der Socketverbindung
- Das zu verwendende Client-Protokoll wird nun automatisch anhand des angegebenen Verbindungs-URLs erkannt
Verbesserungen beim TCP-Duplex-Transportkanal
- Unterstützt nun explizite Bindung an eine bestimmte Netzwerkkarte auf mehrfach vernetzten Computern (bindTo Kanaleinstellung; Analog zum Standard-TCP-Transportkanal)
- Unterstützt nun Initiierung der Socketverbindung bei der Ersten Verbindung (einstellbar über ConnectDuringCreation Parameter)
Neuer Null-Transportkanal für Test- und Monitoringzwecke
mono liefert eine Runtime für Windows-Dienste unter Linux. Damit sollte es möglich sein, Deinen Server als Linux-Dämon im Hintergrund laufen zu lassen.
die einfachste Variante wären ganz herkömmlich Events. Wenn Du Zyan verwendest, kannst Du Events ganz intuitiv verwenden, genau so wie bei ein Click-Ereignis eines Buttons auf einem Windows-Formular.
Solche verteilten Ereignisse verhalten sich dabei genauso wie herkömmliche lokale Ereignisse. Die Abonnenten des Ereignisses werden nacheinander aufgerufen. Das ist aber nicht immer das, was man erreichen will. Manchmal möchte man, dass der Server alle registrierten Clients möglichst gleichzeitig informiert. Dann kann man statt Events mit Delegaten arbeiten. Ein einfacher serverseitiger Benachrichtigungsdienst mit Delegaten könnte z.B. so aussehen:
public class SomeServerComponent : ISomeServerComponent
{
private ConcurrentDictionary<Guid, Action<string>> _subscribers = new ConcurrentDictionary<Guid, Action<string>>();
public Guid Subscribe(Action<string> clientCallback)
{
if (clientCallback == null)
throw new ArgumentNullException("clientCallback");
Guid subscriptionID = Guid.NewGuid();
_subscribers.TryAdd(subscriptionID, clientCallback);
return subscriptionID;
}
public void Unsubscribe(Guid subscriptionID)
{
Action<string> clientCallback;
_subscribers.TryRemove(subscriptionID, out clientCallback);
}
public void NotifyClients(string message)
{
Parallel.ForEach(_subscribers.Values, callback =>
{
try
{
callback(message);
}
catch (SocketException)
{
//TODO: Ausnahme loggen
}
catch (RemotingException)
{
//TODO: Ausnahme loggen
}
});
}
}
Der Client kann sich ganz einfach für Benachrichtigungen registrieren.
das ist ganz einfach möglich. Allerdings wird das binden an eine bestimmte IP-Adresse nicht von allen Kanaltypen unterstützt.
Wenn Du keine Events oder Callbacks durch Client-Firewalls hindurch übertragen musst, kannst Du ein TcpCustomServerProtocolSetup wie folgt verwenden:
// TCP-Protokoll mit unverschlüsselter binärer Datenübetragung
var protocol = new TcpCustomServerProtocolSetup
(
8080, // TCP-Port
new BasicWindowsAuthProvider(), // Authentifizierung mit Windows-Benutzername und Passwort
true // Verschlüsselung eingeschaltet
);
// TCP-Kanal an bestimmte IP-Adresse binden
//TODO: Statt 192.168.0.10 die gewünschte eigene IP-Adresse einsetzen
protocol.ChannelSettings.Add("bindTo", "192.168.0.10");
protocol.ChannelSettings.Add("machineName", "192.168.0.10"); // Nur setzen, wenn Server eine öffentliche statische IP hat! Bei DynDNS etc. nicht setzen!
protocol.ChannelSettings.Add("useIpAddress", true); // Nur setzen, wenn Server eine öffentliche statische IP hat! Bei DynDNS etc. nicht setzen!
Über die ChannelSettings kann man direkt Einstellungen des Kommunikationskanals einstellen. Das TcpCustomServerProtocolSetup verwendet einen TcpChannel. Dessen Konfigurationseinstellungen kannst Du hier nachlesen: MSDN Libraray: Channel und Formatter Configuration
Gruß
Rainbird
ich glaube was Du suchst ist InterLinq.
Damit kannst Du Linq-Abfragen über WCF oder .NET Remoting serialisieren.
Als Autor der Kommunikationskomponente Zyan möchte ich an der Stelle auch ein bischen Eigenwerbung machen. Zyan serialisiert LINQ-Abfragen out-of-the-box.
Beispiel:
// Service-Schnittstelle
interface ISampleService
{
IEnumerable<T> GetList<T>() where T : class;
IQueryable<T> Query<T>() where T : class;
}
// Vom Client aus Verbindung zum Applikationsserver herstellen herstellen
using (var connection = new ZyanConnection("tcpex://localhost/myappserver"))
{
// Verbindung zum Service herstellen
var proxy = connection.CreateProxy<ISampleService>();
// LINQ-Abfrage direkt auf den Service machen
var query =
from c in proxy.Query<Customer>()
where c.BirthDate > DateTime.Today.AddYears(-18)
select c;
...
}
Die Customer-Klasse im Beispiel muss natürlich serialisierbar sein.
Wenn Du interoperabel sein musst, also Dein Client kein .NET Client (min. .NET Client Profile wird benötigt) ist, dann ist Zyan leider nicht geeignet. Zyan macht innerhalb der schönen .NET-Welt alles in Sachen RPC sehr einfach, kann aber nicht Kaffeebohnen, Telefonen, Toastern, etc. reden. Wenn Letztere auf Deiner Client-Liste stehen, nimm WCF und probier mal InterLinq aus.
jede Instanz Deiner Applikation ist ein eigener Windows-Prozess. ChannelServices.GetChannel kann nur Channels über den Namen abrufen, die im aktuellen Prozess existieren. Dein Ansatz, einen Channel, der in Prozess A erzeugt wurde und in dessen Speicherbereich existiert von Prozess B aus abrufen zu wollen, kann nicht funktionieren.
Du kannst das Probelm aber umgehen, indem Du in jeder Instanz Deiner Anwendung einen eindeutigen Kanalnamen verwendest. Häng einfach einen GUID hinter den Namen.
die Schnittstelle IVestasComponent hast Du doppelt. Einmal im Server und einmal im Client. Auch wenn sie beide gleich heißen, sind es zwei verschiedene Typen für die .NET Laufzeitumgebung.
Damit es funktioniert, musst Du die Schnittstelle in eine separate Assembly (also auch separates Visual Studio Projekt vom Typ Klassenbibliothek) auslagern. Diese Schnittstellen-Assembly musst Du ja im Server und im Client als Verweis einbinden. Deshalb wird eine solche Assembly auch Shared Assembly (also gemeinsame Assembly) genannt. Client und Server kommunizieren über eine gemeinsame Schnittstelle (nämlich IVestasComponent). Damit das funktioniert muss es auch wirklich die selbe Schnittstelle sein.
Werde nunmal schauen wie das mit der Berechtigung geht.
Du kannst Dir auch einen eigenen Authentifizierungsanbieter schreiben. In folgendem Diskussionsbeitrag findest Du ein einfaches Beispiel, wie das geht: http://zyan.codeplex.com/discussions/267636
ich vermute dass es daran liegt, dass die drei Windows 7 PCs nicht Teil der selben Active Directory-Domäne sind. Das n-Tier-Architekturbeispiel verwendet Windows-Authentifizierung über Kerberos oder alternativ auch das NTLM-Protokoll. Das funktioniert nur in einem Domänennetzwerk sinnvoll. Ohne einen zentralen Domänencontroller kann die Authentifizierung nicht richtig funktionieren, da jeder alleinstehende Windows 7-PC (also einer der nicht Mitglied einer Domäne ist) nur seine eigenen Benutzer und Gruppen kennt und auch nur diese authentifizieren kann.
Angenommen der Clientcomputer heißt PC1 und der Benutzer Peter, dann würde er sich mit PC1\Peter versuchen beim Server anzumelden. Wenn der Server PC2 heißt und auch einen Benutzer Peter hat, klappt zwar die Authentifiziere, wenn auf beiden PCs für den Benutzer Peter das selbe Passwort gesetzt ist, aber PC2 kann nicht prüfen, in welchen Gruppen PC1\Peter Mitglied ist. Für die Prüfung der Gruppenmitgliedschaft, müsste PC2 auf die SAM-Datenbank von PC1 zugreifen. Das geht aber in einem Peer-To-Peer Netzwerk nicht. Bei einem Domänennetzwerk sieht die Sache anders aus. Da gibt es eine zentrale SAM-Datenbank auf dem Domänencontroller. Alle Gruppenmitgliedschaftsprüfungen laufen dabei über den Domänencontroller.
Mein Beispiel wurde für den Einsatz in einem Domänennetzwerk geschrieben. Ohne Domänennetzwerk wird es nicht sinnvoll funktionieren. Es ist eben nur ein Beispiel.
Zyan bietet aber eine Lösung für das Problem an. Mit dem BasicWindowsAuthProvider Authentifizierungsanbieter kannst Du Windows-Authentifizierung haben, die nur serverseitig abläuft. Dabei spielt es keine Rolle, ob Client und Server in einer Domäne sind, oder nicht.
Auf folgende Doku-Seiten erfährst Du mehr über Zyan und welche Konfigurationsmöglichkeiten es gibt: Architektur einer Zyan-Anwendung ProtocolSetups
Wenn Dir Zyan nicht gefällt, kannst Du auch im Standard .NET Remoting eine eigene Authentifizierung implementieren. Dazu musst Du eigene Kanalsenken schreiben. Schau mal hier: MSDN: Sinks and Sink Chains
Das schreiben von Remoting-Kanalsenken an sich ist nicht schwer. Du brauchst aber tiefgreifende Kenntnisse über die .NET Remoting Infrastruktur.