代码之家  ›  专栏  ›  技术社区  ›  Prisoner ZERO

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

  •  2
  • Prisoner ZERO  · 技术社区  · 16 年前

    我的理解可能是错误的,但是我认为一旦应用了正确的属性,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实际上看起来…

    SrFix.NeW1

    fishc1fe.objectState实际上看起来…

    新鱼

    1 回复  |  直到 14 年前
        1
  •  4
  •   marc_s MisterSmith    16 年前

    确定-WCF服务的默认行为是:

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

    要点:它包含 复制品 那些东西!它们看起来是一样的,并且在线路上序列化为相同的XML格式——但是它们是不同的——在不同的名称空间中,最明显的是。

    这就是WCF的本质-你所做的就是交换 序列化消息 在客户机和服务器之间-所有来回的都是文本消息。没有更多的东西-没有对象引用,没有远程对象-没有那样的东西。把它扔掉!-)

    如果你控制了线路的两端,这可能会很痛苦——如果你需要改变任何东西,你必须在服务器端改变它,更新客户端引用等等。

    因此,如果您控制连接的两端(服务器和客户端),并且它们都基于.NET,则可以执行以下操作:

    • 把你的服务契约和数据契约(只有契约-没有实现!)变成一个独立的组件
    • 从服务实现中,引用协定程序集
    • 将合同程序集复制到客户端,并在客户端项目中引用它

    现在,如果添加服务引用,默认情况下, Add Service Reference visual studio中的函数将重用被引用程序集中的现有类型-因此,如果您已引用了公共“契约”程序集,则将重用这些类型(在其全部荣耀中,包括其命名空间)-不会创建其他副本。

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