1

私はこの問題について新しい質問を開くことにしました。インターネット上のどこにもこの問題についての正確な答えが見つからなかったので、おそらくこの質問を拡張しました。

protobuf-netを使用して、WCFクライアントとサービス間で交換されるメッセージをシリアル化/逆シリアル化したい。このサービスは、Windowsサービスで自己ホストされます。クライアントとサービスの両方がプログラムで構成され、に非常によく似たカスタムバインディングを使用しますwsHttpBinding。サービス参照コードは、VisualStudioの[サービス参照の追加]オプションを使用して生成されます。WCFサービスで使用されるORMはEntityFramework4であり、そのコードはEF 4.xPOCOGeneratorを使用して生成されます。私のサービス構成の詳細については、ここで始めた質問を参照してください(ここで、現在のシリアライザーについて説明しましたDataContractSerialzizer)。

カスタムDTOのリストを返す1つのサービス操作でprotobuf-netをテストしただけです。操作は次のとおりです(ここにコードをコピーして貼り付けただけです。英語ではなく、母国語で名前が付けられたフィールドがある可能性があります)。

    public static List<OsobaView> GetListOsobas()
    {
        Database DB = new Database(); // EF object context
        var retValue = DB.Baza.Osoba
                       .Select(x => new OsobaView
                       {
                           ID = x.ID,
                           Prezime = x.Prezime,
                           Ime = x.Ime,
                           Adresa = x.Adresa,
                           DatumRodjenja = x.DatumRodjenja,
                           JMBG = x.JMBG
                       });
        return retValue.ToList();
    }

OsobaViewクラスの定義は次のとおりです。

    [ProtoContract]
    public class OsobaView
    {
        [ProtoMember(1)]
        public int ID;
        [ProtoMember(2)]
        public string Prezime;
        [ProtoMember(3)]
        public string Ime;
        [ProtoMember(4)]
        public string Adresa;
        [ProtoMember(5)]
        public DateTime DatumRodjenja;
        [ProtoMember(6)]
        public string JMBG;
    }

ProtoContract「サービス参照の追加」を使用して参照コードを生成しているため、クライアントにsとメンバーを認識させるために、2つの回避策のいずれかを使用する必要がありました。

  • DTOの共有アセンブリを使用する(EFで生成されたPOCOをクライアントに渡すため、カスタムDTOを除いて、私の場合は理想的なソリューションではありません)
  • ProtoPartialMemberアプローチを使用

私はそれらの両方を使用し、 protobuf-netのv1v2の両方を使用しました。すべてのソリューションで同様の結果が得られ、クライアントがまったく逆シリアル化されていないと思われました。読む。

ProtoPartialMember私がこのアプローチを使用した場合を考えてみましょう。最初はv2を使用しました。使い方が大好きProtoOperationBehaviorです。呼び出されるサービス操作は次のとおりです。

    [ProtoBuf.ServiceModel.ProtoBehavior]
    public List<OsobaView> GetListOsobas()
    {
        return OsobaQueries.GetListOsobas();
    }

クライアント側でDataContractSerializerOperationBehavior必要ProtoOperationBehaviorなサービス操作を置き換える方法は次のとおりです。

    OperationDescription op = Service.Proxy.Endpoint.Contract.Operations.Find("GetListOsobas");
    if (op != null)
    {
        DataContractSerializerOperationBehavior dcsBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
        if (dcsBehavior != null)
            op.Behaviors.Remove(dcsBehavior);
        op.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoOperationBehavior(op));
    }

そしてもちろん、DTOの上記の回避策の実装は次のとおりです。

    [ProtoPartialMember(1, "ID")]
    [ProtoPartialMember(2, "Prezime")]
    [ProtoPartialMember(3, "Ime")]
    [ProtoPartialMember(4, "Adresa")]
    [ProtoPartialMember(5, "DatumRodjenja")]
    [ProtoPartialMember(6, "JMBG")]
    [ProtoContract]
    public partial class OsobaView
    {
    }

これで、クライアントからこのサービスオペレーションを呼び出すと、が取得されnullます。しかし、フィドラーは同意しません。応答ヘッダーには、次のように明確に記載されています。

    Content-Length: 1301963
    Content-Type: application/soap+xml; charset=utf-8

...そしてメッセージ本文:

    <s:Body>
      <GetListOsobasResponse xmlns="http://tempuri.org/">
        <proto>CkMIpHES .../* REALLY LONG RESPONSE */... IyMDAxOA==</proto>
      </GetListOsobasResponse>
    </s:Body>

それでは、 v1で試してみようと思いました。サービス面では、あまり変わっていません。v2 .DLLへの参照を削除し、v1.DLLへの参照に置き換えました。クライアント側では、サービス操作の動作に追加するコードを削除し、ProtoOperationBehavior代わりに次の行を追加する必要がありました。

    Service.Proxy.Endpoint.Behaviors
        .Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());

