只是想知道在什么情况下,当您可以使用ChannelFactory调用调用时,您更愿意从WCF服务生成代理?
这样,您不必生成代理,并担心在服务器更新时重新生成代理?
谢谢
我正在尝试将现有的.NET Remoting应用程序转换为WCF.服务器和客户端共享公共接口,所有对象都是服务器激活的对象.
在WCF世界中,这类似于创建每个呼叫服务和ChannelFactory<T>
用于创建代理.我正在努力解决如何正确创建ChannelFactory<T>
ASP.NET客户端的问题.
出于性能原因,我希望ChannelFactory<T>
每次调用服务时都缓存对象并创建通道.在.NET远程处理时代,曾经有RemotingConfiguration.GetRegisteredWellknownClientTypes()
一种方法来获取我可以缓存的客户端对象的集合.看起来,在WCF世界中没有这样的东西,虽然我能够从配置文件中获取端点集合.
现在我认为这将是有效的.我可以创建这样的东西:
public static ProxyHelper
{
static Dictionary<Type, object> lookup = new Dictionary<string, object>();
static public T GetChannel<T>()
{
Type type = typeof(T);
ChannelFactory<T> factory;
if (!lookup.ContainsKey(type))
{
factory = new ChannelFactory<T>();
lookup.Add(type, factory);
}
else
{
factory = (ChannelFactory<T>)lookup[type];
}
T proxy = factory.CreateChannel();
((IClientChannel)proxy).Open();
return proxy;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为上面的代码可以工作,但我有点担心多个线程试图添加新ChannelFactory<T>
对象,如果它不在查找中.由于我使用的是.NET 4.0,我首先考虑使用ConcurrentDictionary
和使用GetOrAdd()
方法或使用TryGetValue()
方法来检查是否ChannelFactory<T>
存在并且它不存在,然后使用GetOrAdd()
方法.虽然ConcurrentDictionary.TryGetValue()
和ConcurrentDictionary.GetOrAdd()
方法不确定性能.
另一个小问题是我是否需要 …
我有一个托管的WCF服务,我为其创建了一个自定义工厂,这样就可以使用多个主机头:
/// <summary>
/// Required for hosting where multiple host headers are present
/// </summary>
public class MultipleHostServiceFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
List<Uri> addresses = new List<Uri>();
addresses.Add(baseAddresses[0]);
return base.CreateServiceHost(serviceType, addresses.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
我很确定我的配置文件现在在客户端和服务器上都是正确的(可以在这里看到).
我得到的错误似乎与工厂有关:
此工厂已启用手动寻址,因此必须预先发送所有发送的消息.
public string GetData(int value) {
return base.Channel.GetData(value);
}
Run Code Online (Sandbox Code Playgroud)
错误发生在行return base.Channel.GetData(value);
.
请考虑以下代码,这些代码是许多ChannelFactory示例的典型代码:
WSHttpBinding myBinding = new WSHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress(
ConfigurationSettings.AppSettings["HelloWorldServiceURL"]);
ChannelFactory<IHelloWorldService> myChannelFactory =
new ChannelFactory<IHelloWorldService>(myBinding, myEndpoint);
IHelloWorldService proxy = myChannelFactory.CreateChannel();
((IClientChannel)proxy).Open();
HelloWorldDataContract dc = proxy.SayHello();
((IClientChannel)proxy).Close();
Run Code Online (Sandbox Code Playgroud)
请注意,当调用proxy.Open()时,通道的状态和ChannelFactory的状态都变为"已打开".当调用proxy.Close()时,通道的状态变为"关闭",但ChannelFactory的状态仍为"已打开".
是否应该关闭ChannelFactory?在许多例子中我似乎没有看到这一点.另外,如果可能的话,请解释开放频道与开放频道工厂之间的区别.
另外,我知道IDisposable问题,因此除非它对答案有直接影响,否则它可能会被忽略.
所以我决定在我的WCF应用程序中提高性能,并尝试缓存Channels和ChannelFactory.关于所有这些我有两个问题需要在开始之前清理.
1)ChannelFactory应该实现为单例吗?
2)我不确定如何缓存/重用各个频道.你有任何关于如何分享的例子吗?
值得注意的是,我的WCF服务被部署为独立应用程序,只有一个端点.
编辑:
感谢您的回复.我还有几个问题......
1)我想我对缓存应该发生的位置感到困惑.我正在提供一个客户端API,它将此代码用于我们公司的另一个部门.这个缓存是否发生在客户端?
2)客户端API将用作Silverlight应用程序的一部分,这会改变什么吗?特别是,在这种情况下可以使用哪些缓存机制?
3)我还不清楚GetChannelFactory方法的设计.如果我只有一个服务,是否应该只创建和缓存一个ChannelFactory?
我还没有实现任何缓存功能(因为我对如何完成它完全感到困惑!),但这是我到目前为止客户端代理所拥有的:
namespace MyCompany.MyProject.Proxies
{
static readonly ChannelFactory<IMyService> channelFactory =
new ChannelFactory<IMyService>("IMyService");
public Response DoSomething(Request request)
{
var channel = channelFactory.CreateChannel();
try
{
Response response = channel.DoSomethingWithService(request);
((ICommunicationObject)channel).Close();
return response;
}
catch(Exception exception)
{
((ICommenicationObject)channel).Abort();
}
}
}
Run Code Online (Sandbox Code Playgroud) 问候,当我尝试为我的工厂设置凭证时,问题是:
ChannelFactory<IWCFSeekService> factory = Factory;
if (factory != null)
{
factory.Credentials.UserName.UserName = CServiceCredentials.Instance.Username;
_Channel = factory.CreateChannel();
}
Run Code Online (Sandbox Code Playgroud)
我得到一个异常,即对象是只读的.当我想设置用户名时会发生这种情况.
我们在2008年在.NET 3.5上构建了一个强大的WCF客户端(现在在.NET 4.0下重新编译),它通过net.tcp绑定与我们自己的WCF服务进行通信.健壮的客户端使用ChannelFactory <IOurServiceInterface>()来生成服务代理,通过该代理我们当前对服务进行同步调用.我们从每次通话中得到结果; 我们没有单向通话.
我们正在迁移到.NET 4.5/C#5,并希望使用async/await/TAP使客户端异步.如何以最佳方式执行此操作以获得干净的代码和良好的运行时性能?
(我已经看过关于这个主题的MS文档,但它总是讨论运行svcutil.我们不使用svcutil;我们直接使用ChannelFactory.另外:使用.NET 4.5下的通道工厂异步调用操作的MS文档不变自.NET 3.0起.似乎ChannelFactory尚未接受新的异步.)
我的WCF客户端库有以下规划的体系结构:
我已经阅读了很多关于各种不同内容的文章,但我仍然对如何以正确的方式将它们整合在一起感到困惑.我有以下问题:
我猜,一行代码会说超过一千个单词,所以这是我的代码形式的想法.我在上面用"???"标记了我的所有问题 在代码中.
public class MyServiceClient : IDisposable
{
// channel factory cache
private static ChannelFactory<IMyService> _factory;
private static object _lock = new object();
private IMyService _client = null;
private bool _isDisposed = false;
/// <summary>
/// Creates a channel for the service
/// </summary>
public MyServiceClient()
{
lock (_lock)
{
if (_factory == null)
{
// ... set up custom bindings here and get some config values
var endpoint …
Run Code Online (Sandbox Code Playgroud) 我正在尝试从另一个服务中调用WCF服务,部分使用我在StackOverflow上找到的实现ChannelFactory的示例.
我在我的测试解决方案中创建了一个单独的控制台应用项目(VS 2008,btw),
namespace MyService.Test
{
class Program
{
static void Main(string[] args)
{
MySolution.MyTestClient proxy = new MyTestClient();
proxy = new MyTestClient();
proxy.Endpoint.Address = new EndpointAddress("http://localhost:8723/MySolution/");
// Instantiate a request object and assign values to its member variables.
MySolution.RemoteServiceMethod() theObject = new RemoteServiceMethod();
theObject.SomeProperty = "123";
theObject.SomeOtherProperty = "alpha";
Console.WriteLine("Calling the remote service method now...");
try
{
proxy.SubmitRemoteServiceRequest(proxy.theObject);
}
catch (FaultException<MySolution.RequestException> e)
{
// exception code hereMySolution
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是来自本地服务的App.Config,显示端点:
<system.serviceModel>
<client>
<endpoint …
Run Code Online (Sandbox Code Playgroud) 在我们的SharePoint/ASP.NET环境中,我们有一系列数据检索器类,这些类都来自通用接口.我被分配了创建数据检索器的任务,该数据检索器可以使用WCF与其他SharePoint场远程通信.我现在实现它的方式ChannelFactory<T>
是在静态构造函数中创建单例,然后由远程数据检索器的每个实例重用,以创建单独的代理实例.我认为这样可以很好地工作,因为那时ChannelFactory
只在app域中实例化一次并且它的创建保证是线程安全的.我的代码看起来像这样:
public class RemoteDataRetriever : IDataRetriever
{
protected static readonly ChannelFactory<IRemoteDataProvider>
RequestChannelFactory;
protected IRemoteDataProvider _channel;
static RemoteDataRetriever()
{
WSHttpBinding binding = new WSHttpBinding(
SecurityMode.TransportWithMessageCredential, true);
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType =
MessageCredentialType.Windows;
RequestChannelFactory =
new ChannelFactory<IRemoteDataProvider>(binding);
}
public RemoteDataRetriever(string endpointAddress)
{
_channel = RemoteDataRetriever.RequestChannelFactory.
CreateChannel(new EndpointAddress(endpointAddress));
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是一个很好的设计吗?我想,一旦ChannelFactory
创建,我不需要担心线程安全,因为我只是用它来打电话,CreateChannel()
但我错了吗?它是在改变状态还是在幕后做一些可能导致线程问题的时髦的东西?另外,我是否需要在某个地方放置一些代码(静态终结器?)来手动处理ChannelFactory
或者我可以假设每当IIS重新启动它时,它会为我做所有的清理工作吗?
wcf singleton static-constructor thread-safety channelfactory