我想这个问题已经被问了很多次了,但是我似乎不能让它工作,即使我读了微软的文章和StackOverflow上的一些主题。
我对IPC/WCF很陌生,但我开始在我的WPF应用程序中使用它,因为它很简单。现在我遇到了一个问题,好像没法去上班。问题很简单,我想传递一个List of <T>
到服务器(这也是一个WPF应用程序)。我可以看到它是使用Fiddler发送的,但是在序列化之后什么都没有发生。在我看来,这是因为它被转换成了一个数组。所以我把它调整为一个数组,但仍然没有值。
为了解释更多,让我添加一些代码:
共享(及复印件;粘贴)DataContract客户端和服务器之间:
<DataContract>
<AttributeUsage(AttributeTargets.Class)>
<KnownType(GetType(List(Of Integer)))>
Public Class UnauthorizedFolder
<DataMember>
Public Property RootFolderId As Integer
<DataMember>
Public Property ChildIds As New List(Of Integer)
Public Overrides Function ToString() As String
Return $"{RootFolderId} = [{String.Join(",", ChildIds)}]"
End Function
End Class
共享(及复印件;合同粘贴)客户端和服务器之间
<ServiceContract()>
Public Interface MyRemoteControls
<OperationContract()> Sub UserAccessGranted(UserName As String, lstUnauthorisedFolders As List(Of UnauthorizedFolder))
<OperationContract()> Sub UserAccessRevoked()
End Interface
设置服务端:
_ServiceHost = New ServiceHost(GetType(RemoteControl), New Uri("http://127.0.0.1:8080/MyService"))
_ServiceHost.AddServiceEndpoint(GetType(MyRemoteControls), New BasicHttpBinding(), "MyService")
_ServiceHost.Open()
服务器远程类:
Class RemoteControl
Implements MyRemoteControls
Dim strCurrentUserName As String
Public Sub UserAccesGranted(UserName As String, lstUnauthorisedFolders As List(Of UnauthorizedFolder)) Implements MyRemoteControls.UserAccessGranted
strCurrentUserName = UserName
If lstUnauthorisedFolders Is Nothing OrElse lstUnauthorisedFolders.Count <= 0 Then
Debug.Print($"{Now.ToString("hh:mm:ss")} - UserAccesGranted: [{strCurrentUserName}] - All Folders{vbCrLf}")
Else
Debug.Print($"{Now.ToString("hh:mm:ss")} - UserAccesGranted: [{strCurrentUserName}] {lstUnauthorisedFolders .Count}{vbCrLf}")
End If
End Sub
Public Sub UserAccesRevoked() Implements MyRemoteControls.UserAccessRevoked
Debug.Print($"{Now.ToString("hh:mm:ss")} - UserAccesRevoked: [{strCurrentUserName}]{vbCrLf}")
End Sub
End Class
现在从客户端我可以看到XML被发送到服务器
<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<UserAccessGranted
xmlns="http://tempuri.org/">
<UserName>User 1(1)</UserName>
<lstUnauthorisedFolders
xmlns:a="http://schemas.datacontract.org/2004/07/MyApp"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:UnauthorizedFolder>
<a:ChildIds
xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:int>1</b:int>
<b:int>2</b:int>
<b:int>4</b:int>
<b:int>5</b:int>
<b:int>8</b:int>
</a:ChildIds>
<a:RootFolderId>3</a:RootFolderId>
</a:UnauthorizedFolder>
</lstUnauthorisedFolders>
</UserAccessGranted>
</s:Body>
</s:Envelope>
所以客户端发送一切正确的方式(使用ChannelFactory
),但似乎在服务器上序列化,lstUnauthorisedFolders
没有序列化。
我看到了一些答案,描述我必须调整servicerreference中的类型从Array
到Generic.List
来解决这个问题,但在WPF而不是ASP的服务器应用程序中。NET i没有这样的设置?
我测试过的一个解决方案是使用Newtonsoft.JSON
将List of <T>
作为字符串传递,然后在服务器端将其序列化回List of <T>
,但我发现这是一个丑陋的解决方案,因为List of <T>
也支持XML。
尝试如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication184
{
class Program
{
const string FILENAME = @"c:temptest.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringReader sReader = new StringReader(xml);
XmlReader xReader = XmlReader.Create(sReader);
XmlSerializer serializer = new XmlSerializer(typeof(Envelope));
Envelope envelope = (Envelope)serializer.Deserialize(xReader);
}
}
[XmlRoot(Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
public Body Body { get; set; }
}
public class Body
{
[XmlElement(Namespace = "http://tempuri.org/")]
public UserAccessGranted UserAccessGranted { get; set; }
}
public class UserAccessGranted
{
public string UserName { get; set; }
public lstUnauthorisedFolders lstUnauthorisedFolders { get; set; }
}
public class lstUnauthorisedFolders
{
[XmlElement(Namespace = "http://schemas.datacontract.org/2004/07/MyApp")]
public UnauthorizedFolder UnauthorizedFolder { get; set; }
}
public class UnauthorizedFolder
{
[XmlElement(Namespace = "http://schemas.datacontract.org/2004/07/MyApp")]
public ChildIds ChildIds { get; set; }
[XmlElement(Namespace = "http://schemas.datacontract.org/2004/07/MyApp")]
public int RootFolderId { get; set; }
}
public class ChildIds
{
[XmlElement(ElementName = "int", Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public List<int> numbers { get; set; }
}
}