- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试使用 WCF 以及 WCF 服务器位于 Windows 服务中的位置来设置发布/订阅系统。绑定(bind)是 net.TCP。该服务向客户端提供“订阅”方法,以便客户端可以注册一个回调处理程序到一个事件,该事件将从链接到服务器的 DLL 中引发。在 Subscribe 方法中,我尝试使用 OperationContext.Current.GetCallbackChannel 方法获取回调 channel 。当我尝试这样做时,OperationContext.Current 属性返回 NULL。
谁能告诉我这个属性在什么情况下会返回 null??我错过了设置什么吗?我将在下面包含服务代码和接口(interface)代码。我在 Visual Studio 2012 中使用 c# 并定位框架 4.5。
服务:
namespace WService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class WcfPublisherService : IWcfPublisherContract
{
IOALogic logic = new OAControlExample();
IWcfSubscriberContract _callback = null;
public void Subscribe()
{
_callback = OperationContext.Current.GetCallbackChannel<IWcfSubscriberContract>();
logic.BarriersChanged += logic_BarriersChanged;
}
public void UnSubscribe()
{
logic.BarriersChanged -= logic_BarriersChanged;
}
void logic_BarriersChanged(object sender, BarriersChangedEventArgs e)
{
_callback.BarriersChanged(e.BarrierLines);
}
}
}
接口(interface):
namespace WService
{
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IWcfSubscriberContract))]
public interface IWcfPublisherContract
{
[OperationContract(IsOneWay=false, IsInitiating=true)]
void Subscribe();
[OperationContract(IsOneWay = false, IsTerminating=true)]
void UnSubscribe();
}
public interface IWcfSubscriberContract
{
[OperationContract(IsOneWay = true)]
void BarriersChanged(BarrierLines barrierLines);
}
}
客户:
namespace TestClient
{
public partial class Form1 : Form
{
WcfPublisherService myService
= new WcfPublisherService();
ServiceCallback serviceCallback = new ServiceCallback();
public Form1()
{
InitializeComponent();
serviceCallback.NewMessage += serviceCallback_NewMessage;
}
private delegate void serviceCallback_NewMessageDelegate(object sender, NewMessageEventArgs e);
void serviceCallback_NewMessage(object sender, NewMessageEventArgs e)
{
if (textBox1.InvokeRequired)
{
textBox1.Invoke(new serviceCallback_NewMessageDelegate(serviceCallback_NewMessage), new object[] {sender, e});
}
else
{
if (textBox1.Text.Trim().Length > 1)
{
textBox1.Text += Environment.NewLine;
}
textBox1.Text += e.Msg;
}
}
private void button1_Click(object sender, EventArgs e)
{
myService.Subscribe();
}
private void button2_Click(object sender, EventArgs e)
{
myService.UnSubscribe();
}
}
[CallbackBehaviorAttribute(UseSynchronizationContext = false)]
class ServiceCallback : IWcfSubscriberContract
{
public delegate void NewMessageEventHandler(object sender, NewMessageEventArgs e);
public event NewMessageEventHandler NewMessage;
protected virtual void OnNewMessage(string msg)
{
if (NewMessage != null)
{
NewMessage(this, new NewMessageEventArgs(msg));
}
}
public void BarriersChanged(OA.BarrierLines barrierLines)
{
OnNewMessage("new barrier lines");
}
}
public class NewMessageEventArgs : EventArgs
{
public NewMessageEventArgs(string msg)
{
this.Msg = msg;
}
public string Msg { get; set; }
}
}
********* 新编辑 ************< em>***感谢 SalientBrain 的建议,我对我的项目进行了相当大的更改,因为我意识到即使没有客户端连接,该服务也必须长时间运行并持续运行,所以我将其更改为单例。即便如此,我原来的问题仍然存在。 SalientBrain 要求查看我的配置文件,因此我将其与所有其他相关文件一起包含在下面。为了节省空间,我把它去掉了,但我不认为我删除了任何重要的东西。错误发生在 PulisherService 类的 Subscribe 方法中。我希望这是我在配置文件中做的愚蠢的事情。嗯,这里是:
配置:
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="WService.WCFPublisherServiceBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="WService.WCFPublisherServiceBehavior"
name="WService.WcfPublisherService">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
name="NetTcpBindingEndpoint" contract="WService.IWcfPublisherContract">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
name="MexTcpBindingEndpoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8523/Publisher" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
Wcf 契约(Contract):
namespace WService
{
[ServiceContract(SessionMode = SessionMode.Allowed, CallbackContract = typeof(IWcfSubscriberContract))]
public interface IWcfPublisherContract
{
[OperationContract(IsOneWay=false)]
void Subscribe(string key);
[OperationContract(IsOneWay = false)]
void UnSubscribe(string key);
}
public interface IWcfSubscriberContract
{
[OperationContract(IsOneWay = true)]
void BarriersChanged(BarrierLines barrierLines);
}
}
Wcf服务:
namespace WService
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WcfPublisherService : IWcfPublisherContract
{
private static WcfPublisherService _instance = null;
private IOALogic _logic = null;
private Dictionary<string, IWcfSubscriberContract> _callbacks
= new Dictionary<string, IWcfSubscriberContract>();
private ReaderWriterLock _callbacksLock = new ReaderWriterLock();
private WcfPublisherService() { }
public static WcfPublisherService TheInstance()
{
if (_instance == null)
{
_instance = new WcfPublisherService();
}
return _instance;
}
public void StopWcf()
{
_logic.StopRequest();
}
public void StartWcf(IOALogic logic)
{
_logic = logic;
_logic.BarriersChanged += logic_BarriersChanged;
ThreadPool.QueueUserWorkItem(new WaitCallback(StartWork), null);
}
public void StartWork(object state)
{
_logic.Run();
}
public void Subscribe(string key)
{
OperationContext context = OperationContext.Current;
// The above line returns null ***********************************************
_callbacksLock.AcquireWriterLock(2000);
if (_callbacksLock.IsWriterLockHeld)
{
_callbacks.Add(key, context.GetCallbackChannel<IWcfSubscriberContract>());
// The above line throws a null execption because context is null ********
_callbacksLock.ReleaseWriterLock();
}
}
public void UnSubscribe(string key)
{
_callbacksLock.AcquireWriterLock(2000);
if (_callbacksLock.IsWriterLockHeld)
{
_callbacks.Remove(key);
_callbacksLock.ReleaseWriterLock();
}
}
void logic_BarriersChanged(object sender, BarriersChangedEventArgs e)
{
_callbacksLock.AcquireReaderLock(1000);
if (_callbacksLock.IsReaderLockHeld)
{
try
{
foreach (IWcfSubscriberContract callback in _callbacks.Values)
{
callback.BarriersChanged(e.BarrierLines);
}
}
finally
{
_callbacksLock.ReleaseReaderLock();
}
}
}
}
}
window 服务:
namespace WService
{
public partial class WService : ServiceBase
{
internal static ServiceHost _serviceHost = null;
internal static IOALogic _logic = new OAControlExample();
public WService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (_serviceHost != null)
{
_serviceHost.Close();
}
_serviceHost = new ServiceHost(WcfPublisherService.TheInstance());
WcfPublisherService.TheInstance().StartWcf(_logic);
_serviceHost.Open();
}
protected override void OnStop()
{
if (WcfPublisherService.TheInstance() != null)
{
WcfPublisherService.TheInstance().StopWcf();
}
if (_serviceHost != null)
{
_serviceHost.Close();
_serviceHost = null;
}
}
}
}
测试表格:
namespace TestClient
{
public partial class Form1 : Form
{
ServiceCallback serviceCallback = new ServiceCallback();
public Form1()
{
InitializeComponent();
serviceCallback.NewMessage += serviceCallback_NewMessage;
}
private delegate void serviceCallback_NewMessageDelegate(object sender, NewMessageEventArgs e);
void serviceCallback_NewMessage(object sender, NewMessageEventArgs e)
{
if (textBox1.InvokeRequired)
{
textBox1.Invoke(new serviceCallback_NewMessageDelegate(serviceCallback_NewMessage), new object[] {sender, e});
}
else
{
if (textBox1.Text.Trim().Length > 1)
{
textBox1.Text += Environment.NewLine;
}
textBox1.Text += e.Msg;
}
}
private void button1_Click(object sender, EventArgs e)
{
serviceCallback.Subscribe();
}
private void button2_Click(object sender, EventArgs e)
{
serviceCallback.Unsubscribe();
}
}
}
测试回调类:
namespace TestClient
{
[CallbackBehaviorAttribute(UseSynchronizationContext = true)]
class ServiceCallback : IWcfSubscriberContract
{
WcfPublisherService myService
= WcfPublisherService.TheInstance();
string callbackKey = Guid.NewGuid().ToString();
public delegate void NewMessageEventHandler(object sender, NewMessageEventArgs e);
public event NewMessageEventHandler NewMessage;
protected virtual void OnNewMessage(string msg)
{
if (NewMessage != null)
{
NewMessage(this, new NewMessageEventArgs(msg));
}
}
public void Subscribe()
{
try
{
myService.Subscribe(callbackKey);
}
catch (Exception ex)
{
OnNewMessage("exception: " + ex.Message);
}
}
public void Unsubscribe()
{
try
{
myService.UnSubscribe(callbackKey);
}
catch (Exception ex)
{
OnNewMessage("exception: " + ex.Message);
}
}
public void BarriersChanged(OAInterface.BarrierLines barrierLines)
{
OnNewMessage("new barrier lines");
}
}
public class NewMessageEventArgs : EventArgs
{
public NewMessageEventArgs(string msg)
{
this.Msg = msg;
}
public string Msg { get; set; }
}
}
最佳答案
正如评论中所讨论的那样,如果您直接创建服务类型的实例(而不是 WCF 代理/客户端 channel ),然后对其调用方法,则没有 OperationContext。当您的操作在服务中运行时,WCF 会提供一个 OperationContext 实例。
关于c# - 当前 OperationContext 在 WCF Windows 服务中为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15205337/
我们在深层抽象程序集中的某个地方有一个 WCF 行为,它从 OperationContext.Current 读取数据,当从 Task 中执行此代码时,OperationContext.Current
我做了一个小项目(WCF + REST),但遇到了一个小问题。我想制作我的授权和身份验证类。 我的授权类: //validate api key public class BasicAuthoriza
我有一个 WCF 服务定义如下: [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirements
我有一个通过 net.tcp 绑定(bind)配置的 WCF 服务。我可以通过客户端访问服务并调用它的方法。我也可以访问 OperationContext.Current。如: [ServiceCon
OperationContext.Current.GetCallbackChannel 实际上做了什么?它如何识别每个客户? 我的 WCF 服务遇到问题。如果超过两个用户连接到该服务,我从服务发送到客
在我的 WebApi Controller 中,我尝试调用 .asmx SOAP 服务。 我使用 VS2015 生成 SoapClient 代理作为服务引用。 我的主要问题是我需要设置授权 heade
目前我面临着对生产代码进行单元测试的挑战。我们有一个函数可以从传入的 WCF 消息中检索 IP 地址。 public void DoSomething(){ var ipAddressFrom
我想为我的应用程序(.NET、C#)中的持续操作实现特定的上下文,以便应用程序启动和执行的代码可以访问它。 问题是上下文没有像某些 API 那样作为对象传递。 我想在 WCF 中实现类似于 Opera
我有一个实现 IServiceBehavior 的属性来保护我的 WCF 服务,如下所示: public class AuthorizedServiceAttribute : Attribute, I
我正在尝试在某个方法中调用回调合约方法,该方法在触发某个事件时调用。但是当我试图获取 OperationContext.Current 时出现异常。如何只在触发此事件时调用回调方法。 private
我已经实现了一个订阅/发布(为了我自己的乐趣)WCF 服务,它工作得相当好。就像我看到的所有博客和书籍一样,它们都使用 OperationContext 来获取客户端回调地址。阅读了一下,由于很多人说
如果我使用像下面这样的代码将消息 header 添加到我的 OperationContext 中,所有 future 的传出消息是否都包含从我的应用程序的相同“运行”定义的任何新 ClientProx
使用 WCF 中的 C#5 Async-Await,如果其余代码在不同的线程上继续执行等待,我们将释放当前操作上下文。 (OperationContext.Current 为空)。 我正在开发调用另一
我想知道在 WCF 服务主机实例的实例变量中存储和引用 OperationContext.Current 对象是否明智。服务主机设置为 InstanceContextMode.PerCall,因此每个
我们想模拟 OperationContext用于测试目的的类。我们正在使用“模拟”。但是OperationContext是一个密封类,不能被 mock 。因此,我们试图创建一个虚拟 Operation
我正在运行托管在 Windows 服务中的 WCF 服务; WCF 服务的依赖项是通过 Unity 注入(inject)的,这一切都很好。因此,该服务也很容易为其编写单元测试。 最近,我向服务中添加了
我正在尝试使用 TDD 为 System.ServiceModel.ObjectContext 开发一个扩展(IExtension)。该扩展将用作与温莎城堡一起使用的生命周期管理器的存储。 问题在于抽
我在 IIS 中托管 WCF 服务。我在 IIS 中为站点设置了多个主机名绑定(bind)。但是,在向任何非默认绑定(bind)发出请求时,OperationContext.IncomingMessa
我想从 OperationContext.Current 访问请求 header 信息,是否可以安全地假设如果 WCF 服务有数千次调用,事情不会混淆,无论 InstanceContextMode 是
我正在查看 System.ServiceModel.OperationContext http://msdn.microsoft.com/en-us/library/system.servicemod
我是一名优秀的程序员,十分优秀!