使Windows服务将活动值发送回WCF客户端
本文关键字:WCF 客户端 Windows 服务 活动 | 更新日期: 2023-09-27 18:18:01
我有一个使用net的Windows服务。管道作为WCF服务器和Windows窗体客户端连接到它。有一个名为ConfigSettings的类,其中包含我希望客户端查询的值。
我想让客户端读取服务使用的serviceConfig实例中的当前值。最终,我希望客户端改变其中的值,但首先要循序渐进。
表单可以通过命名管道与服务器通信,但是` return serviceConfig `正在向客户端发送一个新的空实例。我需要服务正在积极使用的数据(即serviceConfig)。设置1 = x;serviceConfig。seting2 = "foo";)
Windows服务和WCF服务器代码(更新到工作版本):
using System.IO;
using System.ServiceModel;
using System.ServiceProcess;
namespace WindowsServiceTest
{
public partial class Service1 : ServiceBase
{
internal static ServiceHost myServiceHost = null;
//this is the master config that the service uses
public static ConfigSettings serviceConfig = new ConfigSettings();
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(WCFService1));
myServiceHost.Open();
//set active default settings
serviceConfig.Setting1 = 1;
serviceConfig.Setting2 = "initial.Setting2:" + serviceConfig.Setting1;
}
protected override void OnStop()
{
if (myServiceHost != null)
{
myServiceHost.Close();
myServiceHost = null;
}
}
}
public partial class WCFService1 : IService1
{
public ConfigSettings GetConfig()
{
return Service1.serviceConfig;
}
public void SetConfig(ConfigSettings sentConfig)
{
Service1.serviceConfig = sentConfig;
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
ConfigSettings GetConfig();
[OperationContract]
void SetConfig(ConfigSettings sentConfig);
}
public class ConfigSettings
{
public int Setting1 { get; set; }
public string Setting2 { get; set; }
public ConfigSettings() { }
}
}
客户端像这样检索配置(更新了一些更改):
using System;
using System.ServiceProcess;
using System.Windows.Forms;
using WindowsServiceTest;
namespace WindowsServiceTestForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ConfigSettings config = new ConfigSettings();
//GetConfig()
private void button1_Click(object sender, EventArgs e)
{
ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "Service1");//this will grant permission to access the Service
//get the current config and display
config = myService.GetConfig();
MessageBox.Show(config.Setting1 + "'r'n" + config.Setting2, "config");
myService.Close();
}
//SetConfig(ConfigSettings)
private void button2_Click(object sender, EventArgs e)
{ //make changes to values
config.Setting1 += 1;
config.Setting2 = "new.Setting2:" + config.Setting1;
ServiceReference1.Service1Client myService = new ServiceReference1.Service1Client();
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "Service1");//this will grant permission to access the Service
//send the new config
myService.SetConfig(config);
myService.Close();
}
}
}
更新:也许我想要做的事有点过头了。我似乎碰到了WCF和Windows Service之间的隔膜。
你将如何处理这个问题?
- 需要Form进行配置的Windows服务。
- 服务启动时,从磁盘加载一个config.xml文件。(一个序列化类)
- 当GUI启动时,我想:
- 检索当前配置,
- 做一些修改,
- 将其推回服务,
触发服务重新读取和响应新的配置。
我试图避免静态/写入配置文件到磁盘,并告诉服务重新读取它。"看起来"WCF是可行的。
更新2 似乎只要将服务中的主配置更改为静态,WCF服务就可以直接访问它。我可以发誓我在发帖之前就这么做了,但我想没有。
我还将Service1的命名分离为上面的WCFService1,但事实证明这无关紧要,并且无论哪种方式都可以工作。
新的完整代码已在上面更新。
你正在混淆Windows服务和WCF服务-并试图让他们都在同一个类-虽然这是可能的-它可能更容易理解,如果你把它们分成两个类。
在您的示例中,Windows服务启动,创建自己的新实例作为WCF服务,然后在Windows服务实例中设置配置元素,这意味着配置在WCF服务实例中为空。
试试这个
using System.ServiceModel;
using System.ServiceProcess;
namespace WindowsServiceTest
{
public partial class Service1 : ServiceBase
{
internal static ServiceHost myServiceHost = null;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
if (myServiceHost != null)
{
myServiceHost.Close();
}
myServiceHost = new ServiceHost(typeof(WCFService1 ));
myServiceHost.Open();
}
protected override void OnStop()
{
if (myServiceHost != null)
{
myServiceHost.Close();
myServiceHost = null;
}
}
}
public class WCFService1 : IService1
{
public WCFService1()
{
//change master settings from null
myConfig.Setting1 = "123";
myConfig.Setting2 = "456";
}
//this is the master config that the service uses
public ConfigSettings myConfig = new ConfigSettings();
public ConfigSettings GetConfig()
{
return myConfig;
}
}
[ServiceContract]
public interface IService1
{
[OperationContract]
ConfigSettings GetConfig();
}
public class ConfigSettings
{
public string Setting1 { get; set; }
public string Setting2 { get; set; }
public ConfigSettings()
{ }
}
}
有几种方法可以做到这一点(在服务实例中注入依赖)。我将展示其中两个。
这里有一个特殊的情况,因为Windows服务也是你的WCF服务实现。我想很快你就会想把它们分开。因此,我的示例基于一个单独的WCF服务实现。
问题是WCF有一个服务实例模式的概念。默认情况下,它是PerCall
,这意味着创建一个新的Service1
实例来处理每个请求。这使得在这些实例中注入一些东西变得更加困难。
最简单的方法是将实例模式设置为Single
,这意味着只有一个Service1
实例处理所有请求。
第二个比较容易实现:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class Service1Implementation : IService1
{
private ConfigSettings _configSettings;
public Service1(ConfigSettings settings)
{
//now you have the settings in the service
_configSettings = setting;
}
...
}
//in the Windows Service
myServiceHost = new ServiceHost(typeof(Service1Implementation), new Service1Implementation(myConfig));
myServiceHost.Open();
第一个解决方案涉及到创建和指定一个服务实例工厂,基础设施稍后将使用该工厂为每个调用创建服务实例。
工厂提供了自己实例化Service1
并传递配置的可能性。
对你来说,让Windows Service实现IInstanceProvider
更容易:
public class Service1 : ServiceBase, IInstanceProvider
{
private ConfigSettings _myConfig; //assign this member later on
...
//IInstanceProvider implementation
public object GetInstance(InstanceContext instanceContext, Message message)
{
//this is how you inject the config
return new Service1Implementation(_myConfig);
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
...
}
我承认,自从我接触WCF以来已经有一段时间了,但在我看来,你的ConfigSettings
类缺少一些通过WCF使其可序列化所需的属性。
using System.Runtime.Serialization;
[DataContract]
public class ConfigSettings
{
[DataMember]
public string Setting1 { get; set; }
[DataMember]
public string Setting2 { get; set; }
public ConfigSettings()
{ }
}
我不相信让你的Windows服务像你的WCF服务一样运行,就像其他答案所建议的那样,是问题所在。但是我同意最好是把它们分成不同的类