无法调用我的服务方法

时间:2011-09-28 15:17:06

标签: c# .net wcf visual-studio-2010 service

我收到了这个错误:

  

通讯对象,   System.ServiceModel.ChannelFactory`1 [FxCurveService.IFxCurveService]   不能用于通信,因为它处于Faulted状态。

当我调用此代码时:

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 个答案:

答案 0 :(得分:5)

如果处置了频道,则无法访问例外的详细信息。因此,在访问WCF服务时,不建议使用可爱的using模式构造。事实上,Exception属性需要访问通道以提取有关异常的一些信息(不知道MS是否错过了这一点,或者是否有技术原因)。

我编写了一个小类来简化对WCF代理的调用(这个site帮助我理解问题并编写类):

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);
            }),

这些助手可以确保正确关闭通道,而无需处理它。您将能够看到实际的异常。当你找到实际的例外时编辑你的帖子。

(也许你的服务工厂已经在使用这种技术。如果没有,请不要犹豫,像我的班级一样更新它。)

[edit] 您仍然需要使用配置。这是一个可能正在运行的配置:

  

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

答案 1 :(得分:1)

我使用的是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服务,这有关系吗?

以下是我在Web应用程序解决方案中创建的服务界面:

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");
            }); 

答案 2 :(得分:0)

您的目标是.Net 3.5还是.Net 4.0?在.Net 4.0中,您可以获得许多服务配置的默认值。在.Net 3.5中,您将不得不在App.config中或以编程方式完全配置端点。例如,使用的是什么绑定?如果你使用的是.Net 4.0,那么你默认会得到一个BasicHttpBinding,因为你指定了一个http uri。在.Net 3.5中,您将会出错,因为没有配置绑定。