参考:https://www.cnblogs.com/JLZT1223/p/6062613.html
和一般连接WCF的不同之处:
1.要手动添加必要的dll
2.要手动创建客户端代码(用svcutil.exe)
我用D盘的绝对路径是因为不加路径会导致无法创建文件,以管理员方式启动cmd的话应该就没问题。
System.Runtime.Serialization.dll不用添加,添加了会说已经存在。我的Unity是5.6.03f
生成文件内容:
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:2.0.50727.8825
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="WCFServiceLib", ConfigurationName="ICommonService")]
public interface ICommonService {
[System.ServiceModel.OperationContractAttribute(Action="WCFServiceLib/ICommonService/Hello", ReplyAction="WCFServiceLib/ICommonService/HelloResponse")]
string Hello(string name);
[System.ServiceModel.OperationContractAttribute(Action="WCFServiceLib/ICommonService/GetString", ReplyAction="WCFServiceLib/ICommonService/GetStringResponse")]
string GetString(int count, string item);
[System.ServiceModel.OperationContractAttribute(Action="WCFServiceLib/ICommonService/SendString", ReplyAction="WCFServiceLib/ICommonService/SendStringResponse")]
string SendString(string msg);
[System.ServiceModel.OperationContractAttribute(Action="WCFServiceLib/ICommonService/GetData", ReplyAction="WCFServiceLib/ICommonService/GetDataResponse")]
WCFModels.DataInfo GetData(string id, string name);
[System.ServiceModel.OperationContractAttribute(Action="WCFServiceLib/ICommonService/SendData", ReplyAction="WCFServiceLib/ICommonService/SendDataResponse")]
string SendData(WCFModels.DataInfo data);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface ICommonServiceChannel : ICommonService, System.ServiceModel.IClientChannel {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class CommonServiceClient : System.ServiceModel.ClientBase<ICommonService>, ICommonService {
public CommonServiceClient() {
}
public CommonServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public CommonServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public CommonServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public CommonServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public string Hello(string name) {
return base.Channel.Hello(name);
}
public string GetString(int count, string item) {
return base.Channel.GetString(count, item);
}
public string SendString(string msg) {
return base.Channel.SendString(msg);
}
public WCFModels.DataInfo GetData(string id, string name) {
return base.Channel.GetData(id, name);
}
public string SendData(WCFModels.DataInfo data) {
return base.Channel.SendData(data);
}
}
namespace WCFModels {
using System.Runtime.Serialization;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="DataInfo", Namespace="http://schemas.datacontract.org/2004/07/WCFModels")]
public partial class DataInfo : object, System.Runtime.Serialization.IExtensibleDataObject {
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private string IdField;
private string NameField;
private string TextField;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Id {
get {
return this.IdField;
}
set {
this.IdField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name {
get {
return this.NameField;
}
set {
this.NameField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Text {
get {
return this.TextField;
}
set {
this.TextField = value;
}
}
}
}
脚本中测试
private void TestCommonServiceClient()
{
CommonServiceClient client = GetCommonServiceClient(WCFClient.Instance.Ip);
client.SendString("CommonServiceClient Start");
WCFModels.DataInfo data = client.GetData("1", "2");
Write(string.Format("{0},{1}", data.Id, data.Name));
}
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;
}
可以
接下来试试这部分代码在Hololens中能不能正常运行。
当初的最终目标就是在Hololens中使用wcf的,因为Hololens的运行环境是UWP,所以先研究了在UWP中使用WCF,然后再通过接口的方式在脚本中使用。
这么看来可能不需要这样。
等待后续测试吧,说不定在Hololens中不能使用呢。
=======================================================
svcutil生成的代码中的 数据类型 和 Unity引用的dll中的数据类型重复了,必须手动删除那部分代码。想让svcutil只生成客户代码,添加-reference:参数,没用,还是会生成。
用VS生成的话,只要客户端项目引用了数据类型所在的dll就不会重新创建这些类型的代码了了。
但是用VS添加服务引用生成的代码中包含异步调用的代码...
将客户端项目修改为3.5的(原本是4.5的),异步调用代码就没有了。
不使用svcutil.exe,还是用VS 项目生成代码吧,再移动到Unity中好了。
==========================================================
考虑到异步处理,还是用回调函数的方式处理返回结果,做一个Unity版本的WCFClient
将UWP中的代码移动到Unity中,相应的修改代码(基本上去掉async和await就行了),语法没问题,测试。
问题1:
获取列表数据时数量没问题,但是无法获取具体数据内容。发现是因为数据类中没有添加DataContract和DataMember,但是用UWP的话可以,之前有测试过的,没加相当于全加上的,但是这样看来在这里不适用。加上合适的DataContract和DataMember就可以了,加[Serializable]没用(《WCF服务编程》里面是说可以的)。
问题2:
MainTest:System.Xml.XmlException: Text content buffer exceeds the quota limitation at 5339. 12220 bytes and should be less than 8192 bytes
at System.Xml.XmlBinaryDictionaryReader.Alloc (Int32 size) [0x00000] in <filename unknown>:0
at System.Xml.XmlBinaryDictionaryReader.ReadTextOrValue (Byte ident, System.Xml.NodeInfo node, Boolean canSkip) [0x00000] in <filename unknown>:0
at System.Xml.XmlBinaryDictionaryReader.Read () [0x00000] in <filename unknown>:0
at System.Xml.XmlReader.Skip () [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer, Boolean empty) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.SerializationMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.CollectionTypeMap.DeserializeContent (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.SerializationMap.DeserializeObject (System.Xml.XmlReader reader, System.Runtime.Serialization.XmlFormatterDeserializer deserializer) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeByMap (System.Xml.XmlQualifiedName name, System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.DeserializeCore (System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Type type, System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlFormatterDeserializer.Deserialize (System.Xml.XmlReader reader, System.Type type, System.Runtime.Serialization.KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, System.String name, System.String ns, Boolean verifyObjectName) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.DataContractSerializer.ReadObject (System.Xml.XmlDictionaryReader reader, Boolean verifyObjectName) [0x00000] in <filename unknown>:0
at System.Runtime.Serialization.XmlObjectSerializer.ReadObject (System.Xml.XmlDictionaryReader reader) [0x00000] in <filename unknown>:0
at System.ServiceModel.Dispatcher.DataContractMessagesFormatter.MessageToParts (System.ServiceModel.Description.MessageDescription md, System.ServiceModel.Channels.Message message) [0x00000] in <filename unknown>:0
at System.ServiceModel.Dispatcher.BaseMessagesFormatter.DeserializeReply (System.ServiceModel.Channels.Message message, System.Object[] parameters) [0x00000] in <filename unknown>:0
at System.ServiceModel.ClientRuntimeChannel.Request (System.ServiceModel.Description.OperationDescription od, System.Object[] parameters) [0x00000] in <filename unknown>:0
at System.ServiceModel.ClientRuntimeChannel.DoProcess (System.Reflection.MethodBase method, System.String operationName, System.Object[] parameters) [0x00000] in <filename unknown>:0
at System.ServiceModel.ClientRuntimeChannel.Process (System.Reflection.MethodBase method, System.String operationName, System.Object[] parameters) [0x00000] in <filename unknown>:0
UnityEngine.Debug:Log(Object)
应该是反序列化时数据量太大了。是因为有一个字符串属性的字符串内容长度为12220导致的。
两个都是反序列化的问题,一般来说是没问题的(正常添加DataContract,一个字符串属性长度不要太大)。
结论:可以使用。
=====================================================================
打包成Hololens的SLN时有问题,
1. System.ServiceModel.dll重复了,说是已经存在了。修改dll的设置,WSAPlayer不选,只在Unity中使用。
2. 前面生成的客户端代码不能用,特性相关的dll不能使用。修改代码,整个WCF客户端代码文件用#if UNITY_EDITOR包起来,只在Unity中测试用。
虽然在Hololens中无法使用,但是不如说正好接上UWP中的版本,一个用于在Unity中测试,测试好后再打包到UWP中测试,能显著减少打包成UWP的次数。