私はそれを起動し、操作を呼び出しましたが、今回は結果がありませんnull。今回は空白のフィールドのリストです。繰り返しになりますが、Fiddlerは以前と同じように言ったため、同意できませんでした。同じコンテンツの長さと同じメッセージ本文。

何が起きてる?

PS何か価値がある場合は、次のWCF構成を使用します。

    CustomBinding customBinding = new CustomBinding();
    customBinding.CloseTimeout = TimeSpan.FromMinutes(10);
    customBinding.OpenTimeout = TimeSpan.FromMinutes(10);
    customBinding.ReceiveTimeout = TimeSpan.FromMinutes(10);
    customBinding.SendTimeout = TimeSpan.FromMinutes(10);
    HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
    httpsBindingElement.AllowCookies = false;
    httpsBindingElement.BypassProxyOnLocal = false;
    httpsBindingElement.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
    httpsBindingElement.MaxBufferPoolSize = 20480000;
    httpsBindingElement.MaxBufferSize = 20480000;
    httpsBindingElement.MaxReceivedMessageSize = 20480000;
    httpsBindingElement.RequireClientCertificate = true;
    httpsBindingElement.UseDefaultWebProxy = true;
    TransportSecurityBindingElement transportSecurityElement = new TransportSecurityBindingElement();
    transportSecurityElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new UserNameSecurityTokenParameters());
    transportSecurityElement.EndpointSupportingTokenParameters.SetKeyDerivation(false);
    TransactionFlowBindingElement transactionFlowElement = new TransactionFlowBindingElement();
    TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement();
    textMessageEncoding.MaxReadPoolSize = 20480000;
    textMessageEncoding.MaxWritePoolSize = 20480000;
    textMessageEncoding.ReaderQuotas = XmlDictionaryReaderQuotas.Max;
    ReliableSessionBindingElement reliableSessionElement = new ReliableSessionBindingElement();
    reliableSessionElement.ReliableMessagingVersion = ReliableMessagingVersion.WSReliableMessagingFebruary2005;
    customBinding.Elements.Add(transportSecurityElement);
    customBinding.Elements.Add(transactionFlowElement);
    customBinding.Elements.Add(textMessageEncoding);
    customBinding.Elements.Add(reliableSessionElement);
    customBinding.Elements.Add(httpsBindingElement);

    EndpointAddress endpoint = new EndpointAddress(new Uri(ServiceAddress));
    Service.Proxy = new BazaService.BazaClient(customBinding, endpoint);
    Service.Proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, CertificateSubject);
    CustomBehavior behavior = Service.Proxy.Endpoint.Behaviors.Find<CustomBehavior>();
    if (behavior == null)
    {
        Service.Proxy.Endpoint.Behaviors.Add(new CustomBehavior()); // message inspector
    }
    Service.Proxy.Endpoint.Contract.Behaviors.Add(new CyclicReferencesAwareContractBehavior(true));
    Service.Proxy.Endpoint.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());

    /* code used for protobuf-net v2

    OperationDescription op = Service.Proxy.Endpoint.Contract.Operations.Find("GetListOsobas");
    if (op != null)
    {
        DataContractSerializerOperationBehavior dcsBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>();
        if (dcsBehavior != null)
            op.Behaviors.Remove(dcsBehavior);
        op.Behaviors.Add(new ProtoBuf.ServiceModel.ProtoOperationBehavior(op));
    } */

    Service.Proxy.ClientCredentials.UserName.UserName = LogOn.UserName;
    Service.Proxy.ClientCredentials.UserName.Password = LogOn.Password;
    Service.Proxy.Open();

編集

さらに多くの情報を提供するために、私はそこに書かれていることを読みましたが、それは役に立ちませんでした。Visual Studioによって生成されたサービス参照を削除し、独自に作成してサービスコントラクト全体を共有しましたが、何も変更されていません。

4

1 に答える 1

1

もう少し集中した後、ソリューションを最初からやり直すことにしました。POCOを使用してEDMX用に1つのクラスライブラリを作成しました。1つはとs用で、ServiceContractもうDataContract1つは実際のWCFサービス実装用です。ServiceContract次に、とs、およびPOCOを含む2つのライブラリをDataContractWCFクライアントと共有して再試行したところ、以前と同じ結果が得られました。シリアル化にprotobuf-netを使用しない他の操作を試した後、最初の操作と同じように動作し、空のフィールド(!)が生成されたことが判明しました。

.datasource問題は、アセンブリ共有手法を使用することを決定した後、リファクタリング中にWCFクライアントのファイルをねじ込んだことです。したがって、これは典型的なPEBKACでしたが、適切に実行すればもちろん正常に機能します。protobuf-netMarc Gravellとの素晴らしい仕事です!

于 2012-04-10T08:19:36.170 に答える