Migrace z .NET Remoting do WCF
Tento článek popisuje, jak migrovat aplikaci, která používá vzdálené komunikace rozhraní .NET k používání technologie Windows Communication Foundation (WCF). Porovnává podobné koncepty mezi těmito produkty a popisuje, jak ve WCF provádět několik běžných scénářů vzdálené komunikace.
Vzdálené komunikace .NET je starší verze produktu, která je podporována pouze kvůli zpětné kompatibilitě. Není zabezpečená v prostředích se smíšeným vztahem důvěryhodnosti, protože nemůže udržovat samostatné úrovně důvěryhodnosti mezi klientem a serverem. Nikdy byste například neměli vystavit koncový bod vzdálené komunikace .NET na internetu nebo nedůvěryhodným klientům. Doporučujeme migrovat stávající aplikace vzdálené komunikace na novější a bezpečnější technologie. Pokud návrh aplikace používá pouze HTTP a je RESTful, doporučujeme ASP.NET webové rozhraní API. Další informace najdete v tématu ASP.NET webové rozhraní API. Pokud je aplikace založená na protokolu SOAP nebo vyžaduje jiné protokoly než HTTP, jako je TCP, doporučujeme WCF.
Porovnání vzdálené komunikace .NET se službou WCF
Tato část porovnává základní stavební bloky vzdálené komunikace .NET s jejich ekvivalenty WCF. Tyto stavební bloky použijeme později k vytvoření některých běžných scénářů klient-server ve WCF. Následující graf shrnuje hlavní podobnosti a rozdíly mezi vzdálené komunikace .NET a WCF.
Vzdálené komunikace pomocí rozhraní .NET | WCF | |
---|---|---|
Typ serveru | Podtřídy MarshalByRefObject |
Označit atributem [ServiceContract] |
Operace služby | Veřejné metody na typu serveru | Označit atributem [OperationContract] |
Serializace | ISerializable nebo [Serializable] |
DataContractSerializer nebo XmlSerializer |
Předané objekty | Podle hodnoty nebo podle odkazu | Pouze po hodnotě |
Chyby nebo výjimky | Jakákoli serializovatelná výjimka | FaultContract<TDetail> |
Objekty proxy klienta | Z MarshalByRefObjects se automaticky vytvoří transparentní proxy servery se silnými typy. | Proxy servery silného typu se generují na vyžádání pomocí ChannelFactory<TChannel.> |
Požadovaná platforma | Klient i server musí používat operační systém Microsoftu a .NET. | Mezi platformami |
Formát zprávy | Privátní | Oborové standardy (například SOAP a WS-*) |
Porovnání implementace serveru
Vytvoření serveru v vzdálené sítě .NET
Typy serverů vzdálené komunikace .NET musí být odvozeny od MarshalByRefObject a definovat metody, které klient může volat, například následující:
public class RemotingServer : MarshalByRefObject
{
public Customer GetCustomer(int customerId) { … }
}
Veřejné metody tohoto typu serveru se stanou veřejnou smlouvou dostupnou klientům. Mezi veřejným rozhraním serveru a jeho implementací není žádné oddělení – jeden typ zpracovává obojí.
Jakmile je typ serveru definovaný, můžete ho zpřístupnit klientům, jako v následujícím příkladu:
TcpChannel channel = new TcpChannel(8080);
ChannelServices.RegisterChannel(channel, ensureSecurity : true);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemotingServer),
"RemotingServer",
WellKnownObjectMode.Singleton);
Console.WriteLine("RemotingServer is running. Press ENTER to terminate...");
Console.ReadLine();
Existuje mnoho způsobů, jak zpřístupnit typ vzdálené komunikace jako server, včetně použití konfiguračních souborů. Toto je jen jeden příklad.
Vytvoření serveru ve WCF
Ekvivalentní krok wcf zahrnuje vytvoření dvou typů – veřejné "kontrakty služeb" a konkrétní implementace. První je deklarován jako rozhraní označené [ServiceContract]. Metody dostupné pro klienty jsou označené [OperationContract]:
[ServiceContract]
public interface IWCFServer
{
[OperationContract]
Customer GetCustomer(int customerId);
}
Implementace serveru je definována v samostatné konkrétní třídě, například v následujícím příkladu:
public class WCFServer : IWCFServer
{
public Customer GetCustomer(int customerId) { … }
}
Po definování těchto typů lze server WCF zpřístupnit klientům, jako je v následujícím příkladu:
NetTcpBinding binding = new NetTcpBinding();
Uri baseAddress = new Uri("net.tcp://localhost:8000/wcfserver");
using (ServiceHost serviceHost = new ServiceHost(typeof(WCFServer), baseAddress))
{
serviceHost.AddServiceEndpoint(typeof(IWCFServer), binding, baseAddress);
serviceHost.Open();
Console.WriteLine($"The WCF server is ready at {baseAddress}.");
Console.WriteLine("Press <ENTER> to terminate service...");
Console.WriteLine();
Console.ReadLine();
}
Poznámka:
Protokol TCP se používá v obou příkladech, aby byly co nejblíže. Příklady použití protokolu HTTP najdete v pozdější části tohoto tématu v návodu ke scénáři.
Existuje mnoho způsobů konfigurace a hostování služeb WCF. Toto je jen jeden příklad, který se označuje jako "v místním prostředí". Další informace naleznete v následujících tématech:
Porovnání implementace klienta
Vytvoření klienta v vzdálené komunikace .NET
Jakmile je objekt serveru vzdálené komunikace .NET dostupný, můžou ho využívat klienti, například v následujícím příkladu:
TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel, ensureSecurity : true);
RemotingServer server = (RemotingServer)Activator.GetObject(
typeof(RemotingServer),
"tcp://localhost:8080/RemotingServer");
RemotingCustomer customer = server.GetCustomer(42);
Console.WriteLine($"Customer {customer.FirstName} {customer.LastName} received.");
Instance RemotingServer vrácená z Activator.GetObject() se označuje jako "transparentní proxy server". Implementuje veřejné rozhraní API pro typ RemotingServer v klientovi, ale všechny metody volají objekt serveru spuštěný v jiném procesu nebo počítači.
Vytvoření klienta ve WCF
Ekvivalentní krok v WCF zahrnuje použití objektu pro vytváření kanálů k explicitní vytvoření proxy serveru. Podobně jako vzdálené komunikace lze objekt proxy použít k vyvolání operací na serveru, například v následujícím příkladu:
NetTcpBinding binding = new NetTcpBinding();
String url = "net.tcp://localhost:8000/wcfserver";
EndpointAddress address = new EndpointAddress(url);
ChannelFactory<IWCFServer> channelFactory =
new ChannelFactory<IWCFServer>(binding, address);
IWCFServer server = channelFactory.CreateChannel();
Customer customer = server.GetCustomer(42);
Console.WriteLine($" Customer {customer.FirstName} {customer.LastName} received.");
Tento příklad ukazuje programování na úrovni kanálu, protože je nejvíce podobný příkladu vzdálené komunikace. K dispozici je také přístup Add Service Reference v sadě Visual Studio, který generuje kód pro zjednodušení programování klientů. Další informace naleznete v následujících tématech:
Použití serializace
Vzdálené komunikace .NET i WCF používají serializaci k odesílání objektů mezi klientem a serverem, ale liší se těmito důležitými způsoby:
Používají různé serializátory a konvence k označení, co se má serializovat.
Vzdálené komunikace rozhraní .NET podporuje serializaci typu odkaz, která umožňuje metodám nebo vlastnostem přistupovat na jedné úrovni ke spouštění kódu na druhé úrovni, což je přes hranice zabezpečení. Tato funkce zveřejňuje ohrožení zabezpečení a je jedním z hlavních důvodů, proč by koncové body vzdálené komunikace nikdy neměly být vystaveny nedůvěryhodným klientům.
Serializace používaná remoting je opt-out (explicitně vyloučit, co se serializovat) a WCF serializace je opt-in (explicitně označit, které členy serializovat).
Serializace v vzdálené sítě .NET
Vzdálené komunikace .NET podporuje dva způsoby serializace a deserializace objektů mezi klientem a serverem:
Podle hodnoty – hodnoty objektu jsou serializovány přes hranice vrstev a nová instance tohoto objektu je vytvořena na druhé úrovni. Všechna volání metod nebo vlastností této nové instance se spouští pouze místně a nemají vliv na původní objekt nebo vrstvu.
Odkazem – speciální "odkaz na objekt" je serializován přes hranice vrstev. Když jedna vrstva komunikuje s metodami nebo vlastnostmi tohoto objektu, komunikuje zpět s původním objektem na původní vrstvě. Odkazované objekty mohou tokovat v libovolném směru – na server do klienta nebo na server.
Typy podle hodnot v remoting jsou označené atributem [Serializable] nebo implementují ISerializable, například v následujícím příkladu:
[Serializable]
public class RemotingCustomer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int CustomerId { get; set; }
}
Odkazové typy jsou odvozeny od MarshalByRefObject třídy, jako v následujícím příkladu:
public class RemotingCustomerReference : MarshalByRefObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int CustomerId { get; set; }
}
Je velmi důležité porozumět důsledkům objektů, které odkazují na vzdálené komunikace. Pokud vrstva (klient nebo server) odešle objekt podle odkazu na druhou vrstvu, všechna volání metody se spustí zpět na úrovni, která vlastní objekt. Například klient volající metody na objektu podle odkazu vrácené serverem spustí kód na serveru. Podobně server volající metody u objektu podle odkazu poskytovaného klientem spustí kód zpět v klientovi. Z tohoto důvodu se použití vzdálené komunikace .NET doporučuje pouze v plně důvěryhodných prostředích. Zveřejnění veřejného koncového bodu vzdálené komunikace .NET nedůvěryhodným klientům způsobí, že server vzdálené komunikace bude ohrožený útokem.
Serializace ve WCF
WCF podporuje pouze serializaci podle hodnot. Nejběžnější způsob, jak definovat typ pro výměnu mezi klientem a serverem, je podobný jako v následujícím příkladu:
[DataContract]
public class WCFCustomer
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public int CustomerId { get; set; }
}
Atribut [DataContract] identifikuje tento typ jako takový, který lze serializovat a deserializovat mezi klientem a serverem. Atribut [DataMember] identifikuje jednotlivé vlastnosti nebo pole pro serializaci.
Když WCF odešle objekt mezi vrstvami, serializuje pouze hodnoty a vytvoří novou instanci objektu na druhé úrovni. Všechny interakce s hodnotami objektu se vyskytují pouze místně – nekomunikují s druhou vrstvou způsobem, jakým .NET Remoting by-reference objekty dělají. Další informace naleznete v tématu Serializace a deserializace.
Možnosti zpracování výjimek
Výjimky v vzdálené komunikace .NET
Výjimky vyvolané serverem vzdálené komunikace jsou serializovány, odesílány klientovi a vyvolány místně na klientovi stejně jako jakékoli jiné výjimky. Vlastní výjimky je možné vytvořit podtřídou typu Výjimky a označit ji [Serializovatelným]. Většina výjimek architektury je již označena tímto způsobem, což umožňuje většinu vyvolání serverem, serializovaným a opětovným vyvoláním klienta. I když je tento návrh vhodný při vývoji, informace na straně serveru mohou být neúmyslně zpřístupněny klientovi. Je to jeden z mnoha důvodů, proč by se vzdálené komunikace měla používat jenom v plně důvěryhodných prostředích.
Výjimky a chyby ve WCF
WCF neumožňuje vrácení libovolných typů výjimek ze serveru klientovi, protože by mohlo vést k neúmyslnému zpřístupnění informací. Pokud operace služby vyvolá neočekávanou výjimku, způsobí vyvolání výjimky FaultException pro obecné účely v klientovi. Tato výjimka neobsahuje žádné informace o tom, proč nebo kde k problému došlo, a u některých aplikací to stačí. Aplikace, které potřebují sdělit bohatší informace o chybách klientovi, to dělají definováním kontraktu chyby.
Uděláte to tak, že nejprve vytvoříte typ [DataContract], který bude obsahovat informace o chybě.
[DataContract]
public class CustomerServiceFault
{
[DataMember]
public string ErrorMessage { get; set; }
[DataMember]
public int CustomerId {get;set;}
}
Zadejte kontrakt selhání, který se má použít pro každou operaci služby.
[ServiceContract]
public interface IWCFServer
{
[OperationContract]
[FaultContract(typeof(CustomerServiceFault))]
Customer GetCustomer(int customerId);
}
Server hlásí chybové stavy vyvoláním výjimky FaultException.
throw new FaultException<CustomerServiceFault>(
new CustomerServiceFault() {
CustomerId = customerId,
ErrorMessage = "Illegal customer Id"
});
A pokaždé, když klient odešle požadavek na server, může zachytit chyby jako běžné výjimky.
try
{
Customer customer = server.GetCustomer(-1);
}
catch (FaultException<CustomerServiceFault> fault)
{
Console.WriteLine($"Fault received: {fault.Detail.ErrorMessage}");
}
Další informace o kontraktech chyb naleznete v tématu FaultException.
Aspekty zabezpečení
Zabezpečení v vzdálené komunikace .NET
Některé kanály vzdálené komunikace .NET podporují funkce zabezpečení, jako je ověřování a šifrování ve vrstvě kanálu (IPC a TCP). Kanál HTTP spoléhá na Internetová informační služba (IIS) pro ověřování i šifrování. I přes tuto podporu byste měli zvážit komunikaci .NET se nezabezpečeným komunikačním protokolem a používat ho pouze v plně důvěryhodných prostředích. Nikdy nezpřístupňujte veřejný koncový bod vzdálené komunikace pro internet nebo nedůvěryhodné klienty.
Zabezpečení ve službě WCF
TECHNOLOGIE WCF byla navržena s ohledem na zabezpečení, a to zčásti tak, aby řešila druhy ohrožení zabezpečení nalezených v vzdálené komunikace .NET. WCF nabízí zabezpečení na úrovni přenosu i zpráv a nabízí mnoho možností ověřování, autorizace, šifrování atd. Další informace naleznete v následujících tématech:
Migrace na WCF
Proč migrovat ze vzdálené komunikace na WCF?
Vzdálené komunikace .NET je starší verze produktu. Jak je popsáno v vzdálené komunikaci .NET, považuje se za starší produkt a nedoporučuje se pro nový vývoj. Wcf nebo ASP.NET webové rozhraní API se doporučuje pro nové a existující aplikace.
WCF používá víceplatformní standardy. WCF byl navržen s ohledem na interoperabilitu napříč platformami a podporuje mnoho oborových standardů (SOAP, WS-Security, WS-Trust atd.). Služba WCF může spolupracovat s klienty běžícími na jiných operačních systémech než Windows. Vzdálenou komunikace byla navržena především pro prostředí, kde serverové i klientské aplikace běží pomocí rozhraní .NET Framework v operačním systému Windows.
WCF má integrované zabezpečení. WCF byl navržen s ohledem na zabezpečení a nabízí mnoho možností pro ověřování, zabezpečení na úrovni přenosu, zabezpečení na úrovni zpráv atd. Komunikace byla navržena tak, aby usnadnila spolupráci aplikací, ale nebyla navržena tak, aby byla zabezpečená v nedůvěryhodných prostředích. TECHNOLOGIE WCF byla navržena tak, aby fungovala v důvěryhodných i nedůvěryhodných prostředích.
Doporučení k migraci
Následující doporučené kroky pro migraci ze vzdálené komunikace .NET na WCF:
Vytvořte kontrakt služby. Definujte typy rozhraní služby a označte je atributem [ServiceContract]. Označte všechny metody, které klienti budou moct volat pomocí operace [OperationContract].
Vytvořte kontrakt dat. Definujte datové typy, které se budou vyměňovat mezi serverem a klientem, a označte je atributem [DataContract]. Označte všechna pole a vlastnosti, které bude klient moct používat s [DataMember].
Vytvoření kontraktu chyby (volitelné) Vytvořte typy, které se budou vyměňovat mezi serverem a klientem, když dojde k chybám. Označte tyto typy pomocí funkce [DataContract] a [DataMember], aby bylo možné je serializovat. U všech operací služby, které jste označili jako [OperationContract], označte je také pomocí funkce [FaultContract], aby bylo možné určit, které chyby se můžou vrátit.
Nakonfigurujte a hostujte službu. Po vytvoření kontraktu služby je dalším krokem konfigurace vazby pro zveřejnění služby v koncovém bodu. Další informace najdete v tématu Koncové body: Adresy, vazby a kontrakty.
Jakmile je aplikace vzdálené komunikace migrována do WCF, je stále důležité odebrat závislosti na vzdálené komunikace .NET. Tím se zajistí, že se z aplikace odeberou všechna ohrožení zabezpečení vzdálené komunikace. Mezi tyto kroky patří:
Ukončení používání MarshalByRefObject Typ MarshalByRefObject existuje pouze pro vzdálené komunikace a wcf ho nepoužívá. Všechny typy aplikací, které podtřídě MarshalByRefObject mají být odebrány nebo změněny.
Ukončení používání [Serializable] a ISerializable. Atribut [Serializable] a rozhraní ISerializable byly původně navrženy pro serializaci typů v rámci důvěryhodných prostředí a jsou používány vzdálené komunikace. Serializace WCF spoléhá na typy označené [DataContract] a [DataMember]. Datové typy používané aplikací by měly být upraveny tak, aby používaly [DataContract] a neměly by používat ISerializable nebo [Serializable].
Scénáře migrace
Teď se podíváme, jak ve WCF provést následující běžné scénáře vzdálené komunikace:
Server vrátí klientovi objekt po hodnotě.
Server vrátí objekt podle odkazu na klienta.
Klient odešle objekt po hodnotě na server.
Poznámka:
Odesílání objektu podle odkazu z klienta na server není v WCF povoleno.
Při čtení těchto scénářů předpokládejme, že naše základní rozhraní pro vzdálené komunikace .NET vypadají jako v následujícím příkladu. Implementace vzdálené komunikace .NET zde není důležitá, protože chceme ilustrovat pouze to, jak použít WCF k implementaci ekvivalentních funkcí.
public class RemotingServer : MarshalByRefObject
{
// Demonstrates server returning object by-value
public Customer GetCustomer(int customerId) {…}
// Demonstrates server returning object by-reference
public CustomerReference GetCustomerReference(int customerId) {…}
// Demonstrates client passing object to server by-value
public bool UpdateCustomer(Customer customer) {…}
}
Scénář 1: Služba vrátí objekt podle hodnoty
Tento scénář ukazuje server vracející objekt klientovi podle hodnoty. WCF vždy vrací objekty ze serveru podle hodnoty, takže následující kroky jednoduše popisují, jak sestavit normální službu WCF.
Začněte definováním veřejného rozhraní pro službu WCF a označte ho atributem [ServiceContract]. [OperationContract] používáme k identifikaci metod na straně serveru, které bude klient volat.
[ServiceContract] public interface ICustomerService { [OperationContract] Customer GetCustomer(int customerId); [OperationContract] bool UpdateCustomer(Customer customer); }
Dalším krokem je vytvoření datového kontraktu pro tuto službu. Provedeme to vytvořením tříd (nikoli rozhraní) označených atributem [DataContract]. Jednotlivé vlastnosti nebo pole, která chceme zobrazit pro klienta i server, jsou označeny uživatelem [DataMember]. Pokud chceme, aby byly odvozené typy povolené, musíme k jejich identifikaci použít atribut [KnownType]. Jediné typy WCF umožní serializovat nebo deserializovat pro tuto službu jsou ty v rozhraní služby a tyto "známé typy". Pokus o výměnu jakéhokoli jiného typu, který není v tomto seznamu, bude odmítnut.
[DataContract] [KnownType(typeof(PremiumCustomer))] public class Customer { [DataMember] public string FirstName { get; set; } [DataMember] public string LastName { get; set; } [DataMember] public int CustomerId { get; set; } } [DataContract] public class PremiumCustomer : Customer { [DataMember] public int AccountId { get; set; } }
Dále poskytneme implementaci rozhraní služby.
public class CustomerService : ICustomerService { public Customer GetCustomer(int customerId) { // read from database } public bool UpdateCustomer(Customer customer) { // write to database } }
Ke spuštění služby WCF musíme deklarovat koncový bod, který zveřejňuje rozhraní služby na konkrétní adrese URL pomocí konkrétní vazby WCF. To se obvykle provádí přidáním následujících částí do souboru web.config projektu serveru.
<configuration> <system.serviceModel> <services> <service name="Server.CustomerService"> <endpoint address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService" /> </service> </services> </system.serviceModel> </configuration>
Službu WCF pak můžete spustit následujícím kódem:
ServiceHost customerServiceHost = new ServiceHost(typeof(CustomerService)); customerServiceHost.Open();
Při spuštění serviceHost používá soubor web.config k vytvoření správného kontraktu, vazby a koncového bodu. Další informace o konfiguračních souborech naleznete v tématu Konfigurace služeb pomocí konfiguračních souborů. Tento styl spuštění serveru se označuje jako samoobslužné hostování. Další informace o dalších možnostech hostování služeb WCF najdete v tématu Hostitelské služby.
App.config klientského projektu musí deklarovat odpovídající informace o vazbě pro koncový bod služby. Nejjednodušším způsobem, jak to udělat v sadě Visual Studio, je použít příkaz Add Service Reference, který automaticky aktualizuje soubor app.config. Případně můžete tyto stejné změny přidat ručně.
<configuration> <system.serviceModel> <client> <endpoint name="customerservice" address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService"/> </client> </system.serviceModel> </configuration>
Další informace o použití odkazu na přidání služby naleznete v tématu Postupy: Přidání, aktualizace nebo odebrání odkazu na službu.
Teď můžeme službu WCF volat z klienta. Provedeme to tak, že pro tuto službu vytvoříme objekt pro vytváření kanálů, požádáme ho o kanál a přímo zavoláme metodu, kterou chceme v tomto kanálu. Můžeme to udělat, protože kanál implementuje rozhraní služby a zpracovává za nás související logiku požadavků a odpovědí. Návratová hodnota volání této metody je deserializovaná kopie odpovědi serveru.
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>("customerservice"); ICustomerService service = factory.CreateChannel(); Customer customer = service.GetCustomer(42); Console.WriteLine($" Customer {customer.FirstName} {customer.LastName} received.");
Objekty vrácené WCF ze serveru do klienta jsou vždy podle hodnoty. Objekty jsou deserializované kopie dat odesílaných serverem. Klient může volat metody na těchto místních kopiích bez nebezpečí vyvolání kódu serveru prostřednictvím zpětných volání.
Scénář 2: Server vrátí objekt podle odkazu
Tento scénář ukazuje server poskytující objekt klientovi odkazem. V rozhraní .NET Remoting se zpracovává automaticky pro jakýkoli typ odvozený z MarshalByRefObject, který je serializován odkazem. Příkladem tohoto scénáře je povolení, aby více klientů mohlo mít nezávislé objekty na straně serveru. Jak jsme již zmínili, objekty vrácené službou WCF jsou vždy podle hodnoty, takže neexistuje žádný přímý ekvivalent objektu podle odkazu, ale je možné dosáhnout něčeho podobného sémantice podle odkazu pomocí objektu EndpointAddress10 . Jedná se o serializovatelný objekt podle hodnoty, který může klient použít k získání objektu relace podle odkazu na serveru. To umožňuje scénář s více klienty s nezávislými objekty na straně serveru.
Nejprve musíme definovat kontrakt služby WCF, který odpovídá samotnému objektu relace.
[ServiceContract(SessionMode = SessionMode.Allowed)] public interface ISessionBoundObject { [OperationContract] string GetCurrentValue(); [OperationContract] void SetCurrentValue(string value); }
Tip
Všimněte si, že objekt sessionful je označen [ServiceContract], čímž se jedná o normální rozhraní služby WCF. Nastavení Vlastnosti SessionMode označuje, že se jedná o službu relace. Ve WCF představuje relace způsob korelace více zpráv odesílaných mezi dvěma koncovými body. To znamená, že jakmile klient získá připojení k této službě, vytvoří se relace mezi klientem a serverem. Klient použije jednu jedinečnou instanci objektu na straně serveru pro všechny interakce v rámci této jedné relace.
Dále musíme poskytnout implementaci tohoto rozhraní služby. Tím, že ho zapíšeme pomocí [ServiceBehavior] a nastavíme InstanceContextMode, řekneme WCF, že chceme pro každou relaci použít jedinečnou instanci tohoto typu.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class MySessionBoundObject : ISessionBoundObject { private string _value; public string GetCurrentValue() { return _value; } public void SetCurrentValue(string val) { _value = val; } }
Teď potřebujeme způsob, jak získat instanci tohoto objektu relace. Provedeme to vytvořením dalšího rozhraní služby WCF, které vrací objekt EndpointAddress10. Jedná se o serializovatelnou formu koncového bodu, kterou klient může použít k vytvoření objektu sessionful.
[ServiceContract] public interface ISessionBoundFactory { [OperationContract] EndpointAddress10 GetInstanceAddress(); }
A implementujeme tuto službu WCF:
public class SessionBoundFactory : ISessionBoundFactory { public static ChannelFactory<ISessionBoundObject> _factory = new ChannelFactory<ISessionBoundObject>("sessionbound"); public SessionBoundFactory() { } public EndpointAddress10 GetInstanceAddress() { IClientChannel channel = (IClientChannel)_factory.CreateChannel(); return EndpointAddress10.FromEndpointAddress(channel.RemoteAddress); } }
Tato implementace udržuje objekt pro vytváření objektů s jednímton kanálem pro vytváření objektů relace. Při volání GetInstanceAddress() vytvoří kanál a vytvoří objekt EndpointAddress10, který efektivně odkazuje na vzdálenou adresu přidruženou k tomuto kanálu. EndpointAddress10 je jednoduše datový typ, který lze vrátit klientovi podle hodnoty.
Konfigurační soubor serveru musíme upravit provedením následujících dvou věcí, jak je znázorněno v následujícím příkladu:
<Deklarujte část klienta>, která popisuje koncový bod pro objekt relace. To je nezbytné, protože server v této situaci funguje také jako klient.
Deklarujte koncové body pro objekt továrny a objekt relace. To je nezbytné, aby klient mohl komunikovat s koncovými body služby, aby získal EndpointAddress10 a vytvořil kanál relace.
<configuration> <system.serviceModel> <client> <endpoint name="sessionbound" address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject"/> </client> <services> <service name="Server.CustomerService"> <endpoint address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService" /> </service> <service name="Server.MySessionBoundObject"> <endpoint address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject" /> </service> <service name="Server.SessionBoundFactory"> <endpoint address="net.tcp://localhost:8081/SessionBoundFactory" binding="netTcpBinding" contract="Shared.ISessionBoundFactory" /> </service> </services> </system.serviceModel> </configuration>
A pak můžeme spustit tyto služby:
ServiceHost factoryHost = new ServiceHost(typeof(SessionBoundFactory)); factoryHost.Open(); ServiceHost sessionHost = new ServiceHost(typeof(MySessionBoundObject)); sessionHost.Open();
Klienta nakonfigurujeme deklarací těchto stejných koncových bodů v souboru app.config projektu.
<configuration> <system.serviceModel> <client> <endpoint name="customerservice" address="http://localhost:8083/CustomerService" binding="basicHttpBinding" contract="Shared.ICustomerService"/> <endpoint name="sessionbound" address="net.tcp://localhost:8081/SessionBoundObject" binding="netTcpBinding" contract="Shared.ISessionBoundObject"/> <endpoint name="factory" address="net.tcp://localhost:8081/SessionBoundFactory" binding="netTcpBinding" contract="Shared.ISessionBoundFactory"/> </client> </system.serviceModel> </configuration>
Aby bylo možné vytvořit a používat tento objekt relace, musí klient provést následující kroky:
Vytvořte kanál pro službu ISessionBoundFactory.
Tento kanál použijte k vyvolání této služby k získání endpointAddress10.
Pomocí endpointAddress10 vytvořte kanál pro získání objektu relace.
Interagujte s objektem relace, abyste ukázali, že zůstává stejnou instancí napříč více voláními.
ChannelFactory<ISessionBoundFactory> channelFactory = new ChannelFactory<ISessionBoundFactory>("factory"); ISessionBoundFactory sessionFactory = channelFactory.CreateChannel(); EndpointAddress10 address1 = sessionFactory.GetInstanceAddress(); EndpointAddress10 address2 = sessionFactory.GetInstanceAddress(); ChannelFactory<ISessionBoundObject> sessionObjectFactory1 = new ChannelFactory<ISessionBoundObject>(new NetTcpBinding(), address1.ToEndpointAddress()); ChannelFactory<ISessionBoundObject> sessionObjectFactory2 = new ChannelFactory<ISessionBoundObject>(new NetTcpBinding(), address2.ToEndpointAddress()); ISessionBoundObject sessionInstance1 = sessionObjectFactory1.CreateChannel(); ISessionBoundObject sessionInstance2 = sessionObjectFactory2.CreateChannel(); sessionInstance1.SetCurrentValue("Hello"); sessionInstance2.SetCurrentValue("World"); if (sessionInstance1.GetCurrentValue() == "Hello" && sessionInstance2.GetCurrentValue() == "World") { Console.WriteLine("sessionful server object works as expected"); }
WCF vždy vrací objekty podle hodnoty, ale je možné podporovat ekvivalent sémantiky podle odkazu prostřednictvím použití EndpointAddress10. To klientovi umožňuje požádat o instanci služby WCF v relaci, po které může s ní pracovat stejně jako s jakoukoli jinou službou WCF.
Scénář 3: Klient odešle server instanci po hodnotě
Tento scénář ukazuje, že klient odesílá instanci objektu, která není primitivní, na server podle hodnoty. Vzhledem k tomu, že WCF odesílá pouze objekty podle hodnoty, tento scénář ukazuje normální použití WCF.
Použijte stejnou službu WCF ze scénáře 1.
Pomocí klienta vytvořte nový objekt podle hodnoty (Zákazník), vytvořte kanál pro komunikaci se službou ICustomerService a odešlete do něj objekt.
ChannelFactory<ICustomerService> factory = new ChannelFactory<ICustomerService>("customerservice"); ICustomerService service = factory.CreateChannel(); PremiumCustomer customer = new PremiumCustomer { FirstName = "Bob", LastName = "Jones", CustomerId = 43, AccountId = 99}; bool success = service.UpdateCustomer(customer); Console.WriteLine($" Server returned {success}.");
Objekt zákazníka bude serializován a odeslán na server, kde je deserializován do nové kopie tohoto objektu.
Poznámka:
Tento kód také ilustruje odesílání odvozeného typu (PremiumCustomer). Rozhraní služby očekává objekt Customer, ale atribut [KnownType] ve třídě Customer označený jako PremiumCustomer byl také povolen. WCF selže při pokusu o serializaci nebo deserializaci jakéhokoli jiného typu prostřednictvím tohoto rozhraní služby.
Normální výměny dat WCF jsou podle hodnoty. To zaručuje, že vyvolání metod na jednom z těchto datových objektů se spustí pouze místně – nevyvolá kód na druhé úrovni. I když je možné dosáhnout něčeho, jako by-reference objekty vrácené ze serveru, není možné, aby klient předal objekt by-reference na server. Scénář, který vyžaduje konverzaci mezi klientem a serverem, je možné dosáhnout ve WCF pomocí duplexní služby. Další informace naleznete v tématu Duplex Services.
Shrnutí
Vzdálená komunikace .NET je komunikační architektura určená k použití pouze v plně důvěryhodných prostředích. Jedná se o starší verzi produktu a podporuje se pouze kvůli zpětné kompatibilitě. Nemělo by se používat k vytváření nových aplikací. Wcf byl naopak navržen s ohledem na zabezpečení a doporučuje se pro nové a existující aplikace. Společnost Microsoft doporučuje migrovat stávající aplikace vzdálené komunikace, aby místo toho používaly WCF nebo ASP.NET webové rozhraní API.