Nasıl yapılır: Yönetilen Kodu DCOM’dan WCF’ye Geçirme
Windows Communication Foundation (WCF), dağıtılmış bir ortamdaki sunucular ve istemciler arasında yönetilen kod çağrıları için Dağıtılmış Bileşen Nesne Modeli (DCOM) yerine önerilen ve güvenli seçimdir. Bu makalede, aşağıdaki senaryolar için kodu DCOM'dan WCF'ye nasıl geçireceğiniz gösterilmektedir.
Uzak hizmet istemciye değere göre bir nesne döndürür
İstemci uzak hizmete değere göre bir nesne gönderir
Uzak hizmet, istemciye bir nesne başvurusu döndürür
Güvenlik nedeniyle, wcf'de istemciden hizmete bir nesnenin başvuruya gönderilmesine izin verilmez. wcf'de çift yönlü hizmet kullanılarak istemci ve sunucu arasında ileri geri konuşma gerektiren bir senaryo elde edilebilir. Çift yönlü hizmetler hakkında daha fazla bilgi için bkz . Çift Yönlü Hizmetler.
Bu hizmetler için WCF hizmetleri ve istemcileri oluşturma hakkında daha fazla bilgi için bkz . Temel WCF Programlama, Hizmetleri Tasarlama ve Uygulama ve İstemci Oluşturma.
DCOM örnek kodu
Bu senaryolar için WCF kullanılarak gösterilen DCOM arabirimleri aşağıdaki yapıya sahiptir:
[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
{
}
Hizmet, değere göre bir nesne döndürür
Bu senaryo için bir hizmete çağrı yaparsınız ve bu yöntem sunucudan istemciye değer tarafından geçirilen bir nesnesi döndürür. Bu senaryo aşağıdaki COM çağrısını temsil eder:
public interface IRemoteService
{
Customer GetObjectByValue();
}
Bu senaryoda istemci, uzak hizmetten bir nesnenin seri durumdan çıkarılmış bir kopyasını alır. İstemci, hizmete geri dönmeden bu yerel kopyayla etkileşimde bulunabilir. Başka bir deyişle, istemcinin yerel kopyadaki yöntemler çağrıldığında hizmetin hiçbir şekilde dahil edilmeyecek olması garanti edilir. WCF her zaman hizmetten nesneleri değere göre döndürür, bu nedenle aşağıdaki adımlar normal bir WCF hizmeti oluşturmayı açıklar.
1. Adım: WCF hizmet arabirimini tanımlama
WCF hizmeti için bir ortak arabirim tanımlayın ve [ServiceContractAttribute] özniteliğiyle işaretleyin. İstemcilere göstermek istediğiniz yöntemleri [OperationContractAttribute] özniteliğiyle işaretleyin. Aşağıdaki örnekte, bir istemcinin çağırabileceği sunucu tarafı arabirimini ve arabirim yöntemlerini tanımlamak için bu özniteliklerin kullanılması gösterilmektedir. Bu senaryo için kullanılan yöntem kalın olarak gösterilir.
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. Adım: Veri sözleşmesini tanımlama
Daha sonra hizmet için verilerin hizmetle istemcileri arasında nasıl değiş tokuş yapılacağını açıklayan bir veri sözleşmesi oluşturmanız gerekir. Veri sözleşmesinde açıklanan sınıflar [DataContractAttribute] özniteliğiyle işaretlenmelidir. hem istemci hem de sunucu tarafından görünmesini istediğiniz tek tek özellikler veya alanlar [DataMemberAttribute] özniteliğiyle işaretlenmelidir. Veri sözleşmesindeki bir sınıftan türetilen türlere izin vermek istiyorsanız, bunları [KnownTypeAttribute] özniteliğiyle tanımlamanız gerekir. WCF yalnızca hizmet arabirimindeki türleri ve bilinen türler olarak tanımlanan türleri serileştirir veya seri durumdan çıkartır. Bilinen bir tür olmayan bir tür kullanmayı denerseniz, bir özel durum oluşur.
Veri sözleşmeleri hakkında daha fazla bilgi için bkz . Veri Sözleşmeleri.
[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. Adım: WCF hizmetini uygulama
Ardından, önceki adımda tanımladığınız arabirimi uygulayan WCF hizmet sınıfını uygulamanız gerekir.
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. Adım: Hizmeti ve istemciyi yapılandırma
WCF hizmetini çalıştırmak için, belirli bir WCF bağlamasını kullanarak bu hizmet arabirimini belirli bir URL'de kullanıma sunan bir uç nokta bildirmeniz gerekir. Bağlama, istemcilerin ve sunucunun iletişim kurması için aktarım, kodlama ve protokol ayrıntılarını belirtir. Genellikle hizmet projesinin yapılandırma dosyasına (web.config) bağlamalar eklersiniz. Aşağıda örnek hizmet için bir bağlama girdisi gösterilmektedir:
<configuration>
<system.serviceModel>
<services>
<service name="Server.CustomerService">
<endpoint address="http://localhost:8083/CustomerManager"
binding="basicHttpBinding"
contract="Shared.ICustomerManager" />
</service>
</services>
</system.serviceModel>
</configuration>
Ardından, istemciyi hizmet tarafından belirtilen bağlama bilgileriyle eşleşecek şekilde yapılandırmanız gerekir. Bunu yapmak için istemcinin uygulama yapılandırması (app.config) dosyasına aşağıdakileri ekleyin.
<configuration>
<system.serviceModel>
<client>
<endpoint name="customermanager"
address="http://localhost:8083/CustomerManager"
binding="basicHttpBinding"
contract="Shared.ICustomerManager"/>
</client>
</system.serviceModel>
</configuration>
5. Adım: Hizmeti çalıştırma
Son olarak, hizmet uygulamasına aşağıdaki satırları ekleyerek ve uygulamayı başlatarak konsol uygulamasında kendi kendine barındırabilirsiniz. WcF hizmet uygulamasını barındırmanın diğer yolları hakkında daha fazla bilgi için, Barındırma Hizmetleri.
ServiceHost customerServiceHost = new ServiceHost(typeof(CustomerService));
customerServiceHost.Open();
6. Adım: İstemciden hizmeti çağırma
İstemciden hizmeti çağırmak için hizmet için bir kanal fabrikası oluşturmanız ve bir kanal istemeniz gerekir; bu da doğrudan istemciden yöntemini çağırmanızı GetCustomer
sağlar. Kanal, hizmetin arabirimini uygular ve temel istek/yanıt mantığını sizin için işler. Bu yöntem çağrısının dönüş değeri, hizmet yanıtının seri durumdan çıkarılmış kopyasıdır.
ChannelFactory<ICustomerManager> factory =
new ChannelFactory<ICustomerManager>("customermanager");
ICustomerManager service = factory.CreateChannel();
Customer customer = service.GetCustomer("Mary", "Smith");
İstemci sunucuya değere göre bir nesne gönderir
Bu senaryoda, istemci sunucuya değere göre bir nesne gönderir. Bu, sunucunun nesnenin seri durumdan çıkarılmış bir kopyasını alacağı anlamına gelir. Sunucu bu kopyadaki yöntemleri çağırabilir ve istemci koduna geri çağrı yapılmayacağı garanti edilir. Daha önce belirtildiği gibi, normal WCF veri değişimleri değere göre yapılır. Bu, bu nesnelerden birinde çağrılan yöntemlerin yalnızca yerel olarak yürütülmesini garanti eder; istemcide kod çağırmaz.
Bu senaryo aşağıdaki COM yöntemi çağrısını temsil eder:
public interface IRemoteService
{
void SendObjectByValue(Customer customer);
}
Bu senaryo, ilk örnekte gösterildiği gibi aynı hizmet arabirimini ve veri sözleşmesini kullanır. Ayrıca, istemci ve hizmet de aynı şekilde yapılandırılır. Bu örnekte, nesneyi göndermek ve aynı şekilde çalıştırmak için bir kanal oluşturulur. Ancak, bu örnekte, bir nesneyi değere göre geçirerek hizmeti çağıran bir istemci oluşturacaksınız. İstemcinin hizmet sözleşmesinde çağıracağı hizmet yöntemi kalın olarak gösterilir:
[ServiceContract]
public interface ICustomerManager
{
[OperationContract] void StoreCustomer(Customer customer);
[OperationContract]
Customer GetCustomer(string firstName, string lastName);
}
İstemciye değere göre nesne gönderen kod ekleme
Aşağıdaki kodda, istemcinin yeni bir değere göre müşteri nesnesi oluşturması, hizmetle iletişim kurmak için bir kanal oluşturması ICustomerManager
ve müşteri nesnesini buna göndermesi gösterilmektedir.
Müşteri nesnesi seri hale getirilir ve hizmet tarafından seri durumdan çıkarılarak bu nesnenin yeni bir kopyasına gönderilir. Hizmetin bu nesnede çağıracağı tüm yöntemler yalnızca sunucuda yerel olarak yürütülür. Bu kodun türetilmiş bir tür (PremiumCustomer
) göndermeyi gösterdiğini unutmayın. Hizmet sözleşmesi bir Customer
nesne bekler, ancak hizmet veri sözleşmesi de izin verildiğini PremiumCustomer
belirtmek için [KnownTypeAttribute] özniteliğini kullanır. WCF, bu hizmet arabirimi aracılığıyla başka bir türü seri hale getirme veya seri durumdan çıkarma girişimlerinde başarısız olur.
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);
Hizmet, başvuruya göre bir nesne döndürür
Bu senaryo için istemci uygulaması uzak hizmete bir çağrı yapar ve yöntemi, hizmetten istemciye başvuru ile geçirilen bir nesnesi döndürür.
Daha önce belirtildiği gibi WCF hizmetleri her zaman değere göre nesne döndürür. Ancak, sınıfını EndpointAddress10 kullanarak benzer bir sonuç elde edebilirsiniz. , EndpointAddress10 istemci tarafından sunucuda oturumlu bir başvuruya göre nesnesi elde etmek için kullanılabilecek serileştirilebilir bir değere göre nesnesidir.
Bu senaryoda gösterilen WCF'deki başvuru nesnesinin davranışı DCOM'dan farklıdır. DCOM'da, sunucu doğrudan istemciye bir başvuru nesnesi döndürebilir ve istemci bu nesnenin sunucuda yürütülen yöntemlerini çağırabilir. Ancak WCF'de döndürülen nesne her zaman değere göredir. İstemci tarafından temsil edilen EndpointAddress10 bu değere göre nesnesini almalı ve kendi oturumlu başvuru nesnesi oluşturmak için bu nesneyi kullanmalıdır. İstemci yöntemi, sunucuda yürütülen oturumlu nesne üzerinde çağrılar. Başka bir deyişle, WCF'deki bu başvuru nesnesi oturumlu olacak şekilde yapılandırılmış normal bir WCF hizmetidir.
WCF'de oturum, iki uç nokta arasında gönderilen birden çok iletiyi ilişkilendirmenin bir yoludur. Bu, bir istemci bu hizmete bir bağlantı edindikten sonra istemci ile sunucu arasında bir oturum kurulacağı anlamına gelir. İstemci, bu tek oturumdaki tüm etkileşimleri için sunucu tarafı nesnesinin tek bir benzersiz örneğini kullanır. Oturumlu WCF sözleşmeleri, bağlantı odaklı ağ isteği/yanıt desenlerine benzer.
Bu senaryo aşağıdaki DCOM yöntemiyle temsil edilir.
public interface IRemoteService
{
IRemoteObject GetObjectByReference();
}
1. Adım: Oturumlu WCF hizmet arabirimini ve uygulamasını tanımlama
İlk olarak, oturumlu nesnesini içeren bir WCF hizmet arabirimi tanımlayın.
Bu kodda, oturumlu nesne, onu normal bir WCF hizmet arabirimi olarak tanımlayan özniteliğiyle ServiceContract
işaretlenir. Buna ek olarak, SessionMode özelliği oturumlu bir hizmet olacağını belirtmek için ayarlanır.
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface ISessionBoundObject
{
[OperationContract]
string GetCurrentValue();
[OperationContract]
void SetCurrentValue(string value);
}
Aşağıdaki kod hizmet uygulamasını gösterir.
Hizmet [ServiceBehavior] özniteliğiyle işaretlenir ve instanceContextMode özelliği InstanceContextMode.PerSessions olarak ayarlanır ve bu türün benzersiz bir örneğinin her oturum için oluşturulması gerektiğini belirtir.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MySessionBoundObject : ISessionBoundObject
{
private string _value;
public string GetCurrentValue()
{
return _value;
}
public void SetCurrentValue(string val)
{
_value = val;
}
}
2. Adım: Oturumlu nesne için WCF fabrika hizmetini tanımlama
Oturumlu nesneyi oluşturan hizmet tanımlanmalı ve uygulanmalıdır. Aşağıdaki kod bunun nasıl yapılacağını gösterir. Bu kod, nesne döndüren başka bir EndpointAddress10 WCF hizmeti oluşturur. Bu, oturumun tam nesnesini oluşturmak için kullanabileceği bir uç noktanın serileştirilebilir bir biçimidir.
[ServiceContract]
public interface ISessionBoundFactory
{
[OperationContract]
EndpointAddress10 GetInstanceAddress();
}
Aşağıda bu hizmetin uygulanması yer alır. Bu uygulama, oturumlu nesneler oluşturmak için tek kanallı bir fabrika tutar. Çağrıldığında GetInstanceAddress
, bir kanal oluşturur ve bu kanalla ilişkilendirilmiş uzak adrese işaret eden bir EndpointAddress10 nesne oluşturur. EndpointAddress10 , istemciye değere göre döndürülebilen bir veri türüdür.
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. Adım: WCF hizmetlerini yapılandırma ve başlatma
Bu hizmetleri barındırmak için sunucunun yapılandırma dosyasına (web.config) aşağıdaki eklemeleri yapmanız gerekir.
Oturumlu nesnenin uç noktasını açıklayan bir
<client>
bölüm ekleyin. Bu senaryoda, sunucu aynı zamanda bir istemci işlevi görür ve bunu etkinleştirmek için yapılandırılması gerekir.<services>
bölümünde, fabrika ve oturumlu nesne için hizmet uç noktalarını bildirin. Bu, istemcinin hizmet uç noktalarıyla iletişim kurmasını, oturumlu kanalı almasını EndpointAddress10 ve oluşturmasını sağlar.
Aşağıda, bu ayarlara sahip örnek bir yapılandırma dosyası verilmiştir:
<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>
Hizmeti kendi kendine barındırmak ve uygulamayı başlatmak için bir konsol uygulamasına aşağıdaki satırları ekleyin.
ServiceHost factoryHost = new ServiceHost(typeof(SessionBoundFactory));
factoryHost.Open();
ServiceHost sessionBoundServiceHost = new ServiceHost(
typeof(MySessionBoundObject));
sessionBoundServiceHost.Open();
4. Adım: İstemciyi yapılandırma ve hizmeti çağırma
Projenin uygulama yapılandırma dosyasında (app.config) aşağıdaki girişleri yaparak istemciyi WCF hizmetleriyle iletişim kuracak şekilde yapılandırın.
<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>
Hizmeti çağırmak için, aşağıdakileri yapmak için istemciye kodu ekleyin:
Hizmete bir kanal
ISessionBoundFactory
oluşturun.Hizmeti çağırmak
ISessionBoundFactory
için kanalı kullanın ve bir EndpointAddress10 nesne alın.Oturumlu bir nesne almak üzere bir kanal oluşturmak için öğesini EndpointAddress10 kullanın.
SetCurrentValue
Birden çok çağrıda aynı nesne örneğinin kullanıldığını göstermek için veGetCurrentValue
yöntemlerini çağırı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");
}