Можно предоставить MarshalByRefObjects, которые имеют конструкторы с параметрами, вместо удаленного взаимодействия, и пользователи класса могут иметь дело только с его интерфейсом.
Я создал небольшое доказательство концепции проекта. Он имеет 3 проекта: сервер, клиент и ядро. Сервер и клиент ссылаются на ядро, но не ссылаются друг на друга.
В ядре мы определяем сервисный интерфейс:
namespace Core
{
public interface ICountingService
{
int Increment();
}
}
Сервер определяет конкретную реализацию, на которую у клиента нет ссылки:
namespace Server
{
public class CountingService : MarshalByRefObject, ICountingService
{
private static int _value = 0;
public CountingService(int startValue)
{
_value = startValue;
}
public int Increment()
{ // not threadsafe!
_value++;
return _value;
}
}
}
Важно отметить, что у него есть конструктор с параметром, это MarshalByRefObject, и он реализует интерфейс в основном проекте.
Проект сервера — это консольное приложение, которое настраивает канал удаленного взаимодействия (произвольно через HTTP в этом примере), создает службу и регистрирует ее с помощью удаленного взаимодействия:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
namespace Server
{
class Program
{
static void Main(string[] args)
{
HttpServerChannel serverChannel = new HttpServerChannel(8234);
ChannelServices.RegisterChannel(serverChannel, false);
// Following line won't work at runtime as there is no parameterless constructor
//RemotingConfiguration.RegisterWellKnownServiceType(typeof(CountingService),
// "CountingService.rem", WellKnownObjectMode.Singleton);
CountingService countingService = new CountingService(5);
RemotingServices.Marshal(countingService, "CountingService.rem");
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
}
}
Вышеприведенный код зарегистрировал URL-адрес http://localhost:8234/CountingService.rem, который содержит экземпляр службы. , который начнет отсчет с 5.
Затем клиент, также являющийся консольным приложением, может получить ссылку, используя класс интерфейса:
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using Core;
namespace Client
{
class Program
{
static void Main(string[] args)
{
HttpClientChannel serverChannel = new HttpClientChannel();
ChannelServices.RegisterChannel(serverChannel, false);
for (int i = 0; i < 5; i++)
{
ICountingService countingService =
(ICountingService)Activator.GetObject(typeof(ICountingService),
"http://localhost:8234/CountingService.rem");
int newValue = countingService.Increment();
Console.WriteLine("Value is " + newValue);
}
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
}
}
Когда сервер и клиент запущены, они печатают значения от 6 до 10.
Резюме: клиент знает только об интерфейсе; конструктор реализации может иметь параметры; создание экземпляров может контролироваться вашим собственным кодом, а не .NET. Очень полезно при работе с внедрением зависимостей на основе конструктора с удаленными объектами.
person
Daniel Flower
schedule
21.01.2010