Если уже есть WCF-сервер, прослушивающий конечную точку именованного канала, будет создан объект общей памяти, через который сервер публикует фактическое имя канала. Подробнее об этом .
Вы можете проверить существование этого объекта общей памяти с помощью кода, подобного следующему, который не будет выдавать, просто вернет false, если сервер еще не запущен. (Я извлек это из кода, который у меня уже работает, а затем отредактировал его, чтобы сделать то, что вы хотите - но без тестирования отредактированной версии, поэтому извиняюсь, если вам нужно исправить сборку / ссылки на пространство имен и т. Д., Чтобы запустить его.) 1005 *
public static class ServiceInstanceChecker
{
public static bool DoesAServerExistAlready(string hostName, string path)
{
return IsNetNamedPipeSharedMemoryMetaDataPublished(DeriveSharedMemoryName(hostName, path));
}
private static string DeriveSharedMemoryName(string hostName, string path)
{
StringBuilder builder = new StringBuilder();
builder.Append(Uri.UriSchemeNetPipe);
builder.Append("://");
builder.Append(hostName.ToUpperInvariant());
builder.Append(path);
byte[] uriBytes = Encoding.UTF8.GetBytes(builder.ToString());
string encodedNameRoot;
if (uriBytes.Length >= 0x80)
{
using (HashAlgorithm algorithm = new SHA1Managed())
{
encodedNameRoot = ":H" + Convert.ToBase64String(algorithm.ComputeHash(uriBytes));
}
}
else
{
encodedNameRoot = ":E" + Convert.ToBase64String(uriBytes);
}
return Uri.UriSchemeNetPipe + encodedNameRoot;
}
private static bool IsNetNamePipeSharedMemoryMetaDataPublished(string sharedMemoryName)
{
const uint FILE_MAP_READ = 0x00000004;
const int ERROR_FILE_NOT_FOUND = 2;
using (SafeFileMappingHandle fileMappingHandle
= OpenFileMapping(FILE_MAP_READ, false, sharedMemoryName))
{
if (fileMappingHandle.IsInvalid)
{
int errorCode = Marshal.GetLastWin32Error();
if (ERROR_FILE_NOT_FOUND == errorCode) return false;
throw new Win32Exception(errorCode); // The name matched, but something went wrong opening it
}
return true;
}
}
private class SafeFileMappingHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeFileMappingHandle() : base(true) { }
public SafeFileMappingHandle(IntPtr handle) : base(true) { base.SetHandle(handle); }
protected override bool ReleaseHandle()
{
return CloseHandle(base.handle);
}
}
}
Имя хоста и путь, по которому вы переходите, получены из URL-адреса службы WCF. Имя хоста - это либо конкретное имя хоста (например, localhost
), либо +
, либо *
, в зависимости от настройки HostNameComparisonMode.
РЕДАКТИРОВАТЬ: Вам также понадобится пара объявлений P / Invoke для функций Win API:
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern SafeFileMappingHandle OpenFileMapping(
uint dwDesiredAccess,
bool inheritHandle,
string name
);
EDIT2: нам нужно настроить возвращаемое значение DeriveSharedMemoryName, чтобы указать пространство имен локального ядра, предполагая, что ваше приложение не запускается с повышенными привилегиями. Измените последнюю строку этой функции следующим образом:
return @"Local\" + Uri.UriSchemeNetPipe + encodedNameRoot;
Вам также необходимо правильно указать параметр hostname, чтобы он соответствовал настройке hostNameComparisonMode, используемой в вашей привязке. Насколько я помню, по умолчанию это сопоставление StrongWildcard в NetNamedPipeBinding, поэтому вам, вероятно, нужно передать "+"
, а не "localhost"
.