前面确认了在Hololens(Unity)中能够使用WCF,测试的方式是调用服务,但是并没有接收数据。
注意:在Unity中无法使用Asyn和Task<>。
使用Async会出现:error CS1644: Feature `asynchronous functions' cannot be used because it is not part of the C# 4.0 language specification
使用Task,直接找不到该类。
1.Unity中如何使用WCF
前面在Unity中使用WCF是通过接口
在Unity中定义接口
public interface IWCFClient
{
void SendString(string msg);
void TestReceive(int count);
void Test();
}
以及一个单例对象(静态类也行)
public class WCFClientFactory: IWCFClient
{
public static WCFClientFactory Instance=new WCFClientFactory();
public IWCFClient Client;
public void SendString(string msg)
{
if (Client != null)
{
Client.SendString(msg);
}
else
{
Debug.Log(msg);
}
}
public void Test()
{
if (Client != null)
{
Client.Test();
}
else
{
Debug.Log("WCFClientFactory.Test");
}
}
public void TestReceive(int count)
{
if (Client != null)
{
Client.TestReceive(count);
}
else
{
Debug.Log("WCFClientFactory.TestReceive");
}
}
}
注意这里的 public IWCFClient Client;
然后在UWP(启动项目中)添加服务引用,在App中初始化Client
public App()
{
this.InitializeComponent();
SetupOrientation();
appCallbacks = new AppCallbacks();
ServiceClientFactory.Test();
WCFClientFactory.Instance.Client=new WCFClient();
}
public class WCFClient:IWCFClient
{
public async void SendString(string msg)
{
CommonServiceClient client = ServiceClientFactory.GetCommonServiceClient("192.168.253.1");
await client.SendStringAsync(msg);
await client.CloseAsync();
}
public void Test()
{
ServiceClientFactory.Test();
}
public async void TestReceive(int count)
{
CommonServiceClient client = ServiceClientFactory.GetCommonServiceClient("192.168.253.1");
string msg=await client.GetStringAsync(count, "a");
await client.CloseAsync();
ServiceClientFactory.Log("Receive:" + msg.Length);
}
}
public static class ServiceClientFactory
{
public static void Test()
{
Log("Start Test");
TestCommonServiceClient();
}
public static CommonServiceClient GetCommonServiceClient(string ip)
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.MaxReceivedMessageSize = int.MaxValue;
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://" + ip + ":8001/CommonService");
CommonServiceClient currentClient = new CommonServiceClient(binding, endpointAddress);
return currentClient;
}
public static async void TestCommonServiceClient()
{
try
{
CommonServiceClient client = GetCommonServiceClient("192.168.253.1");
await client.HelloAsync("TestClient");
await client.GetStringAsync(10, "A");
await client.SendStringAsync("ABCD");
await client.CloseAsync();
}
catch (Exception ex)
{
Log(ex.Message);
}
}
public static async void Log(string msg)
{
CommonServiceClient client = GetCommonServiceClient("192.168.253.1");
await client.SendStringAsync("[Log]:"+msg);
await client.CloseAsync();
}
}
最后,在Unity脚本中使用
public class Commands : MonoBehaviour {
void OnSelect()
{
if (!this.GetComponent<Rigidbody>())
{
var rigidbody = this.gameObject.AddComponent<Rigidbody>();
rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
WCFClientFactory.Instance.SendString("Commands.OnSelect");
}
}
前面写了TestRecevie相关的代码,但是,现在实际上是无法将返回信息显示在Unity中的。
2.显示返回信息
Unity中:
IWCFClient添加
string ReceiveString(int count);
WCFClientFactory添加
public string ReceiveString(int count)
{
if (Client != null)
{
return Client.ReceiveString(count);
}
else
{
Debug.Log("WCFClientFactory.RecevieString");
return "";
}
}
UWP中:
WPFClient中添加
public string ReceiveString(int count)
{
CommonServiceClient client = ServiceClientFactory.GetCommonServiceClient("192.168.253.1");
string msg = await client.GetStringAsync(count, "a");
await client.CloseAsync();
return msg;
}
结果
await必须和async配对,async的函数必须是void 或者 Task 或者 Task<T>
如果将string改成Task<string>的话,接口就要改,就改到Unity中了,在UWP环境中是可以改的,回到Unity环境就不行了。
改成用回调函数的方式:
Unity中:
IWCFClient修改
void ReceiveString(int count,Action<string> callback);
WCFClientFactory修改
public void ReceiveString(int count, Action<string> callback)
{
if (Client != null)
{
Client.ReceiveString(count, callback);
}
else
{
Debug.Log("WCFClientFactory.RecevieString");
if (callback != null)
{
callback("");
}
}
}
UWP中:
WPFClient中修改
public async void ReceiveString(int count, Action<string> callback)
{
CommonServiceClient client = ServiceClientFactory.GetCommonServiceClient("192.168.253.1");
string msg = await client.GetStringAsync(count, "a");
await client.CloseAsync();
if (callback != null)
{
callback(msg);
}
}
Unity脚本调用,OnSelect是
Hololens开发(9)中的点击后调用的函数
public class TestReceive : MonoBehaviour {
public int Count = 1;
private void OnSelect()
{
TestResult.Intance.Write("TestReceive.OnSelect");
gameObject.transform.Translate(Vector3.up);
WCFClientFactory.Instance.ReceiveString(Count, msg =>
{
TestResult.Intance.Append("Msg:" + msg);
});
}
可以!
TestResult脚本
using UnityEngine;
using UnityEngine.UI;
public class TestResult : MonoBehaviour {
public static TestResult Intance;
public Text text;
private string _txt;
private bool _isDirty;
void Awake()
{
Intance = this;
}
void Update()
{
if (_isDirty)
{
Write(_txt);
_isDirty = false;
}
}
public void WriteAsync(string msg)
{
_isDirty = true;
_txt = msg + "\n";
}
public void AppendAsync(string msg)
{
_isDirty = true;
_txt += msg + "\n";
}
public void Write(string msg)
{
Debug.Log(msg);
try
{
text.text = msg + "\n";
}
catch (System.Exception ex)
{
text.text = ex.ToString();
}
}
public void Clear()
{
text.text = "";
}
public void Append(string msg)
{
Debug.Log(msg);
try
{
text.text += msg+"\n";
}
catch (System.Exception ex)
{
text.text = ex.ToString();
}
}
}
注意:因为async是异步调用,也就是子线程,在Unity中子线程里面是不能修改Object这些Unity物体的,在线程中也不能修改UI的,需要通过Update来执行相应的回调函数行为(显示结果到UI上)。不然会抛出异常,另外因为异常是在子线程中抛出的,必须在子线程中接。