c# WCF关闭通道和使用函数function

本文关键字:function 函数 WCF 通道 | 更新日期: 2023-09-27 18:02:37

这就是重点,我有一个WCF服务,它现在正在工作。所以我开始在客户端工作。当应用程序运行时,出现了一个异常:timeout。所以我开始阅读,有很多关于如何保持连接的例子,但是,我也发现,最好的方法,是创建通道,使用它,然后处理它。老实说,我喜欢这样。那么,现在读到关闭频道的最佳方法,有两个链接可以对任何需要它们的人有用:

1。清理客户端,正确的方式

2。使用函数

在第一个链接中,这是示例:

    IIdentityService _identitySvc;
...
if (_identitySvc != null)
 {
     ((IClientChannel)_identitySvc).Close();
     ((IDisposable)_identitySvc).Dispose();
     _identitySvc = null;
 }

因此,如果通道不为空,则关闭、处置并赋值为空。但我有个小问题。在这个例子中,通道有一个。Close()方法,但是在我的例子中,智能感知并没有显示Close()方法。它只存在于工厂对象中。所以我相信我必须写出来。但是,在具有契约的接口或实现它的类中?这个方法应该做什么??

现在,下一个链接,这里有一些我以前没有尝试过的东西。Func<T>。看完目标后,会觉得很有趣。它创建了一个函数,该函数使用lambdas创建通道、使用通道、关闭通道并处置通道。这个例子像Using()语句一样实现了这个函数。这真的很好,是一个很好的进步。但是,我需要一点帮助,老实说,我不懂这个函数,所以,一个专家的解释会很有用。下面是函数:

TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
    var chanFactory = GetCachedFactory<TChannel>();
    TChannel channel = chanFactory.CreateChannel();
    bool error = true; 
    try {
        TReturn result = code(channel); 
        ((IClientChannel)channel).Close();
        error = false; 
        return result; 
    }
    finally {
        if (error) {
            ((IClientChannel)channel).Abort();
        }
    }
}

是这样使用的:

int a = 1; 
int b = 2; 
int sum = UseService((ICalculator calc) => calc.Add(a, b)); 
Console.WriteLine(sum);

是的,我认为它真的,真的很好,我想了解它,在我的项目中使用它。

和往常一样,我希望这篇文章能对很多人有所帮助。

c# WCF关闭通道和使用函数function <T>

UseService方法接受委托,该委托使用通道发送请求。委托有一个参数和一个返回值。你可以在委托中调用WCF服务。

在UseService中,它创建通道并将通道传递给委托,委托应该由你提供。通话结束后,关闭通道。

代理对象实现的不仅仅是你的合约——它还实现了IClientChannel,它允许控制代理的生存期

第一个例子中的代码是不可靠的——如果通道已经破裂(例如,在基于会话的交互中服务已经关闭),它将会泄漏。正如您在第二个版本中看到的那样,在出现错误的情况下,它在代理上调用Abort,这仍然会清理客户端

你也可以使用如下的扩展方法:

 enum OnError
 {
     Throw,
     DontThrow
 }
 static class ProxyExtensions
 {
     public static void CleanUp(this IClientChannel proxy, OnError errorBehavior)
     {
         try
         {
             proxy.Close();
         }
         catch
         {
             proxy.Abort();
             if (errorBehavior == OnError.Throw)
             {
                 throw;
             }
         }
     }
 }

但是,这种用法有点麻烦

 ((IClientChannel)proxy).CleanUp(OnError.DontThrow);

但是如果你创建你自己的代理接口来扩展你的合约和IClientChannel

,你可以让它变得更优雅
interface IPingProxy : IPing, IClientChannel
{
}

要回答Jason回答中评论中留下的问题,GetCachedFactory的一个简单示例可能如下所示。该示例查找要创建的端点,方法是在配置文件中找到"Contract"属性等于工厂要创建的服务的ConfigurationName的端点。

ChannelFactory<T> GetCachedFactory<T>()
{
    var endPointName = EndPointNameLookUp<T>();
    return new ChannelFactory<T>(endPointName);
}
// Determines the name of the endpoint the factory will create by finding the endpoint in the config file which is the same as the type of the service the factory is to create
string EndPointNameLookUp<T>()
{
    var contractName = LookUpContractName<T>();
    foreach (ChannelEndpointElement serviceElement in ConfigFileEndPoints)
    {
        if (serviceElement.Contract == contractName) return serviceElement.Name;
    }
    return string.Empty;
}
// Retrieves the list of endpoints in the config file
ChannelEndpointElementCollection ConfigFileEndPoints
{
    get
    {
        return ServiceModelSectionGroup.GetSectionGroup(
            ConfigurationManager.OpenExeConfiguration(
                ConfigurationUserLevel.None)).Client.Endpoints;
    }
}
// Retrieves the ConfigurationName of the service being created by the factory
string LookUpContractName<T>()
{
    var attributeNamedArguments = typeof (T).GetCustomAttributesData()
        .Select(x => x.NamedArguments.SingleOrDefault(ConfigurationNameQuery));
    var contractName = attributeNamedArguments.Single(ConfigurationNameQuery).TypedValue.Value.ToString();
    return contractName;
}
Func<CustomAttributeNamedArgument, bool> ConfigurationNameQuery
{
    get { return x => x.MemberInfo != null && x.MemberInfo.Name == "ConfigurationName"; }
}
一个更好的解决方案是让IoC容器为您管理客户端的创建。例如,使用autoface,它会像下面这样。首先,您需要像这样注册服务:
var builder = new ContainerBuilder();
builder.Register(c => new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator"))
  .SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<ICalculator>>().CreateChannel())
  .UseWcfSafeRelease();
container = builder.Build();

其中"WSHttpBinding_ICalculator"是配置文件中端点的名称。然后,您可以像这样使用该服务:

using (var lifetime = container.BeginLifetimeScope())
{
    var calc = lifetime.Resolve<IContentService>();
    var sum = calc.Add(a, b);
    Console.WriteLine(sum);
}