Не удается вызвать мой метод обслуживания

#c# #.net #wcf #visual-studio-2010 #service

#c# #.net #wcf #visual-studio-2010 #Обслуживание

Вопрос:

Я получаю эту ошибку:

Объект связи, система.ServiceModel.ChannelFactory`1[FxCurveService.IFxCurveService], не может использоваться для связи, поскольку он находится в состоянии сбоя.

Когда я вызываю этот код:

 using (var client = new WCFServiceChannelFactory<IFxCurveService>(new Uri("http://ksqcoreapp64int:5025/")))
                {
                    guid = client.Call(svc => svc.ReserveSnapshot(fxCurveKey));
                    DiscountFactorNew[] dfs = client.Call(svc => svc.GetDiscountFactors(guid, dates, from));
                    Assert.IsTrue(guid != null);
                }
  

Здесь ошибка — client.Call(svc => svc.ReserveSnapshot(fxCurveKey));

Я понятия не имею, почему он это делает. Я передаю правильные параметры, вводя правильный адрес для службы, что еще я должен здесь проверять?

Кстати, WCFServiceChannelFactory это наш собственный класс, который мы используем для выполнения служебных вызовов. Изложите здесь:

 public class WCFServiceChannelFactory<T> : IDisposable
    {
        public WCFServiceChannelFactory();
        public WCFServiceChannelFactory(Uri uri);

        public T Channel { get; }
        public System.ServiceModel.ChannelFactory<T> ChannelFactory { get; }
        public Type ChannelType { get; }

        public void Call(Action<T> f);
        public R Call<R>(Func<T, R> f);
        public void Dispose();
    }
  

Дело в том, что проблема не в этом, поскольку это работает точно так же в любом другом проекте, кроме этого. По сути, я должен передать Uri его непосредственно в моем, где, поскольку другие извлекают его из файла .config в проекте, чего я не смог сделать здесь. Это единственное отличие.

Спасибо.

Комментарии:

1. Что такое WcfServiceChannelFactory?

2. Наш собственный класс, см. Редактирование.

3. Я подозреваю, что проблема заключается в реализации этого пользовательского класса WCFServiceChannelFactory. Причина, по которой он работает в других решениях, не означает, что он будет работать во всех решениях.

4. Время взломать средство просмотра трассировки службы. Подробности здесь: msdn.microsoft.com/en-us/library/ms732023.aspx — должно дать вам представление о том, в чем заключается ошибка и почему это происходит.

Ответ №1:

Вы не можете получить доступ к деталям исключения, если канал удален. Таким using образом, построение прекрасного шаблона не рекомендуется при доступе к службе WCF. Фактически, для свойств исключения требуется доступ к каналу для извлечения некоторой информации об исключении (не знаю, пропустила ли MS этот момент или есть технические причины).

Я написал небольшой класс, чтобы упростить вызов прокси-серверов WCF (этот сайт помогает мне понять проблему и написать класс) :

 using System;
using System.ServiceModel;

namespace Utility
{
    public class ServiceHelper
    {

        /// <summary>
        /// WCF proxys do not clean up properly if they throw an exception. This method ensures that the service 
        /// proxy is handeled correctly. Do not call TService.Close() or TService.Abort() within the action lambda.
        /// </summary>
        /// <typeparam name="TService">The type of the service to use</typeparam>
        /// <param name="action">Lambda of the action to performwith the service</param>
        [System.Diagnostics.DebuggerStepThrough]
        public static void UsingProxy<TService>(Action<TService> action)
            where TService : ICommunicationObject, IDisposable, new()
        {
            var service = new TService();
            bool success = false;
            try
            {
                action(service);
                if (service.State != CommunicationState.Faulted)
                {
                    service.Close();
                    success = true;
                }
            }
            finally
            {
                if (!success)
                {
                    service.Abort();
                }
            }
        }
        /// <summary>
        /// WCF proxys do not clean up properly if they throw an exception. This method ensures that the service 
        /// proxy is handeled correctly. Do not call TService.Close() or TService.Abort() within the action lambda.
        /// </summary>
        /// <typeparam name="TIServiceContract">The type of the service contract to use</typeparam>
        /// <param name="action">Action to perform with the client instance.</param>
        /// <remarks>In the configuration, an endpoint with names that maches the <typeparamref name="TIServiceContract"/> name
        /// must exists. Otherwise, use <see cref="UsingContractamp;<TIServiceContractamp;>(string endpointName, Action<TIServiceContract> action)"/>. </remarks>
        [System.Diagnostics.DebuggerStepThrough]
        public static void UsingContract<TIServiceContract>(Action<TIServiceContract> action)
        {
            UsingContract<TIServiceContract>(
                typeof(TIServiceContract).Name,
                action
                );
        }
        /// <summary>
        /// WCF proxys do not clean up properly if they throw an exception. This method ensures that the service 
        /// proxy is handeled correctly. Do not call TService.Close() or TService.Abort() within the action lambda.
        /// </summary>
        /// <typeparam name="TIServiceContract">The type of the service contract to use</typeparam>
        /// <param name="action">Action to perform with the client instance.</param>
        /// <param name="endpointName">Name of the endpoint to use</param>
        [System.Diagnostics.DebuggerStepThrough]
        public static void UsingContract<TIServiceContract>(
              string endpointName,
              Action<TIServiceContract> action)
        {
            var cf = new ChannelFactory<TIServiceContract>(endpointName);
            var channel = cf.CreateChannel();
            var clientChannel = (IClientChannel)channel;

            bool success = false;
            try
            {
                action(channel);
                if (clientChannel.State != CommunicationState.Faulted)
                {
                    clientChannel.Close();
                    success = true;
                }
            }
            finally
            {
                if (!success) clientChannel.Abort();
            }
        }
    }    
}
  

Тогда вы можете просто сделать что-то вроде этого (в зависимости от того, есть ли у вас ссылка на службу или контракты :

 ServiceHelper.UsingContract<IFxCurveService>(svc=>
            {
                guid = svc.ReserveSnapshot(fxCurveKey);
                DiscountFactorNew[] dfs = svc.GetDiscountFactors(guid, dates, from));
                Assert.IsTrue(guid != null);
            }),
  

Эти помощники обеспечивают правильное закрытие каналов, не удаляя его. Тогда вы сможете увидеть фактическое исключение. Отредактируйте свой пост, когда найдете фактическое исключение.

(Возможно, ваша фабрика обслуживания уже использует этот метод. Если нет, не стесняйтесь обновлять его, как мой класс).

[править]Вам все равно придется поиграть с конфигурацией. вот, вероятно, рабочий конфиг для вас :

         contract="The.Correct.Namespace.IFxCurveService"
        name="IFxCurveService" />
  

Ответ №2:

Я использую 4.0, и я настроил его следующим образом:

 <system.serviceModel>
    <bindings>
      <webHttpBinding>
        <binding name="defaultBasicHttpBinding">
          <security mode="Transport">
            <transport clientCredentialType="None" proxyCredentialType="None"/>
            <!--<message clientCredentialType="Certificate" algorithmSuite="Default" />-->
          </security>
        </binding>
      </webHttpBinding>
    </bindings>

    <client>
      <endpoint address="https://abc1234.abc.nsroot.net/MyService/MyService.svc"
                binding="webHttpBinding"
                bindingConfiguration="defaultBasicHttpBinding"
                contract="IMyService"
                name="TestJeph"/>
    </client>
  </system.serviceModel>
  

К вашему сведению: я вызываю службу WCF Rest, имеет ли это значение?

ниже приведен мой интерфейс службы, который я создал в решении для веб-приложений:

 namespace anothertest
{
    using System;
    using System.ServiceModel;


    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName = "IMyService")]
    public interface IMyService
    {

        [OperationContract]
        test.WebService.Entity.BusinessEntity[] GetAllActiveBusiness();
    }

 public class ProductClient : ClientBase<IMyService>, IMyService
        {
            #region Members

            public test.WebService.Entity.BusinessEntity[] GetAllActiveBusiness()
            {
                return Channel.GetAllActiveBusiness();
            }

            #endregion
        }
}
  

ниже приведен код для вызова службы:

 anothertest.Utility.ServiceHelper.UsingContract<anothertest.IMyService>
            ("TestJeph",
            svc=>
            {
                string test = svc.UpdateCMPStatus("test", "me");
            }); 
  

Ответ №3:

Вы ориентируетесь на .Net 3.5 или .Net 4.0? В .Net 4.0 вы получаете множество значений по умолчанию для конфигурации службы. В .Net 3.5 вам нужно будет полностью настроить конечную точку либо в App.config, либо программно. Например, какую привязку использует enpoint? Если вы используете .Net 4.0, то по умолчанию вы получите базовую привязку HttpBinding, поскольку вы указали uri http. В .Net 3.5 вы ошибаетесь, так как привязка настроена не будет.