Postup: Migrace spravovaného kódu DCOM do WCF
Windows Communication Foundation (WCF) je doporučená a bezpečná volba pro volání spravovaného kódu mezi servery a klienty v distribuovaném prostředí prostřednictvím modelu DCOM (Distributed Component Object Model). Tento článek ukazuje, jak migrovat kód z modelu DCOM do WCF pro následující scénáře.
Vzdálená služba vrátí klientovi objekt po hodnotě.
Klient odešle objekt po hodnotě do vzdálené služby.
Vzdálená služba vrátí objekt podle odkazu na klienta.
Z bezpečnostních důvodů není odesílání objektu odkazem z klienta do služby ve službě povoleno. Scénář, který vyžaduje konverzaci mezi klientem a serverem, je možné dosáhnout ve WCF pomocí duplexní služby. Další informace o duplexní služby naleznete v tématu Duplex Services.
Další podrobnosti o vytváření služeb WCF a klientů pro tyto služby naleznete v tématu Základní programování WCF, navrhování a implementace služeb a sestavování klientů.
Ukázkový kód modelu DCOM
Pro tyto scénáře mají rozhraní DCOM, která jsou znázorněna pomocí WCF, následující strukturu:
[ComVisible(true)]
[Guid("AA9C4CDB-55EA-4413-90D2-843F1A49E6E6")]
public interface IRemoteService
{
Customer GetObjectByValue();
IRemoteObject GetObjectByReference();
void SendObjectByValue(Customer customer);
}
[ComVisible(true)]
[Guid("A12C98DE-B6A1-463D-8C24-81E4BBC4351B")]
public interface IRemoteObject
{
}
public class Customer
{
}
Služba vrátí objekt po hodnotě.
V tomto scénáři provedete volání služby a metoda vrátí objekt, který je předán podle hodnoty ze serveru klientovi. Tento scénář představuje následující volání modelu COM:
public interface IRemoteService
{
Customer GetObjectByValue();
}
V tomto scénáři klient obdrží deserializovanou kopii objektu ze vzdálené služby. Klient může s touto místní kopií pracovat bez volání zpět do služby. Jinými slovy, klient zaručuje, že služba nebude zapojena žádným způsobem, když jsou volána metody v místní kopii. WCF vždy vrací objekty ze služby podle hodnoty, takže následující kroky popisují vytvoření běžné služby WCF.
Krok 1: Definování rozhraní služby WCF
Definujte veřejné rozhraní pro službu WCF a označte ho atributem [ServiceContractAttribute]. Označte metody, které chcete zpřístupnit klientům pomocí atributu [OperationContractAttribute]. Následující příklad ukazuje použití těchto atributů k identifikaci rozhraní na straně serveru a metod rozhraní, které klient může volat. Metoda použitá pro tento scénář je zobrazena tučně.
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
. . .
[ServiceContract]
public interface ICustomerManager
{
[OperationContract]
void StoreCustomer(Customer customer);
[OperationContract] Customer GetCustomer(string firstName, string lastName);
}
Krok 2: Definování datového kontraktu
Dále byste měli vytvořit kontrakt dat pro službu, který popisuje způsob výměny dat mezi službou a jejími klienty. Třídy popsané v datovém kontraktu by měly být označeny atributem [DataContractAttribute]. Jednotlivé vlastnosti nebo pole, která chcete zobrazit pro klienta i server, by měly být označeny atributem [DataMemberAttribute]. Pokud chcete, aby byly typy odvozené z třídy v kontraktu dat povolené, musíte je identifikovat pomocí atributu [KnownTypeAttribute]. WCF bude serializovat nebo deserializovat typy v rozhraní služby a typy identifikované jako známé typy. Pokud se pokusíte použít typ, který není známým typem, dojde k výjimce.
Další informace o kontraktech dat naleznete v tématu Kontrakty dat.
[DataContract]
[KnownType(typeof(PremiumCustomer))]
public class Customer
{
[DataMember]
public string Firstname;
[DataMember]
public string Lastname;
[DataMember]
public Address DefaultDeliveryAddress;
[DataMember]
public Address DefaultBillingAddress;
}
[DataContract]
public class PremiumCustomer : Customer
{
[DataMember]
public int AccountID;
}
[DataContract]
public class Address
{
[DataMember]
public string Street;
[DataMember]
public string Zipcode;
[DataMember]
public string City;
[DataMember]
public string State;
[DataMember]
public string Country;
}
Krok 3: Implementace služby WCF
Dále byste měli implementovat třídu služby WCF, která implementuje rozhraní, které jste definovali v předchozím kroku.
public class CustomerService: ICustomerManager
{
public void StoreCustomer(Customer customer)
{
// write to a database
}
public Customer GetCustomer(string firstName, string lastName)
{
// read from a database
}
}
Krok 4: Konfigurace služby a klienta
Pokud chcete spustit službu WCF, musíte deklarovat koncový bod, který zveřejňuje rozhraní služby na konkrétní adrese URL pomocí konkrétní vazby WCF. Vazba určuje podrobnosti přenosu, kódování a protokolu pro komunikaci klientů a serveru. Do konfiguračního souboru projektu služby (web.config) obvykle přidáváte vazby. Následující příklad ukazuje položku vazby pro ukázkovou službu:
<configuration>
<system.serviceModel>
<services>
<service name="Server.CustomerService">
<endpoint address="http://localhost:8083/CustomerManager"
binding="basicHttpBinding"
contract="Shared.ICustomerManager" />
</service>
</services>
</system.serviceModel>
</configuration>
Dále musíte klienta nakonfigurovat tak, aby odpovídal informacím o vazbě určeným službou. Uděláte to tak, že do souboru konfigurace aplikace klienta (app.config) přidáte následující kód.
<configuration>
<system.serviceModel>
<client>
<endpoint name="customermanager"
address="http://localhost:8083/CustomerManager"
binding="basicHttpBinding"
contract="Shared.ICustomerManager"/>
</client>
</system.serviceModel>
</configuration>
Krok 5: Spuštění služby
Nakonec ji můžete sami hostovat v konzolové aplikaci tak, že do aplikace služby přidáte následující řádky a spustíte aplikaci. Další informace o dalších způsobech hostování aplikace služby WCF, Hosting Services.
ServiceHost customerServiceHost = new ServiceHost(typeof(CustomerService));
customerServiceHost.Open();
Krok 6: Volání služby z klienta
Pokud chcete volat službu z klienta, musíte pro službu vytvořit objekt pro vytváření kanálů a požádat o kanál, který vám umožní přímo volat metodu GetCustomer
přímo z klienta. Kanál implementuje rozhraní služby a zpracovává za vás související logiku požadavků a odpovědí. Návratová hodnota volání této metody je deserializovaná kopie odpovědi služby.
ChannelFactory<ICustomerManager> factory =
new ChannelFactory<ICustomerManager>("customermanager");
ICustomerManager service = factory.CreateChannel();
Customer customer = service.GetCustomer("Mary", "Smith");
Klient odešle objekt podle hodnoty na server.
V tomto scénáři klient odešle objekt na server po hodnotě. To znamená, že server obdrží deserializovanou kopii objektu. Server může volat metody na této kopii a zaručit, že neexistuje zpětné volání do klientského kódu. Jak už bylo zmíněno dříve, normální výměny dat WCF jsou podle hodnoty. To zaručuje, že volání metod na jednom z těchto objektů se provádí pouze místně – nevyvolá kód na klientovi.
Tento scénář představuje následující volání metody MODELU COM:
public interface IRemoteService
{
void SendObjectByValue(Customer customer);
}
Tento scénář používá stejné rozhraní služeb a kontrakt dat, jak je znázorněno v prvním příkladu. Klient a služba se navíc nakonfigurují stejným způsobem. V tomto příkladu se vytvoří kanál pro odeslání objektu a spuštění stejným způsobem. V tomto příkladu však vytvoříte klienta, který volá službu a předává objekt po hodnotě. Metoda služby, která klient zavolá ve smlouvě o službě, se zobrazí tučně:
[ServiceContract]
public interface ICustomerManager
{
[OperationContract] void StoreCustomer(Customer customer);
[OperationContract]
Customer GetCustomer(string firstName, string lastName);
}
Přidání kódu do klienta, který odešle objekt podle hodnoty
Následující kód ukazuje, jak klient vytvoří nový objekt zákazníka podle hodnoty, vytvoří kanál pro komunikaci se službou ICustomerManager
a odešle mu objekt zákazníka.
Objekt zákazníka bude serializován a odeslán do služby, kde je deserializován službou do nové kopie tohoto objektu. Všechny metody, které služba volá na tomto objektu, se spustí pouze místně na serveru. Je důležité si uvědomit, že tento kód znázorňuje odesílání odvozeného typu (PremiumCustomer
). Kontrakt služby očekává Customer
objekt, ale kontrakt dat služby používá atribut [KnownTypeAttribute] k označení, že PremiumCustomer
je také povolený. WCF se nezdaří pokusy o serializaci nebo deserializaci jakéhokoli jiného typu prostřednictvím tohoto rozhraní služby.
PremiumCustomer customer = new PremiumCustomer();
customer.Firstname = "John";
customer.Lastname = "Doe";
customer.DefaultBillingAddress = new Address();
customer.DefaultBillingAddress.Street = "One Microsoft Way";
customer.DefaultDeliveryAddress = customer.DefaultBillingAddress;
customer.AccountID = 42;
ChannelFactory<ICustomerManager> factory =
new ChannelFactory<ICustomerManager>("customermanager");
ICustomerManager customerManager = factory.CreateChannel();
customerManager.StoreCustomer(customer);
Služba vrátí objekt podle odkazu.
V tomto scénáři klientská aplikace volá vzdálenou službu a metoda vrátí objekt, který je předán odkazem ze služby klientovi.
Jak už bylo zmíněno dříve, služby WCF vždy vrací objekt podle hodnoty. Podobný výsledek však můžete dosáhnout pomocí EndpointAddress10 třídy. Jedná se EndpointAddress10 o serializovatelný objekt podle hodnoty, který může klient použít k získání objektu relace by-reference na serveru.
Chování objektu podle odkazu ve WCF zobrazeném v tomto scénáři se liší od modelu DCOM. V modelu DCOM může server vrátit objekt podle odkazu přímo klientovi a klient může volat metody daného objektu, které se spouští na serveru. Ve WCF je však vrácen objekt vždy po hodnotě. Klient musí tento objekt podle hodnoty reprezentovat EndpointAddress10 a použít k vytvoření vlastního objektu relace podle odkazu. Metoda klienta volá na serveru spuštěný objekt relace. Jinými slovy, tento objekt podle odkazu ve WCF je normální služba WCF, která je nakonfigurována tak, aby byla 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. Kontrakty WCF s relacemi jsou podobné schématům síťových požadavků a odpovědí orientovaným na připojení.
Tento scénář je reprezentován následující metodou modelu DCOM.
public interface IRemoteService
{
IRemoteObject GetObjectByReference();
}
Krok 1: Definování rozhraní a implementace služby WCF sessionful
Nejprve definujte rozhraní služby WCF, které obsahuje objekt relace.
V tomto kódu je objekt sessionful označen atributem ServiceContract
, který jej identifikuje jako běžné rozhraní služby WCF. Kromě toho je vlastnost nastavena tak, SessionMode aby označí, že se jedná o službu relace.
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface ISessionBoundObject
{
[OperationContract]
string GetCurrentValue();
[OperationContract]
void SetCurrentValue(string value);
}
Následující kód ukazuje implementaci služby.
Služba je označena atributem [ServiceBehavior] a jeho InstanceContextMode vlastnost nastavena na InstanceContextMode.PerSessions označující, že pro každou relaci by měla být vytvořena jedinečná instance 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;
}
}
Krok 2: Definování služby továrny WCF pro objekt relace
Služba, která vytváří objekt relace, musí být definována a implementována. Následující kód ukazuje, jak to provést. Tento kód vytvoří další službu WCF, která vrací EndpointAddress10 objekt. Jedná se o serializovatelnou formu koncového bodu, který může použít k vytvoření objektu celé relace.
[ServiceContract]
public interface ISessionBoundFactory
{
[OperationContract]
EndpointAddress10 GetInstanceAddress();
}
Následuje implementace této služby. Tato implementace udržuje objekt pro vytváření objektů s jednímton kanálem pro vytváření objektů relace. Při GetInstanceAddress
volání vytvoří kanál a vytvoří EndpointAddress10 objekt, který odkazuje na vzdálenou adresu přidruženou k tomuto kanálu. EndpointAddress10 je datový typ, který může být vrácen klientovi podle hodnoty.
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);
}
}
Krok 3: Konfigurace a spuštění služeb WCF
Pokud chcete tyto služby hostovat, budete muset do konfiguračního souboru serveru (web.config) přidat následující údaje.
<client>
Přidejte oddíl, který popisuje koncový bod pro objekt relace. V tomto scénáři server funguje také jako klient a musí být nakonfigurovaný tak, aby ho povolil.<services>
V části deklarujte koncové body služby pro objekt factory a objekt relace. To umožňuje klientovi komunikovat s koncovými body služby, získat EndpointAddress10 a vytvořit kanál relace.
Následuje příklad konfiguračního souboru s těmito nastaveními:
<configuration>
<system.serviceModel>
<client>
<endpoint name="sessionbound"
address="net.tcp://localhost:8081/SessionBoundObject"
binding="netTcpBinding"
contract="Shared.ISessionBoundObject"/>
</client>
<services>
<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>
Přidejte do konzolové aplikace následující řádky, pro samoobslužné hostování služby a spusťte aplikaci.
ServiceHost factoryHost = new ServiceHost(typeof(SessionBoundFactory));
factoryHost.Open();
ServiceHost sessionBoundServiceHost = new ServiceHost(
typeof(MySessionBoundObject));
sessionBoundServiceHost.Open();
Krok 4: Konfigurace klienta a volání služby
Nakonfigurujte klienta pro komunikaci se službami WCF tak, že v konfiguračním souboru aplikace projektu (app.config) nastavíte následující položky.
<configuration>
<system.serviceModel>
<client>
<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>
Pokud chcete službu volat, přidejte do klienta kód, který provede následující akce:
Vytvořte kanál pro
ISessionBoundFactory
službu.Pomocí kanálu vyvoláte
ISessionBoundFactory
službu získání objektu EndpointAddress10 .EndpointAddress10 Slouží k vytvoření kanálu k získání objektu relace.
Voláním
SetCurrentValue
metod aGetCurrentValue
předvedete, že zůstává stejná instance objektu, se používá napříč několika voláními.
ChannelFactory<ISessionBoundFactory> factory =
new ChannelFactory<ISessionBoundFactory>("factory");
ISessionBoundFactory sessionBoundFactory = factory.CreateChannel();
EndpointAddress10 address = sessionBoundFactory.GetInstanceAddress();
ChannelFactory<ISessionBoundObject> sessionBoundObjectFactory =
new ChannelFactory<ISessionBoundObject>(
new NetTcpBinding(),
address.ToEndpointAddress());
ISessionBoundObject sessionBoundObject =
sessionBoundObjectFactory.CreateChannel();
sessionBoundObject.SetCurrentValue("Hello");
if (sessionBoundObject.GetCurrentValue() == "Hello")
{
Console.WriteLine("Session-full instance management works as expected");
}