Commit b7320a4a authored by 潘栩锋's avatar 潘栩锋 🚴

添加更多说明

parent 6f530842
# WSCF
WSCF (WebSocket Communication Foundation) 就是 抄 微软的WCF, 但有 推送功能。
\ No newline at end of file
WSCF (WebSocket Communication Foundation) 就是 抄 微软的WCF, 但有 推送功能。
# 1. 项目描述
**WSCF** 是项目 <br>
**WSCF.Test** 项目测试 库<br>
**WSCF.Test.Client** 测试客户端<br>
**WSCF.Test.Server** 测试服务器<br>
<br>
<br>
<br>
<br>
# 2. 使用方法
1. 定义服务接口 IXXXService
//WSCF.Test/IService/IFooService.cs
2. 在服务器中,创建 类 XXX 实现 IXXXService 接口
//WSCF.Test/Server/Foo.cs
3. 在服务器中,
//WSCF.Test/Server.WsProxy/WsProxy.cs
```csharp
wssv = new WebSocketServer($"ws://{addr}/");
wssv.AddWebSocketService<Reflect_Proxy>("/Foo", (wsproxy) =>
{
//IFooService 服务接口, foo 继承IFooService的类Foo 的对象
wsproxy.Init(typeof(IFooService), foo);
});
//如果有多个服务,就继续 wssv.AddWebSocketService<Reflect_Proxy>
this.wssv.Start();
```
4. 在客户端中
创建 类 XXXServiceClient 实现 IXXXService 接口
//WSCF.Test/ServiceClient/FooServiceClient.cs
最后使用
```csharp
//后面的 "foo" 是连接的名字,对应 地址 { Addr = "127.0.0.1:5540", ConnName = "foo" }
// WSCF.FObjServiceClientManager 负责维护这个地址列表
Foo = new WSCF.Test.ServiceClient.FooServiceClient("Foo", true, "foo");
```
<br>
<br>
<br>
<br>
# 3. 描述
服务代理 它还另一个版本 在项目 FObjBase.Reflect
1. 如果代理的对象为 INotifyPropertyChanged, 对象内的 property 改变,能推送给客户端( [JsonIgnore] 除外);
2. 代理的对象不为INotifyPropertyChanged, 但 对象内的 property
+ 是 [PropertyPush],
+ 且是 INotifyPropertyChanged,
+ 且 只能是get,不能有set
那这个 property 内的 子property 改变,也会推送给 客户端 且 子property 是 [PropertyPush],会继续向下全部注册 PropertyChanged, 也推送给 客户端;
3. 客户端 可以通过 Call(.....) 调用 服务 的function, function返回的内容,需要通过[Call(...)] 定义; 且function 必须是
```csharp
void function(object param1, object param2,object paramN, AsyncCBHandler asyncDelegate, object asyncContext);
//必须有参数 AsyncCBHandler asyncDelegate, object asyncContext, 名字不能改。 前面的 param1~paramN, 多少个都行
```
4. 服务中的event, 通过 [Push(...)] 可以推送给客户端, 但event 只能是 EventHandler
```csharp
[Push(typeof(BulkDBTempFrameChangedEventArgs))]
public event EventHandler TempFrameChanged;
```
......@@ -28,6 +28,9 @@ namespace WSCF.Test.Client
{
InitializeComponent();
//创建连接
//正常情况 FObjServiceClientManager 从配置文件读取
//最终的目标方便 UnityContainer 使用
WSCF.FObjServiceClientManager.Instance.DefaultAddrs.Add(new ConnDefaultAddr() { Addr = "127.0.0.1:5540", ConnName = "foo" });
mainVm = new MainVm();
......@@ -56,7 +59,7 @@ namespace WSCF.Test.Client
}
public void Init()
{
//后面的 "foo" 是连接的名字,对应 上面 { Addr = "127.0.0.1:5540", ConnName = "foo" }
Foo = new WSCF.Test.ServiceClient.FooServiceClient("Foo", true, "foo");
}
void Add()
......
......@@ -7,16 +7,91 @@ using System.Threading.Tasks;
namespace WSCF.Test.IService
{
/// <summary>
/// 服务接口 继承INotifyPropertyChanged的,PropertyChanged事件 已经在基类实现,不需要显式 Push() 声明
/// </summary>
public interface IFooService:INotifyPropertyChanged
{
string Msg{ get; set; }
int Number { get; }
DateTime AddFuncTime { get; }
/// <summary>
/// 只支持 数组, List, ObservableCollection 都不支持
/// </summary>
int[] Abc { get; }
/// <summary>
/// ProfileParam 是 INotifyPropertyChanged, 而且它是单例,
/// 只能通过 PropertyPush 声明, 才能注册 Param.PropertyChanged 事件;
/// 实现 Param 里面的 属性变化,同步到 客户端与服务器
/// 这个 Param 里面不能用 method, 它只是 property 的集合体
/// 当 ProfileParam内还有 property 是 INotifyPropertyChanged 要继续通过 PropertyPush 声明
/// </summary>
[PropertyPush]
ProfileParam Param { get; }
/// <summary>
/// 只要是event, 只能是 EventHandler类,
/// EventArgs e, 通过 Push() 声明
/// DataChangedEventArgs 必须是 继承 EventArgs
/// </summary>
[Push(typeof(DataChangedEventArgs))]
event EventHandler DataChanged;
/// <summary>
/// 带返回的方法, 只能通过 回调函数的方法返回。 asyncDelegate
/// 返回的数据类型 通过 Call() 声明, 对应 asyncDelegate(asyncContext, retData) 中的 retData
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="asyncDelegate"></param>
/// <param name="asyncContext"></param>
[Call(typeof(FooServiceAddReponse))]
void Add(int a, int b, AsyncCBHandler asyncDelegate, object asyncContext);
/// <summary>
/// 这个方法 不带返回,会自动 添加 Call() , 不需要手动写
/// </summary>
/// <param name="param"></param>
void Apply(ProfileParam param);
}
public class FooServiceAddReponse
{
public int result;
}
public class DataChangedEventArgs:EventArgs
{
public DateTime Time;
public string Msg;
}
public class ProfileParam : INotifyPropertyChanged
{
#region 正常运行参数
/// <summary>
/// 产品名称
/// </summary>
public string PName { get; set; } = "pname";
/// <summary>
/// 目标值
/// </summary>
public double Target { get; set; } = 100;
#endregion
/// <summary>
///
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
}
}
......@@ -18,7 +18,7 @@ namespace WSCF.Test.Server.WsProxy
{
wsproxy.Init(typeof(IFooService), foo);
});
//如果有多个服务,就继续 wssv.AddWebSocketService<Reflect_Proxy>
this.wssv.Start();
}
}
......
......@@ -13,8 +13,15 @@ namespace WSCF.Test.Server
{
public int Number { get; protected set; }
public DateTime AddFuncTime { get; protected set; }
public string Msg { get; set; }
public int[] Abc { get; protected set; }
public ProfileParam Param { get; } = new ProfileParam();
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler DataChanged;
public DispatcherTimer timer = new DispatcherTimer();
public Foo()
......@@ -25,9 +32,27 @@ namespace WSCF.Test.Server
timer.Start();
}
int timecnt = 0;
private void Timer_Tick(object sender, EventArgs e)
{
Number++;
List<int> abc = new List<int>();
Random r = new Random();
for (int i = 0; i < 3; i++) {
abc.Add(r.Next(10));
}
Abc = abc.ToArray();
timecnt++;
if (timecnt > 3) {
timecnt = 0;
DataChanged?.Invoke(this, new DataChangedEventArgs()
{
Time = DateTime.Now,
Msg = "hello " + Msg
}); ;
}
}
public void Add(int a, int b, AsyncCBHandler asyncDelegate, object asyncContext)
......@@ -36,5 +61,11 @@ namespace WSCF.Test.Server
AddFuncTime = DateTime.Now;
asyncDelegate?.Invoke(asyncContext, new FooServiceAddReponse() { result = Number });
}
public void Apply(ProfileParam param)
{
Param.PName = param.PName;
Param.Target = param.Target;
}
}
}
......@@ -7,23 +7,50 @@ using WSCF.Test.IService;
namespace WSCF.Test.ServiceClient
{
//很机械式 按格式填就好,下一个版本,会有软件 自动生成下面的代码
public class FooServiceClient : Reflect_SeviceClient, IFooService
{
//注明要实现的服务接口
protected override Type InterfaceType => typeof(IFooService);
//只要是property,get, set 都必须 public 就算 IFooService.Number 只有 Get没有Set
public int Number { get; set; }
public DateTime AddFuncTime { get; set; }
public string Msg { get; set; }
public int[] Abc { get; set; }
public ProfileParam Param { get; } = new ProfileParam();
public FooServiceClient(string serverName, bool isByConnName, string addrOrConnName):base(serverName, isByConnName, addrOrConnName)
{
}
public event EventHandler DataChanged;
/// <summary>
/// 只要是事件,都只能手动 创建 Trigger_xxxx(xxxx为event名称),作为触发事件的函数,该函数的参数类型就是Push 里面定义的
/// </summary>
/// <param name="e"></param>
public void Trigger_DataChanged(DataChangedEventArgs e)
{
DataChanged?.Invoke(this, e);
}
public void Add(int a, int b, AsyncCBHandler asyncDelegate, object asyncContext)
{
//Call 的 parameters 必须写 为 new {a, b} 这样简写模式, 因为需要匹配 参数名字
Call(nameof(Add), new { a, b }, asyncDelegate, asyncContext);
}
public void Apply(ProfileParam param)
{
//如果连参数也没有,只需要写 Call(nameof(Apply));
Call(nameof(Apply), new { param });
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment