WCF 服务返回的对象层次结构与预期不同

发布于 2024-08-28 18:59:25 字数 3119 浏览 1 评论 0原文

我的理解可能是错误的,但我认为一旦应用了正确的属性,DataContractSerializer 就会将完全合格的实例渲染回调用者。

代码运行并且对象返回。但奇怪的是,一旦我查看返回的对象,我注意到命名空间消失了,并且通过(Web 应用程序)服务引用公开的对象层次结构似乎变得“扁平”(不知何故)。现在,我希望通过 Web 服务实现这一点……但不是通过 WCF。当然,我对WCF能做什么的理解可能是错误的。

...请记住我仍在尝试这一切。

所以我的问题是...

问:我可以在 WCF 服务中执行某些操作来强制命名空间通过(服务参考)数据客户端代理渲染?

问:或者,我(仅仅是)错误地使用了该服务吗?

问:这可能吗?

服务代码看起来像…

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class DataService : IFishData
{
    public C1FE GetC1FE(Int32 key)
    {
         //… more stuff here …
    }
    public Project GetProject(Int32 key)
    {
      //… more stuff here …
    }
}

[ServiceContract]
[ServiceKnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[ServiceKnownType(typeof(wcfFISH.StateManagement.Project.New))]
public interface IFishData
{
     [OperationContract]
     C1FE GetC1FE(Int32 key);

     [OperationContract]
     Project GetProject(Int32 key);
}

[DataContract]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class Project
{
      [DataMember]
      public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }

      //… more stuff here …
}

[DataContract]
KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class C1FE
{
      [DataMember]
      public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }

   //… more stuff here …
}

