Реле служебной шины Azure и протокол http

Я должен настроить службу Azure, которая должна быть доступна для других платформ (Android, iOS). Вот почему я пытаюсь настроить его, используя протокол http или https, а не протокол sb (служебная шина) (см. Привязки служебной шины, последний абзац).

К сожалению, служба выдает исключение при инициализации:

"HTTP could not register URL http://+:80/ServiceBusDefaultNamespace/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details)."

Код инициализации службы в WorkerRole:

  private void InitailizeService()
  {
     Trace.WriteLine("Initializing service");
     try
     {
        var serviceAddress = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceAddress");
        var protocol = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.Protocol");
        string keyName = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceKeyName");
        string sharedAccessKey = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceSharedAccessKey");

        Uri uri = new Uri(protocol + "://" + serviceAddress + "/ServiceBusDefaultNamespace");

        ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
        _host = new ServiceHost(typeof(WorkerRoleService), uri);

        TokenProvider tp = null;
        if (!String.IsNullOrEmpty(keyName))
        {
           tp = TokenProvider.CreateSharedAccessSignatureTokenProvider(keyName, sharedAccessKey);
        }
        var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior(tp);

        ContractDescription contractDescription = ContractDescription.GetContract(typeof(IInstalSoftCloudService), typeof(WorkerRoleService));

        ServiceEndpoint serviceEndPoint = new ServiceEndpoint(contractDescription);
        serviceEndPoint.Address = new EndpointAddress(uri);

        Binding binding;
        switch (protocol)
        {
           case "sb":
              binding = new NetTcpRelayBinding { TransferMode = TransferMode.Streamed, MaxReceivedMessageSize = 1048576000, MaxBufferSize = 10485760, MaxConnections = 200 };
              break;
           case "http":
           case "https":
              binding = new WebHttpRelayBinding { TransferMode = TransferMode.Streamed, MaxReceivedMessageSize = 1048576000, MaxBufferSize = 10485760 };
              break;
           default:
              throw new NotSupportedException("Protocol not supported: " + protocol);
        }
        serviceEndPoint.Binding = binding;
        serviceEndPoint.Behaviors.Add(sharedSecretServiceBusCredential);

        _host.Description.Endpoints.Add(serviceEndPoint);

        _host.Open();

        Trace.WriteLine("Service initialization completed");
     }
     catch (Exception e)
     {
        Trace.WriteLine("Service initialization failed.\r\n" + e.Message);

        throw; 
     }
  }

Настройки в ServiceConfiguration.Cloud.cscfg:

  <Setting name="Microsoft.ServiceBus.ServiceAddress" value="<my namespace here>.servicebus.windows.net" />
  <Setting name="Microsoft.ServiceBus.ServiceKeyName" value="RootManageSharedAccessKey" />
  <Setting name="Microsoft.ServiceBus.ServiceSharedAccessKey" value="<my key here>" />
  <Setting name="Microsoft.ServiceBus.Protocol" value="http" />

Приведенный выше код отлично работает, когда протокол в настройках изменен на "sb".

1 ответ

Решение

После нескольких часов борьбы я в конечном итоге заставил его работать по протоколу https. Важное изменение было внесено в строку создания хоста сервиса:

_host = new ServiceHost(typeof(WorkerRoleService));

вместо:

_host = new ServiceHost(typeof(WorkerRoleService), uri);

Я также изменил маркер безопасности с SAS на ACS. Для этого потребовалось воссоздать мою служебную шину с использованием интерфейса командной строки Azure, поскольку портал Azure не позволяет включить ACS для ранее созданной служебной шины. Для получения дополнительной информации см. Этот пост: Как я могу создать службу ACS для Windows с помощью powershell? (прочитайте все комментарии, потому что правильной командой для выбора подписки является Select-AzureSubscription).

