Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A Windows Communication Foundation (WCF) az elosztott komponensobjektum-modell (DCOM) ajánlott és biztonságos választása a kiszolgálók és ügyfelek közötti felügyelt kódhívásokhoz elosztott környezetben. Ez a cikk bemutatja, hogyan migrálhatja a kódot a DCOM-ból a WCF-be az alábbi helyzetekben.
A távoli szolgáltatás objektumonkénti értéket ad vissza az ügyfélnek
Az ügyfél objektumonkénti értéket küld a távoli szolgáltatásnak
A távoli szolgáltatás egy objektumot ad vissza az ügyfélre mutató hivatkozással
Biztonsági okokból a WCF nem engedélyezi, hogy objektumot referencia szerint küldjön az ügyféltől a szolgáltatás részére. Az ügyfél és a kiszolgáló közötti oda-vissza beszélgetést igénylő forgatókönyv kétoldalas szolgáltatással érhető el a WCF-ben. További információért a duplex szolgáltatásokról, lásd: Duplex Services.
A WCF-szolgáltatások és -ügyfelek ezen szolgáltatásokhoz való létrehozásáról további információt az alapszintű WCF-programozás, a szolgáltatások tervezése és megvalósítása, valamint az ügyfelek létrehozása című témakörben talál.
DCOM-példakód
Ezekben a forgatókönyvekben a WCF használatával illusztrált DCOM-felületek a következő struktúrával rendelkeznek:
[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
{
}
A szolgáltatás objektumonkénti értéket ad vissza
Ebben a forgatókönyvben hívást kezdeményez egy szolgáltatáshoz, és a metódus egy objektumot ad vissza, amelyet a kiszolgáló átad az ügyfélnek. Ez a forgatókönyv a következő COM-hívást jelenti:
public interface IRemoteService
{
Customer GetObjectByValue();
}
Ebben az esetben az ügyfél megkapja egy objektum deszerializált másolatát a távoli szolgáltatásból. Az ügyfél anélkül használhatja ezt a helyi példányt, hogy visszahívna a szolgáltatásba. Más szóval az ügyfél garantáltan semmilyen módon nem vesz részt a szolgáltatásban a helyi példány metódusainak meghívásakor. A WCF mindig érték szerint ad vissza objektumokat a szolgáltatásból, ezért az alábbi lépések egy normál WCF-szolgáltatás létrehozását írják le.
1. lépés: A WCF szolgáltatás felületének meghatározása
Definiáljon egy nyilvános felületet a WCF szolgáltatáshoz, és jelölje meg a [ServiceContractAttribute] attribútummal. Jelölje meg az ügyfelek számára elérhetővé tenni kívánt metódusokat a [OperationContractAttribute] attribútummal. Az alábbi példa ezeket az attribútumokat mutatja be az ügyfél által meghívható kiszolgálóoldali felületi és felületi metódusok azonosításához. Az ehhez a forgatókönyvhöz használt módszer félkövér színben jelenik meg.
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);
}
2. lépés: Az adatszerződés meghatározása
Ezután létre kell hoznia egy adatszerződést a szolgáltatáshoz, amely leírja, hogyan lesznek kicserélve az adatok a szolgáltatás és ügyfelei között. Az adatszerződésben leírt osztályokat [DataContractAttribute] attribútummal kell megjelölni. Az ügyfél és a kiszolgáló számára is látható egyes tulajdonságokat vagy mezőket [DataMemberAttribute] attribútummal kell megjelölni. Ha engedélyezni szeretné az adatszerződés egyik osztályából származó típusokat, akkor azokat a [KnownTypeAttribute] attribútummal kell azonosítania. A WCF csak szerializálja vagy deszerializálja a szolgáltatási felületen lévő típusokat, és az ismert típusokként azonosított típusokat. Ha olyan típust próbál használni, amely nem ismert típus, kivétel történik.
Az adatszerződésekről további információt az Adatszerződések című témakörben talál.
[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;
}
3. lépés: A WCF szolgáltatás implementálása
Ezután implementálnia kell a WCF szolgáltatásosztályt, amely megvalósítja az előző lépésben definiált felületet.
public class CustomerService: ICustomerManager
{
public void StoreCustomer(Customer customer)
{
// write to a database
}
public Customer GetCustomer(string firstName, string lastName)
{
// read from a database
}
}
4. lépés: A szolgáltatás és az ügyfél konfigurálása
WCF-szolgáltatás futtatásához deklarálnia kell egy végpontot, amely egy adott URL-címen teszi elérhetővé ezt a szolgáltatásfelületet egy adott WCF-kötés használatával. A kötés az ügyfelek és a kiszolgáló kommunikációjának átviteli, kódolási és protokolladatait határozza meg. Általában kötéseket ad hozzá a szolgáltatásprojekt konfigurációs fájljába (web.config). Az alábbiakban a példaszolgáltatáshoz tartozó kötési bejegyzés látható:
<configuration>
<system.serviceModel>
<services>
<service name="Server.CustomerService">
<endpoint address="http://localhost:8083/CustomerManager"
binding="basicHttpBinding"
contract="Shared.ICustomerManager" />
</service>
</services>
</system.serviceModel>
</configuration>
Ezután konfigurálnia kell az ügyfelet, hogy megfeleljen a szolgáltatás által megadott kötési adatoknak. Ehhez adja hozzá a következőket az ügyfél alkalmazáskonfigurációs (app.config) fájljába.
<configuration>
<system.serviceModel>
<client>
<endpoint name="customermanager"
address="http://localhost:8083/CustomerManager"
binding="basicHttpBinding"
contract="Shared.ICustomerManager"/>
</client>
</system.serviceModel>
</configuration>
5. lépés: A szolgáltatás futtatása
Végül önállóan üzemeltetheti egy konzolalkalmazásban azáltal, hogy hozzáadja az alábbi sorokat a szolgáltatásalkalmazáshoz, és elindítja az alkalmazást. További információ a WCF-szolgáltatásalkalmazások üzemeltetésének egyéb módjairól, a Hosting Servicesről.
ServiceHost customerServiceHost = new ServiceHost(typeof(CustomerService));
customerServiceHost.Open();
6. lépés: A szolgáltatás meghívása az ügyfélen keresztül
Ha az ügyféltől szeretné meghívni a szolgáltatást, létre kell hoznia egy csatorna-előállítót a szolgáltatáshoz, és egy csatornát kell kérnie, amely lehetővé teszi a GetCustomer metódus közvetlen meghívását közvetlenül az ügyféltől. A csatorna implementálja a szolgáltatás felületét, és kezeli az alapul szolgáló kérés/válasz logikát. A metódushívás visszatérési értéke a szolgáltatás válaszának deszerializált másolata.
ChannelFactory<ICustomerManager> factory =
new ChannelFactory<ICustomerManager>("customermanager");
ICustomerManager service = factory.CreateChannel();
Customer customer = service.GetCustomer("Mary", "Smith");
Az ügyfél egy értékenkénti objektumot küld a kiszolgálónak
Ebben a forgatókönyvben az ügyfél egy objektumot küld a kiszolgálónak, érték szerint. Ez azt jelenti, hogy a kiszolgáló megkapja az objektum deszerializált másolatát. A kiszolgáló meghívhat metódusokat ezen a példányon, és garantáltan nincs visszahívás az ügyfélkódba. Ahogy korábban említettük, a WCF normál adatcseréi értékenkéntiek. Ez garantálja, hogy a metódusok meghívása ezen objektumok egyikén csak helyileg fut – nem fogja meghívni a kódot az ügyfélen.
Ez a forgatókönyv a következő COM-metódushívást jelenti:
public interface IRemoteService
{
void SendObjectByValue(Customer customer);
}
Ez a forgatókönyv ugyanazt a szolgáltatási felületet és adatszerződést használja, mint az első példában. Emellett az ügyfél és a szolgáltatás ugyanúgy lesz konfigurálva. Ebben a példában egy csatorna jön létre, amely elküldi az objektumot, és ugyanúgy fut. Ebben a példában azonban létre fog hozni egy klienst, amely meghívja a szolgáltatást, és egy objektumot érték szerint ad át. Az ügyfél által a szolgáltatási szerződésben meghívandó szolgáltatásmetódus félkövéren jelenik meg.
[ServiceContract]
public interface ICustomerManager
{
[OperationContract] void StoreCustomer(Customer customer);
[OperationContract]
Customer GetCustomer(string firstName, string lastName);
}
Kód hozzáadása a by-value objektumot küldő ügyfélhez
Az alábbi kód bemutatja, hogyan hoz létre az ügyfél egy új, értékalapú ügyfélobjektumot, hogyan hoz létre egy csatornát a ICustomerManager szolgáltatással való kommunikációhoz, és hogyan küldi el az ügyfélobjektumot.
A rendszerben az ügyfélobjektumot szerializálják és elküldik a szolgáltatásnak, ahol azt a szolgáltatás deszerializálja az objektum egy új példányává. Az objektumon a szolgáltatás által meghívt metódusok csak helyileg lesznek végrehajtva a kiszolgálón. Fontos megjegyezni, hogy ez a kód egy származtatott típus (PremiumCustomer) küldését szemlélteti. A szolgáltatási szerződés objektumot Customer vár, de a szolgáltatási adat szerződés a [KnownTypeAttribute] attribútummal jelzi, hogy PremiumCustomer szintén megengedett. A WCF nem próbálja szerializálni vagy deszerializálni bármely más típust ezen a szolgáltatási felületen keresztül.
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);
A szolgáltatás egy objektumot ad vissza hivatkozás alapján
Ebben az esetben az ügyfélalkalmazás hívást kezdeményez a távoli szolgáltatáshoz, a metódus pedig egy objektumot ad vissza, amelyet a szolgáltatás hivatkozása továbbít az ügyfélnek.
Ahogy korábban említettük, a WCF-szolgáltatások mindig érték szerint adnak vissza objektumot. Azonban a EndpointAddress10 osztály használatával hasonló eredményt érhet el. Ez EndpointAddress10 egy szerializálható érték szerinti objektum, amelyet az ügyfél használhat, hogy egy munkamenet-alapú referencia szerinti objektumot szerezzen be a kiszolgálón.
Az ebben a forgatókönyvben bemutatott, a WCF-ben található by-reference objektum viselkedése eltér a DCOM-tól. A DCOM-ban a kiszolgáló közvetlenül vissza tud adni egy referenciaobjektumot az ügyfélnek, és az ügyfél meghívhatja az objektum metódusát, amely a kiszolgálón fut. A WCF-ben azonban a visszaadott objektum mindig érték szerint adódik vissza. Az ügyfélnek meg kell szereznie azt a by-value objektumot, amelyet a EndpointAddress10 jelöl, majd azt a saját munkamenet-alapú hivatkozási objektumának létrehozására kell használnia. Az ügyfélmetódus meghívja a kiszolgálón végrehajtott munkamenet-objektumot. Más szóval a WCF-ben ez a referencia-objektum egy normál WCF-szolgáltatás, amely munkamenet-alapúra van konfigurálva.
A WCF-ben a munkamenet a két végpont között küldött több üzenet korrelációjának módja. Ez azt jelenti, hogy ha egy ügyfél kapcsolatot szerez ezzel a szolgáltatással, létrejön egy munkamenet az ügyfél és a kiszolgáló között. Az ügyfél a kiszolgálóoldali objektum egyetlen egyedi példányát fogja használni az egyetlen munkameneten belüli összes interakcióhoz. A munkamenet-alapú WCF-szerződések hasonlóak a kapcsolatorientált hálózati kérés-/válaszmintákhoz.
Ezt a forgatókönyvet a következő DCOM-metódus képviseli.
public interface IRemoteService
{
IRemoteObject GetObjectByReference();
}
1. lépés: A munkamenet-alapú WCF szolgáltatás felületének és implementációjának meghatározása
Először definiáljon egy WCF-szolgáltatásfelületet, amely tartalmazza a munkamenet-alapú objektumot.
Ebben a kódban a munkamenet-objektumot az ServiceContract attribútum jelöli meg, amely normál WCF-szolgáltatási felületként azonosítja azt. Emellett a SessionMode tulajdonság úgy van beállítva, hogy azt jelezze, hogy munkamenet-alapú szolgáltatás lesz.
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface ISessionBoundObject
{
[OperationContract]
string GetCurrentValue();
[OperationContract]
void SetCurrentValue(string value);
}
Az alábbi kód a szolgáltatás implementálását mutatja be.
A szolgáltatás a [ServiceBehavior] attribútummal van megjelölve, az InstanceContextMode.PerSessions értékre állított InstanceContextMode tulajdonság pedig azt jelzi, hogy minden munkamenethez létre kell hozni egy ilyen típusú egyedi példányt.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MySessionBoundObject : ISessionBoundObject
{
private string _value;
public string GetCurrentValue()
{
return _value;
}
public void SetCurrentValue(string val)
{
_value = val;
}
}
2. lépés: A munkamenetes objektum WCF-gyárszolgáltatásának definiálása
A munkamenet-objektumot létrehozó szolgáltatást meg kell határozni és végre kell hajtani. Az alábbi kód bemutatja, hogyan teheti ezt meg. Ez a kód létrehoz egy másik WCF-szolgáltatást, amely egy objektumot EndpointAddress10 ad vissza. Ez egy olyan végpont szerializálható formája, amellyel létrehozhatja a munkamenet-teljes objektumot.
[ServiceContract]
public interface ISessionBoundFactory
{
[OperationContract]
EndpointAddress10 GetInstanceAddress();
}
A következő a szolgáltatás implementálása. Ez az implementáció egy singleton csatorna gyárat tart fenn munkamenet-objektumok létrehozásához. Amikor GetInstanceAddress meghívják, létrehoz egy csatornát, és létrehoz egy EndpointAddress10 objektumot, amely a csatornához társított távoli címre mutat.
EndpointAddress10 olyan adattípus, amely visszaadható az ügyfélnek érték szerint.
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);
}
}
3. lépés: A WCF-szolgáltatások konfigurálása és elindítása
A szolgáltatások üzemeltetéséhez a következő kiegészítéseket kell elvégeznie a kiszolgáló konfigurációs fájljában (web.config).
Adjon hozzá egy szakaszt
<client>, amely leírja a munkamenet-objektum végpontját. Ebben az esetben a kiszolgáló ügyfélként is működik, és konfigurálva kell lennie ennek engedélyezéséhez.A szakaszban deklarálja a
<services>gyári és a munkamenet-alapú objektum szolgáltatásvégpontjait. Ez lehetővé teszi az ügyfél számára a szolgáltatásvégpontokkal való kommunikációt, a EndpointAddress10 munkamenet-alapú csatorna beszerzését és létrehozását.
Az alábbi példakonfigurációs fájl az alábbi beállításokkal rendelkezik:
<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>
Adja hozzá a következő sorokat egy konzolalkalmazáshoz a szolgáltatás önkiszolgáló üzemeltetéséhez és az alkalmazás elindításához.
ServiceHost factoryHost = new ServiceHost(typeof(SessionBoundFactory));
factoryHost.Open();
ServiceHost sessionBoundServiceHost = new ServiceHost(
typeof(MySessionBoundObject));
sessionBoundServiceHost.Open();
4. lépés: Az ügyfél konfigurálása és a szolgáltatás meghívása
Konfigurálja az ügyfelet a WCF-szolgáltatásokkal való kommunikációra a projekt alkalmazáskonfigurációs fájljának következő bejegyzéseivel (app.config).
<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>
A szolgáltatás meghívásához adja hozzá a kódot az ügyféloldali alkalmazáshoz a következők végrehajtásához:
Hozzon létre egy csatornát a
ISessionBoundFactoryszolgáltatáshoz.A csatornát használva meghívhatja a
ISessionBoundFactoryszolgáltatást, és megszerezhet egy EndpointAddress10 objektumot.Használja a EndpointAddress10 egy csatorna létrehozásához egy munkamenethez kötődő objektum beszerzéséhez.
Hívja meg a
SetCurrentValueésGetCurrentValuemetódusokat annak bemutatására, hogy ugyanaz az objektumpéldány kerül felhasználásra több hívás során.
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");
}