[DataContract(Namespace = "wcfFISH.StateManagement")]
[KnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[KnownType(typeof(wcfFISH.StateManagement.Project.New))]
public abstract class ObjectState
{
      //… more stuff here …
}

[DataContract(Namespace = "wcfFISH.StateManagement.C1FE", Name="New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
      //… more stuff here …
}

[DataContract(Namespace = "wcfFISH.StateManagement.Project", Name = "New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
      //… more stuff here …
}

Web 应用程序代码看起来像…

public partial class Fish_Invite : BaseForm
{
    protected void btnTest_Click(object sender, EventArgs e)
    {
       Project project = new Project();
       project.Get(base.ProjectKey, base.AsOf);

       mappers.Project mapProject = new mappers.Project();

       srFish.Project fishProject = new srFish.Project();
       srFish.FishDataClient fishService = new srFish.FishDataClient();

       mapProject.MapTo(project, fishProject);

       fishProject = fishService.AddProject(fishProject, IUser.UserName);

       project = null;
    }
}

如果我不清楚…

问题的出现是因为命名空间我期望看到(返回)与实际返回的不同。

fishProject.ObjectState 应类似于...

srFish.StateManagement.Project.New

fishC1FE.ObjectState 应类似于...

srFish.StateManagement.C1FE.New

fishProject .ObjectState 实际上看起来像...

srFish.New1

fishC1FE.ObjectState 实际上看起来像...

srFish.New

My understanding may be wrong, but I thought once you applied the correct attributes the DataContractSerializer would render fully-qualified instances back to the caller.

The code runs and the objects return. But oddly enough, once I look at the returned objects I noticed the namespacing disappeared and the object-hierarchy being exposed through the (web applications) service reference seems to become "flat" (somehow). Now, I expect this from a web-service…but not through WCF. Of course, my understanding of what WCF can do may be wrong.

...please keep in mind I'm still experimenting with all this.

So my questions are…

Q: Can I do something within the WCF Service to force the namespacing to render through the (service reference) data client proxy?

Q: Or perhaps, am I (merely) consuming the service incorrectly?

Q: Is this even possible?

The service code looks like…

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class DataService : IFishData
{
    public C1FE GetC1FE(Int32 key)
    {
         //… more stuff here …
    }
    public Project GetProject(Int32 key)
    {
      //… more stuff here …
    }
}

[ServiceContract]
[ServiceKnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[ServiceKnownType(typeof(wcfFISH.StateManagement.Project.New))]
public interface IFishData
{
     [OperationContract]
     C1FE GetC1FE(Int32 key);

     [OperationContract]
     Project GetProject(Int32 key);
}

[DataContract]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class Project
{
      [DataMember]
      public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }

      //… more stuff here …
}

[DataContract]
KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class C1FE
{
      [DataMember]
      public wcfFISH.StateManagement.ObjectState ObjectState { get; set; }

   //… more stuff here …
}

[DataContract(Namespace = "wcfFISH.StateManagement")]
[KnownType(typeof(wcfFISH.StateManagement.C1FE.New))]
[KnownType(typeof(wcfFISH.StateManagement.Project.New))]
public abstract class ObjectState
{
      //… more stuff here …
}

[DataContract(Namespace = "wcfFISH.StateManagement.C1FE", Name="New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
      //… more stuff here …
}

[DataContract(Namespace = "wcfFISH.StateManagement.Project", Name = "New")]
[KnownType(typeof(wcfFISH.StateManagement.ObjectState))]
public class New : ObjectState
{
      //… more stuff here …
}

The web application code looks like…

public partial class Fish_Invite : BaseForm
{
    protected void btnTest_Click(object sender, EventArgs e)
    {
       Project project = new Project();
       project.Get(base.ProjectKey, base.AsOf);

       mappers.Project mapProject = new mappers.Project();

       srFish.Project fishProject = new srFish.Project();
       srFish.FishDataClient fishService = new srFish.FishDataClient();

       mapProject.MapTo(project, fishProject);

       fishProject = fishService.AddProject(fishProject, IUser.UserName);

       project = null;
    }
}

In case I’m not being clear…

The issue arises in that the namespacing I expect to see (returned) is different from what is actually returned.

fishProject.ObjectState SHOULD look like...

srFish.StateManagement.Project.New

fishC1FE.ObjectState SHOULD look like...

srFish.StateManagement.C1FE.New

fishProject.ObjectState ACTUALLY looks like...

srFish.New1

fishC1FE.ObjectState ACTUALLY looks like...

srFish.New

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

溇涏 2024-09-04 18:59:25

好的 - WCF 服务的默认行为是这样的:

  • 您就可以在服务器上定义服务契约、操作和数据契约(例如,在命名空间“Server.MyService”中)
  • 一旦服务启动并运行, ,在客户端上创建一个执行此操作时,服务引用
  • ,Visual Studio 或 svcutil.exe 所做的就是
  • 根据该元数据询问该服务的元数据(服务方法和数据的描述),生成客户端代理(命名空间“Client.MyService”),它包含服务契约(方法)和数据契约的副本

重要提示:它包含这些东西的副本!它们看起来相同,并且在线上序列化为相同的 XML 格式 - 但它们是不同的 - 在不同的命名空间中,最值得注意的是。

这就是 WCF 的本质 - 您所做的就是在客户端和服务器之间交换序列化消息 - 所有来回的都是文本消息。仅此而已 - 没有对象引用,没有远程对象 - 没有类似的东西。把它从你的脑海中扔掉吧! :-)

如果您控制线路的两端,这可能会很痛苦 - 如果您需要更改任何内容,则必须在服务器端进行更改,更新客户端引用等等。

因此,如果您控制线路的两端 - 服务器和客户端 - 并且它们都是基于 .NET 的,您可以执行以下操作:

  • 将您的服务契约和数据契约(仅契约 - 无实现!)放入 从您的服务实现中分离出一个单独的程序集
  • ,引用该合同程序集
  • 将合同程序集复制到您的客户端,并在您的客户端项目中引用它

现在,如果您添加服务引用,默认情况下,添加服务引用 Visual Studio 中的函数将重用引用程序集中的现有类型 - 因此,如果您引用了常见的“合同”程序集,这些类型(以其全部荣耀,包括其命名空间)将被重用 - 不会创建额外的副本。

这样,您就可以创建一个供服务器端代码和客户端使用的单个共享合约程序集,并且不必处理任何重复的数据结构。但再次强调:只有当您控制线路的两端并且两者都是 .NET 时,这才有效

OK - default behavior for a WCF Service is this:

  • you define your service contracts, operations, and data contract on the server (e.g. in namespace "Server.MyService")
  • once the service is up and running, on your client, you create a service reference
  • when doing so, what Visual Studio or svcutil.exe do, is interrogate that service for its metadata (description of service methods and data)
  • based on that metadata, the client side proxy is generated (namespace "Client.MyService") and it contains replicas of the service contract (the methods) and the data contract

Important: it contains replicas of those things! They look the same, and they serialize into the same XML format on the wire - but they are different - in different namespaces, most notably.

This is the very nature of WCF - all you do is exchange serialized messages between client and server - all that goes back and forth are textual messages. Nothing more - no object references, no remote object - nothing like that. Toss that out of your mind! :-)

If you control both ends of the wire, this can be a pain - if you need to change anything, you have to change it on the server side, update the client references and so forth.

So if you control both ends of the wire - both the server and the client - and they're both .NET based, you can do the following:

  • put your service contracts and your data contracts (only the contracts - no implementations!) into a separate assembly
  • from your service implementation, reference that contracts assembly
  • copy the contracts assembly to your client, and also reference it in your client project

Now, if you add the service reference, by default, the Add Service Reference function in Visual Studio will reuse existing types in referenced assemblies - so if you have referenced your common "Contracts" assembly, those types (in their full glory, including their namespace) will be reused - no additional copies will be created.

That way, you can create a single, shared contracts assembly used by both the server side code, as well as your client, and you don't have to mess with any duplication of data structures. But again: that only works if you are in control of both ends of the wire, and both are .NET

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文