Я не собирался отвечать на этот вопрос, так как вы уже ответили на него, (а это, ну, что? Прошло 2,5 года! ») Но есть ВСЕГДА те люди, которые ищут эту же тему и читают ответы ...
Для того, чтобы мой сервис мог взаимодействовать с рабочим столом, не важно, ЧТО рабочий стол, ни МНОГО рабочих столов, ни сервис, даже запущенный на ОДНОМ ЖЕ КОМПЬЮТЕРЕ в качестве настольного приложения !! Ничто из этого не имеет отношения к тому, что я получил здесь ... Я не буду утомлять вас деталями, я просто дам вам мясо и картошку, а вы и дайте мне знать, если вы хотите увидеть больше ...
Хорошо. Первым делом я создал рекламный сервис . Это поток, который запускает служба, открывает UDP-сокет для прослушивания трансляций в сети. Затем, используя тот же фрагмент кода, я поделился им с клиентским приложением, но оно вызывает Advertise.CLIENT , а не Advertise.SERVER ... КЛИЕНТ открывает порт Я ожидаю, что служба будет включена, и рассылает сообщение «Здравствуйте ... Есть ли кто-нибудь там?», Спрашивая, слушают ли они ЛЮБЫЕ серверы, и если да, ответьте на ЭТОТ IP-адрес с вашего компьютера. имя, IP-адрес и номер порта, где я могу найти .NET Remoting Services ... "Затем он ожидает небольшой промежуток времени ожидания, собирает полученные ответы, а если их больше одного, он представляет пользователю с диалоговым окном и списком сервисов, которые ответили ... Затем клиент выбирает один или, если ответил только ОДИН, он вызовет Connect ( (TServerResponse) res); для этого необходимо подключиться На этом этапе сервер использует службы удаленного взаимодействия с WellKnownClientType и WellKnownServerType, чтобы выставить себя ...
Я не думаю, что вы слишком заинтересованы в моем "локаторе автосервиса", потому что многие люди недовольны UDP, особенно когда ваше приложение начинает вещание в больших сетях. Итак, я предполагаю, что вас больше заинтересует мой RemotingHelper, который подключит клиента к серверу. Это выглядит так:
public static Object GetObject(Type type)
{
try {
if(_wellKnownTypes == null) {
InitTypeCache();
}
WellKnownClientTypeEntry entr = (WellKnownClientTypeEntry)_wellKnownTypes[type];
if(entr == null) {
throw new RemotingException("Type not found!");
}
return System.Activator.GetObject(entr.ObjectType, entr.ObjectUrl);
} catch(System.Net.Sockets.SocketException sex) {
DebugHelper.Debug.OutputDebugString("SocketException occured in RemotingHelper::GetObject(). Error: {0}.", sex.Message);
Disconnect();
if(Connect()) {
return GetObject(type);
}
}
return null;
}
private static void InitTypeCache()
{
if(m_AdvertiseServer == null) {
throw new RemotingException("AdvertisementServer cannot be null when connecting to a server.");
}
_wellKnownTypes = new Dictionary<Type, WellKnownClientTypeEntry>();
Dictionary<string, object> channelProperties = new Dictionary<string, object>();
channelProperties["port"] = 0;
channelProperties["name"] = m_AdvertiseServer.ChannelName;
Dictionary<string, object> binFormatterProperties = new Dictionary<string, object>();
binFormatterProperties["typeFilterLevel"] = "Full";
if(Environment.UserInteractive) {
BinaryServerFormatterSinkProvider binFormatterProvider = new BinaryServerFormatterSinkProvider(binFormatterProperties, null);
_serverChannel = new TcpServerChannel(channelProperties, binFormatterProvider);
// LEF: Only if we are coming form OUTSIDE the SERVICE do we want to register the channel, since the SERVICE already has this
// channel registered in this AppDomain.
ChannelServices.RegisterChannel(_serverChannel, false);
}
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IPawnStatServiceStatus)));
RegisterType(typeof(IPawnStatServiceStatus),m_AdvertiseServer.RunningStatusURL.ToString());
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IPawnStatService)));
RegisterType(typeof(IPawnStatService), m_AdvertiseServer.RunningServerURL.ToString());
System.Diagnostics.Debug.Write(string.Format("Registering: {0}...\n", typeof(IServiceConfiguration)));
RegisterType(typeof(IServiceConfiguration), m_AdvertiseServer.RunningConfigURL.ToString());
}
[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration, RemotingConfiguration=true)]
public static void RegisterType(Type type, string serviceUrl)
{
WellKnownClientTypeEntry clientType = new WellKnownClientTypeEntry(type, serviceUrl);
if(clientType != RemotingConfiguration.IsWellKnownClientType(type)) {
RemotingConfiguration.RegisterWellKnownClientType(clientType);
}
_wellKnownTypes[type] = clientType;
}
public static bool Connect()
{
// Init the Advertisement Service, and Locate any listening services out there...
m_AdvertiseServer.InitClient();
if(m_AdvertiseServer.LocateServices(iTimeout)) {
if(!Connected) {
bConnected = true;
}
} else {
bConnected = false;
}
return Connected;
}
public static void Disconnect()
{
if(_wellKnownTypes != null) {
_wellKnownTypes.Clear();
}
_wellKnownTypes = null;
if(_serverChannel != null) {
if(Environment.UserInteractive) {
// LEF: Don't unregister the channel, because we are running from the service, and we don't want to unregister the channel...
ChannelServices.UnregisterChannel(_serverChannel);
// LEF: If we are coming from the SERVICE, we do *NOT* want to unregister the channel, since it is already registered!
_serverChannel = null;
}
}
bConnected = false;
}
}
Итак, это основа моего удаленного кода, и он позволил мне написать клиента, который не должен был знать, где установлены службы или сколько служб запущено в сети. Это позволило мне общаться с ним по сети или на локальной машине. И это не было проблемой, если бы два или более человек работали с приложением, однако, это возможно. Теперь у меня есть некоторый сложный код обратного вызова, в котором я регистрирую события для прохождения через канал удаленного взаимодействия, поэтому мне нужно иметь код, который проверяет, подключен ли клиент, прежде чем отправлять уведомление клиенту о том, что что-то произошло , Кроме того, если вы работаете более чем с одним пользователем, вы можете не использовать объекты Singleton. Это было хорошо для меня, потому что сервер СОБСТВЕННЫЙ объектов, и они являются тем, что сервер говорит, что они есть. Итак, мой объект STATS, например, является Singleton. Нет причин создавать его экземпляр для КАЖДОГО соединения, когда все будут видеть одни и те же данные, верно?
Я могу предоставить больше кусков кода, если это необходимо. Это, конечно, один крошечный кусочек общей картины того, что делает эту работу ... Не говоря уже о поставщиках подписки и все такое.
Для полноты картины я включаю фрагмент кода, чтобы поддерживать подключение службы в течение всего процесса.
public override object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if(lease.CurrentState == LeaseState.Initial) {
lease.InitialLeaseTime = TimeSpan.FromHours(24);
lease.SponsorshipTimeout = TimeSpan.FromSeconds(30);
lease.RenewOnCallTime = TimeSpan.FromHours(1);
}
return lease;
}
#region ISponsor Members
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
public TimeSpan Renewal(ILease lease)
{
return TimeSpan.FromHours(12);
}
#endregion
Если вы включите интерфейс ISponsor как часть вашего серверного объекта, вы можете реализовать приведенный выше код.
Надеюсь, некоторые из них полезны.