NH+WCF
其中NH中一对多的结构为
IList<Test> Detail
{
}
然后 WCF在客户端
var wsHttp = new BasicHttpBinding(BasicHttpSecurityMode.None);
ChannelFactory<T> channelFactory = new ChannelFactory<T>(wsHttp, "http://" + "localhost:9999" + "/" + url);
但是当客户端调用的时候 去使用 Detail这个属性的时候发现 集合对象变成了【只读】的状态,原因为 生成的 返回对象为IList 但是NH又没有办法做改动,项目中也不能添加服务的引用,请问如何在ChannelFactory 中设置CollectionMappings 属性啊!!
你能用代码解释下你的 Detail 如何是只读的?也就是说你为什么说它是只读的?
因为在 IList 反序列化回来的时候 IList<T> 实际上被序列化成了 Array<T> 成了一个定长数组,而我又不希望在项目中直接 【引用服务】,所以 无法生成
<CollectionMappings>
<CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" />
</CollectionMappings>
的映射。
@啤酒草: 我很好奇的问一句,CollectionMapping 是 NH 中的,还是 WCF 中的?
调用 WCF 服务有两种方式,一种是通过服务引用生成代理类,另一种方式就是手动编写代理类代码。第二种方式你可以参考 StockTrader 中的示例。
@Launcher: CollectionMapping 是WCF中直接应用服务所生生的
<?xml version="1.0" encoding="utf-8"?>
<ReferenceGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="9ab7031e-9d9f-4592-b272-43afcac553e7" xmlns="urn:schemas-microsoft-com:xml-wcfservicemap">
<ClientOptions>
<GenerateAsynchronousMethods>false</GenerateAsynchronousMethods>
<EnableDataBinding>true</EnableDataBinding>
<ExcludedTypes />
<ImportXmlTypes>false</ImportXmlTypes>
<GenerateInternalTypes>false</GenerateInternalTypes>
<GenerateMessageContracts>false</GenerateMessageContracts>
<NamespaceMappings />
<CollectionMappings>
<CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" />
</CollectionMappings>
<GenerateSerializableTypes>true</GenerateSerializableTypes>
<Serializer>Auto</Serializer>
<ReferenceAllAssemblies>true</ReferenceAllAssemblies>
<ReferencedAssemblies />
<ReferencedDataContractTypes />
<ServiceContractMappings />
</ClientOptions>
<MetadataSources>
<MetadataSource Address="http://localhost:9999/TestService/metadata" Protocol="http" SourceId="1" />
</MetadataSources>
<Metadata>
<MetadataFile FileName="TestService.wsdl" MetadataType="Wsdl" ID="22af1928-583f-4e1b-a7f9-d2876daafac8" SourceId="1" SourceUrl="http://localhost:9999/TestService/metadata" />
<MetadataFile FileName="metadata.xsd" MetadataType="Schema" ID="7c9e6d59-59bb-472e-8493-905661a00eba" SourceId="1" SourceUrl="http://localhost:9999/TestService/metadata?xsd=xsd2" />
<MetadataFile FileName="metadata1.xsd" MetadataType="Schema" ID="88452e87-d36d-4689-ace5-065cbf3e6156" SourceId="1" SourceUrl="http://localhost:9999/TestService/metadata?xsd=xsd1" />
<MetadataFile FileName="metadata2.xsd" MetadataType="Schema" ID="d2d2cd8c-2dc8-4f00-8310-3f2e38760d42" SourceId="1" SourceUrl="http://localhost:9999/TestService/metadata?xsd=xsd0" />
<MetadataFile FileName="metadata.wsdl" MetadataType="Wsdl" ID="ca974723-d890-475c-8654-18a6fc701521" SourceId="1" SourceUrl="http://localhost:9999/TestService/metadata?wsdl=wsdl0" />
</Metadata>
<Extensions>
<ExtensionFile FileName="configuration91.svcinfo" Name="configuration91.svcinfo" />
<ExtensionFile FileName="configuration.svcinfo" Name="configuration.svcinfo" />
</Extensions>
</ReferenceGroup>
但是我们的开发环境是不直接应用服务的,所以这个属性不知道哪里去设置
@啤酒草:
1、 “我又不希望在项目中直接 【引用服务】”
2、“是WCF中直接应用服务所生生的” ——你这里可能是笔误,你应该想说的是“是WCF中直接引用服务所生生的”
请问,你到底是想,还是不想“直接引用服务”?
@Launcher: 我不想直接应用服务 我上面没有表述清楚吧,我接着表述一下
ServiceContract:
[ServiceContract()] public interface ITestService { [OperationContract] IList<TestObject> Add(); }
Service:
public class TestService :ITestService { public IList<TestObject> Add() { List<TestObject> list = new List<TestObject>(); list.Add(new TestObject()); list.Add(new TestObject()); list.Add(new TestObject()); list.Add(new TestObject()); return list; } }
TestObject:
[System.Runtime.Serialization.DataContract()] public class TestObject { [System.Runtime.Serialization.DataMember()] public string AAA { get; set; } }
ServiceHost:
public class ERPServerHost : ServiceHost { public ERPServerHost(Type hostType,Type interFaceType,string serviceName):base(hostType, new Uri[]{new Uri(@"http://localhost:9999/TestService/")}) { var wsHttp = new BasicHttpBinding(BasicHttpSecurityMode.None); this.AddServiceEndpoint(interFaceType, wsHttp, ""); if (this.Description.Behaviors.Find<ServiceMetadataBehavior>() == null) { ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; behavior.HttpGetUrl = new Uri(@"http://localhost:9999/TestService/" + "metadata"); this.Description.Behaviors.Add(behavior); } ServiceDebugBehavior debug = new ServiceDebugBehavior(); debug.IncludeExceptionDetailInFaults = true; this.Description.Behaviors.Add(debug); this.Open(); } }
客户端有二种生成方式
第一种直接引用服务,然后再类型列表中选择 集合类型为 【List类型】,然后查看生成的代理类,发现XML上多了一段
<CollectionMappings> <CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" /> </CollectionMappings>
这个时候 生成的 ITestService接口的是这样的:
[System.Diagnostics.DebuggerStepThroughAttribute()] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")] public partial class TestServiceClient : System.ServiceModel.ClientBase<Client.ServiceReference1.ITestService>, Client.ServiceReference1.ITestService { public TestServiceClient() { } public TestServiceClient(string endpointConfigurationName) : base(endpointConfigurationName) { } public TestServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public TestServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public TestServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } public System.Collections.Generic.List<Modal.TestObject> Add() { return base.Channel.Add(); } }
返回值为 List<TestObject>
第二种方式为工作创建方法:
var wsHttp = new BasicHttpBinding(BasicHttpSecurityMode.None); ChannelFactory<T> channelFactory = new ChannelFactory<T>(wsHttp, "http://" + "localhost:9999" + "/" + url); return channelFactory.CreateChannel();
这个时候创建的接口 返回值 确实 TestObject[] 类型的定长数组。
求问:如何 采用工厂创建服务接口的方式 让返回值变为 List<TestObject>,既使用代码将
<CollectionMappings> <CollectionMapping TypeName="System.Collections.Generic.List`1" Category="List" /> </CollectionMappings>
@啤酒草: ChannelFactory<ITestService> channelFactory = new ChannelFactory<ITestService>()....
直接把服务器的 dll 引用进来使用就行了,完整实现,你可以看下 StockTrader .
@Launcher: 客服端去应用服务器端的DLL文件?好像不是这样的吧。
@啤酒草: 如果你还没有下载 StockTrader 项目学习过,那么请你学习完了后再发表你的结论。如果你都懒得去学习,仅凭感觉就说“好象不是这样吧”,那么我也无法再回答你的问题了。