Совместное размещение конечных точек WCF REST и NET.TCP в Azure с ASP.NET - PullRequest
0 голосов
/ 08 февраля 2012

Я размещаю свои службы REST в приложении ASP.NET в Windows Azure.Он работает отлично, но мне нужна была служба связи Inter-Role несколько дней назад, я создал свой сервис, но у меня проблемы с его размещением.

Этот код в моем Global.asax отлично работает на моем локальном сервере разработки Azure, но он не работал в облаке Azure.

Каков наилучший способ их правильного размещения?

Global.asax:

public class Global : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        StartNotificationServiceHost();
        RegisterRoutes();
    }

    public ServiceHost ServiceHost { get; private set; }
    private void RegisterRoutes()
    {
        var hostfactory = new WebServiceHostFactory();
        RouteTable.Routes.Add(new ServiceRoute("REST/Companies",hostfactory, typeof(Companies)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Public", hostfactory, typeof(Public)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Users", hostfactory, typeof(Users)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Contacts", hostfactory, typeof(Contacts)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Projects", hostfactory, typeof(Projects)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Instances", hostfactory, typeof(Instances)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Activity", hostfactory, typeof(Activity)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Search", hostfactory, typeof(Search)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Tasks", hostfactory, typeof(Tasks)));
        RouteTable.Routes.Add(new ServiceRoute("REST/Documents", hostfactory, typeof(Documents)));
    }
    private void StartNotificationServiceHost()
    {
        Trace.WriteLine("Starting Service Host", "Information");
        NotificationServiceHost serviceHostBase = new NotificationServiceHost();
        serviceHostBase.RecycleNotificationRecieved += new RecycleNotificationRecievedEventHandler(ServiceHost_RecycleNotificationRecieved);
        serviceHostBase.CheckInstanceStatusRecieved += new CheckInstanceStatusRecievedEventHandler(serviceHostBase_CheckInstanceStatusRecieved);
        ServiceHost = new ServiceHost(serviceHostBase);
        this.ServiceHost.Faulted += (sender, e) =>
        {
            Trace.TraceError("Service Host fault occured");
            this.ServiceHost.Abort();
            Thread.Sleep(500);
            this.StartNotificationServiceHost();

        };
        NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
        RoleInstanceEndpoint notificationServiceHostEndPoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["NotificationServiceEndPoint"];
        this.ServiceHost.AddServiceEndpoint(
            typeof(INotifyService),
            binding,
            String.Format("net.tcp://{0}/NotifyService", notificationServiceHostEndPoint.IPEndpoint)
            );
        try
        {
            this.ServiceHost.Open();
            Trace.TraceInformation("Service Host Opened");
        }
        catch (TimeoutException timeoutException)
        {
            Trace.TraceError("Service Host open failure, Time Out: " + timeoutException.Message);
        }
        catch (CommunicationException communicationException)
        {
            Trace.TraceError("Service Host open failure, Communication Error: " + communicationException.Message);
        }
        Trace.WriteLine("Service Host Started", "Information");
    }
        InstanceItem serviceHostBase_CheckInstanceStatusRecieved(object sender, int e)
        {
...
        }
        void ServiceHost_RecycleNotificationRecieved(object sender, NotificationMessage e)
        {
...

        }
}

Раздел Web.config / ServiceModel:

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- This behavior enables API Key Verification -->
          <serviceAuthorization serviceAuthorizationManagerType="OfisimCRM.Webservice.APIKeyAuthorization, OfisimCRM.Webservice" />
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior>
          <webHttp />
          <serviceValidator />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions>
      <behaviorExtensions>
        <add name="serviceValidator" type="OfisimCRM.Webservice.WebHttpWithValidationBehaviorExtension, OfisimCRM.Webservice, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
    <standardEndpoints>
      <webHttpEndpoint>
        <!-- 
            Configure the WCF REST service base address via the global.asax.cs file and the default endpoint 
            via the attributes on the <standardEndpoint> element below
        -->
        <standardEndpoint crossDomainScriptAccessEnabled="true" faultExceptionEnabled="true" hostNameComparisonMode="WeakWildcard" name="" defaultOutgoingResponseFormat="Json" helpEnabled="true" automaticFormatSelectionEnabled="true" maxBufferSize="65536" maxReceivedMessageSize="104857600" transferMode="Streamed" />
      </webHttpEndpoint>
    </standardEndpoints>
  </system.serviceModel>

Определение службы / WebRole:

 <WebRole name="OfisimCRM.WebClient" vmsize="Small">
    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="Endpoint1" protocol="http" port="80" />
      <InternalEndpoint name="NotificationServiceEndPoint" protocol="tcp" />
    </Endpoints>
    <Imports>
      <Import moduleName="Diagnostics" />
      <Import moduleName="RemoteAccess" />
    </Imports>
    <ConfigurationSettings>
    </ConfigurationSettings>
  </WebRole>

Ошибка:

The server encountered an error processing the request. The exception message is 'Could not connect to net.tcp://x.x.x.29:8000/NotifyService. The connection attempt lasted for a time span of 00:00:21.0918600. TCP error code 10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond x.x.x.29:8000. '. See server logs for more details.

1 Ответ

6 голосов
/ 08 февраля 2012

Доступ к экземплярам ролей ограничен брандмауэром.Обычно экземпляр принимает соединения только от балансировщика нагрузки.Вы добавляете настройку в файл определения сервиса (* .csdef) следующим образом, и необходимо принять соединение.

<?xml version="1.0" encoding="utf-8" ?>
  <ServiceDefinition name="RoleCommunication" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"> 
: 
  <NetworkTrafficRules> 
    <OnlyAllowTrafficTo> 
      <Destinations> 
        <RoleEndpoint endpointName="YourEndPointName" roleName="YourRole" /> 
      <Destinations> 
      <WhenSource matches="AnyRole"> 
        <FromRole roleName="YourRole" /> 
      </WhenSource> 
    </OnlyAllowTrafficTo> 
  </NetworkTrafficRules> 
</ServiceDefinition >

В качестве альтернативы, вы можете добавить правило соединения с помощью команды netsh в Startup Task.

ex) netsh advfirewall firewall добавить правило name = "YourEndPoint" dir = в действии = разрешить localport = 80 protocol = tcp

====

*=== *1008*

Является ли InternalEndpoint динамическимпорт?Если возможно, не могли бы вы установить фиксированный порт в .csdef и задаче запуска.

ex)

<InternalEndpoint name="NotificationServiceEndPoint" protocol="tcp" port="8000"/>

и

netsh advfirewall firewall add rule name="NotificationServiceEndPoint" dir=in action=allow localport=8000 protocol=tcp

====

Или переменная среды доступна следующим образом:

   <Endpoints>
      <InputEndpoint name="Endpoint1" protocol="http" port="80" />
      <InternalEndpoint name="NotificationServiceEndPoint" protocol="tcp" />
    </Endpoints>

      <Startup>
          <Task commandLine="configfirewall.cmd" executionContext="elevated" taskType="simple">
              <Environment>
                  <Variable name="NotificationServiceEndPointPort" value="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[@name=&#39;NotificationServiceEndPoint&#39;]/@port" />
              </Environment>
          </Task>
      </Startup>

и вы используете переменную среды в задачах запуска

netsh advfirewall firewall add rule name="ServiceEndPoint" dir=in action=allow localport=<b>%NotificationServiceEndPointPort%</b> protocol=tcp
...