Не могу вызвать мой метод обслуживания - PullRequest
0 голосов
/ 28 сентября 2011

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

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

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

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 в проекте, что я не смог сделать здесь.Это единственное отличие.

Спасибо.

Ответы [ 3 ]

5 голосов
/ 28 сентября 2011

Вы не можете получить доступ к информации об исключении, если канал расположен. Поэтому прекрасная конструкция using не рекомендуется при доступе к службе WCF. Фактически, свойства Exception требуют наличия доступа к каналу для извлечения некоторой информации об исключении (не знаю, пропустила ли 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="UsingContract&lt;TIServiceContract&gt;(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" />

1 голос
/ 07 декабря 2011

Я использую 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");
            }); 
0 голосов
/ 28 сентября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...