Мой окончательный код:

  private void InitailizeService()
  {
     try
     {
        var serviceAddress = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceAddress");
        var serviceNamespace = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceNamespace");
        var protocol = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.Protocol");
        string issuerName = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceIssuerName");
        string issuerSecret = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ServiceIssuerSecret");

        Uri uri = ServiceBusEnvironment.CreateServiceUri(protocol, serviceAddress, serviceNamespace);

        ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
        _host = new ServiceHost(typeof(WorkerRoleService));

        TokenProvider tp = null;
        if (!String.IsNullOrEmpty(issuerName))
        {
           tp = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
        }
        var sharedSecretServiceBusCredential = new TransportClientEndpointBehavior(tp);

        Binding binding;
        switch (protocol)
        {
           case "sb":
              binding = new NetTcpRelayBinding { TransferMode = TransferMode.Streamed, MaxReceivedMessageSize = 1048576000, MaxBufferSize = 10485760, MaxConnections = 200 };
              break;
           case "http":
              binding = new BasicHttpBinding { TransferMode = TransferMode.Streamed, MaxReceivedMessageSize = 1048576000, MaxBufferSize = 10485760 };
              break;
           case "https":
              var wsbinding = new WS2007HttpRelayBinding { MaxReceivedMessageSize = 1048576000 };
              wsbinding.Security.Mode = EndToEndSecurityMode.Transport;
              wsbinding.Security.RelayClientAuthenticationType = RelayClientAuthenticationType.None;
              binding = wsbinding;
              break;
           default:
              throw new NotSupportedException("Protocol not supported: " + protocol);
        }
        var serviceEndPoint = _host.AddServiceEndpoint(typeof(IInstalSoftCloudService), binding, uri);
        serviceEndPoint.Behaviors.Add(sharedSecretServiceBusCredential);

        // Lines below are for MEX and publishing of the service
        EnableMetadataExchange(uri, sharedSecretServiceBusCredential, binding);
        ServiceRegistrySettings serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public) { DisplayName = "InstalSystemMobileEngine" };
        foreach (ServiceEndpoint subscriberEndpoint in _host.Description.Endpoints)
        {
           subscriberEndpoint.Behaviors.Add(serviceRegistrySettings);
        }

        _host.Open();

        Trace.WriteLine("Service initialization completed");
     }
     catch (Exception e)
     {
        Trace.WriteLine("Service initialization failed.\r\n" + e.Message);

        throw; 
     }
  }

  private void EnableMetadataExchange(Uri aBaseUri, TransportClientEndpointBehavior aBehavior, Binding aBinding, bool aEnableHttpGet = true)
  {
     if (_host.State == CommunicationState.Opened)
        throw new InvalidOperationException("Host already opened");
     var metadataBehavior = _host.Description.Behaviors.Find<ServiceMetadataBehavior>();
     if (metadataBehavior == null)
     {
        metadataBehavior = new ServiceMetadataBehavior();
        _host.Description.Behaviors.Add(metadataBehavior);
        Trace.WriteLine("_host.Description.Behaviors.Add(metadataBehavior)");
     }
     var mexEndpoint = _host.AddServiceEndpoint(typeof(IMetadataExchange), aBinding, new Uri(aBaseUri, "mex"));
     mexEndpoint.Behaviors.Add(aBehavior);
  }

Конфигурация для вышеуказанного кода:

  <Setting name="Microsoft.ServiceBus.ServiceAddress" value="<service bus address - without .servicebus.windows.net>" />
  <Setting name="Microsoft.ServiceBus.ServiceNamespace" value="ServiceBusDefaultNamespace/" />
  <Setting name="Microsoft.ServiceBus.ServiceIssuerName" value="<issuer name>" />
  <Setting name="Microsoft.ServiceBus.ServiceIssuerSecret" value="<issuer secret>" />
  <Setting name="Microsoft.ServiceBus.Protocol" value="https" />

Теперь нам нужно попытаться подключиться к этому сервису из приложения для Android - надеюсь, все пройдет хорошо. Соединение из тестового приложения WCF работает правильно, и, что очень важно, позволяет масштабировать Azure (несколько экземпляров рабочих ролей подключены к служебной шине).

Приведенный выше код не работает с протоколом http. Я оставил его здесь, потому что он работает на эмуляторе Azure (с переключением служебной шины на локальную служебную шину для Windows).

Надеюсь, что выше помогает кому-то...

Другие вопросы по тегам