我收到了这个错误:
通讯对象, 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文件中获取它,我在这里无法做到。这是唯一的区别。
感谢。
答案 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<TIServiceContract>(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中,您将会出错,因为没有配置绑定。