Обычно WCF делался так — в сборке публиковались интерфейсы, определялись атрибуты [ServiceContract], [DataContract] и так далее, писалась реализация, после чего откомпилированная сборка шла в svcutil, оттуда выдавались классы, которые можно было инстанцировать из клиента.
А можно ли сделать разделяемую сборку, в которой опубликовать все интерфейсы, чтобы и клиент и сервер ссылались на эту сборку и использовали один набор интерфейсов для работы, а не прокси-заменитель?
Ключ /reference для svcutil смотрите.
В самой студии на вкладке генерации прокси есть галка Use types in refrenced assemblies.
А можно вообще без генерации прокси обойтись, если строить канал через ChanellFactory (нужны будут только интерфейсы).
Здравствуйте, Аноним, Вы писали:
А>Обычно WCF делался так — в сборке публиковались интерфейсы, определялись атрибуты [ServiceContract], [DataContract] и так далее, писалась реализация, после чего откомпилированная сборка шла в svcutil, оттуда выдавались классы, которые можно было инстанцировать из клиента.
А>А можно ли сделать разделяемую сборку, в которой опубликовать все интерфейсы, чтобы и клиент и сервер ссылались на эту сборку и использовали один набор интерфейсов для работы, а не прокси-заменитель?
Можно. Что-то типа:
ICalculator.cs
using System.ServiceModel;
namespace WcfExample.Contracts
{
[ServiceContract]
public interface ICalculator
{
[OperationContract]
double Add(double a, double b);
}
}
MyCloudCalculator.cs
using WcfExample.Contracts;
namespace WcfExample.Service
{
public class MyCloudCalculator : ICalculator
{
public double Add(double a, double b)
{
return a + b;
}
}
}
Program.cs на сервере:
using System;
using System.ServiceModel;
namespace WcfExample.Service
{
class Program
{
static int Main(string[] args)
{
try
{
var host = new ServiceHost(typeof (MyCloudCalculator));
host.Open();
Console.WriteLine("Started");
Console.ReadLine();
return 0;
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
return -1;
}
}
}
}
Program.cs на клиенте:
using System;
using System.ServiceModel;
using WcfExample.Contracts;
namespace WcfExample.Client
{
class Program
{
static int Main(string[] args)
{
try
{
var channelFactory = new ChannelFactory<ICalculator>("CalculatorEndpoint");
var client = channelFactory.CreateChannel();
var result = client.Add(1, 2);
Console.WriteLine("Result = {0}", result);
Console.ReadLine();
return 0;
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
return -1;
}
}
}
}
Солить App.config-и по вкусу.
Re[2]: WCF с разделяемой интерфейсной сборкой
От:
Аноним
Дата:
15.11.10 17:59
Оценка:
Здравствуйте, anton_t, Вы писали:
_>Здравствуйте, Аноним, Вы писали:
Да, я только что по наводке RushDevion написал аналогичную вещь, только воспользовался статической фабрикой
var channel = ChannelFactory<IWhatever>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(@"net.pipe://localhost/whatever"));
Спасибо за код.
Кстати, как лучше поступить? Держать открытой фабрику, создавая у нее каналы по мере надобности, создавать каналы через статический метод, или же вообще удерживать инстанс канала насколько это возможно? Приложение не нагруженное, но не хотелось бы тормозов из-за ерунды.
Re[2]: WCF с разделяемой интерфейсной сборкой
От:
Аноним
Дата:
15.11.10 18:04
Оценка:
Здравствуйте, RushDevion, Вы писали:
RD>Ключ /reference для svcutil смотрите. RD>В самой студии на вкладке генерации прокси есть галка Use types in refrenced assemblies. RD>А можно вообще без генерации прокси обойтись, если строить канал через ChanellFactory (нужны будут только интерфейсы).
Нужно ли в случае постройки канала через фабрику специфицировать дата-контракты? В тестовом примере
[ServiceContract]
public interface IWhatever
{
[OperationContract]
DataMessage Do(DataMessage what);
}
public class DataMessage
{
public string Message { get; set; }
}
public class Whatever : IWhatever
{
public DataMessage Do(DataMessage what) { return new DataMessage() { Message = what.Message + " DONE" }; }
}
public class Program
{
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(Whatever), new Uri(@"net.pipe://localhost/whatever")))
{
host.Open();
Thread t = new Thread(RCV);
t.Start();
Console.ReadLine();
}
}
static void RCV()
{
var channel = ChannelFactory<IWhatever>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(@"net.pipe://localhost/whatever"));
Console.WriteLine(channel.Do(new DataMessage() { Message = "SHIT" }).Message);
}
}
А>Кстати, как лучше поступить? Держать открытой фабрику, создавая у нее каналы по мере надобности, создавать каналы через статический метод, или же вообще удерживать инстанс канала насколько это возможно? Приложение не нагруженное, но не хотелось бы тормозов из-за ерунды.
Конструирование фабрики — довольно затратная операция — лучше ее переиспользовать по возможности. Вот здесь посмотрите подробнее на этот счет.
> Нужно ли в случае постройки канала через фабрику специфицировать дата-контракты? В тестовом примере > Заработало и без них.
Не могу прокоментировать. Видимо сериалайзеру хватает ума разобраться с этим.
Но я бы советовал в любом случае задавать датаконтракты — хотя бы чтобы пространство имен определять (для сервиса, кстати, тоже).