3

わかりました、特定の問題を解決するのに非常に苦労しています。サービスを介したオブジェクトの転送。概念的には、それは理にかなっている...と思いますか?私が読んだことから、ジェネリックは明示的に定義されていない限りシリアル化できません。

ですから、私の例を挙げたいと思います。まったく仕事に行けない状況です。つまり、他にも苦労されている方はいらっしゃると思います。コードを提供できるかどうかを支援する場合。それは機能し、それを説明します。そうすれば、問題を完全に理解できます。これは、Windows Communication Foundation を理解するのに役立ちます。

目標は、単純に 5 つのフィールドを持つクライアント アプリケーションです。サーバーに「投稿」します。

  • ファーストネーム
  • 苗字
  • 電子メールアドレス
  • 電話番号
  • サイトアドレス

それほど複雑ではありません。

これが私が行ったことです。WCF を学ぶために、SOA ベースのアプリケーションにできる限り OOP プリンシパルに近いものを含めました。そのようにして、コードの再利用性を提供します。

モデル/データ契約:

#region Using Reference...

using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using System.Linq;
using System;

#endregion

namespace _2Do.Model.Customer
{

    [DataContract(IsReference = true)]
    public class Person
    {

        #region Declared Variable.

        string first;
        string last;
        string email;
        string phone;
        string site;

        #endregion

        #region Constructor:

        Person()
        {

            // Empty Constructor.

        }

        #endregion

        #region Data Member Properties:

        [DataMember()]
        public string First
        {

            get { return first; }
            set { first = value; }

        }

        [DataMember()]
        public string Last
        {

            get { return last; }
            set { last = value; }

        }

        [DataMember()]
        public string Email
        {

            get { return email; }
            set { email = value; }

        }

        [DataMember()]
        public string Phone
        {

            get { return phone; }
            set { phone = value; }

        }

        [DataMember()]
        public string Site
        {

            get { return site; }
            set { site = value; }

        }

        #endregion

    }

}

つまり、クライアントのメタデータを介して公開する必要があるオブジェクトです。だから私はこれを試みたサービスインターフェースのために:

#region Using Reference...

using System.Collections.Generic;
using System.Threading.Tasks;
using System.ServiceModel;
using _2Do.Model.Customer;
using System.Text;
using System.Linq;
using System;

#endregion

namespace _2Do.Contract.Customer
{

    [ServiceContract (Namespace = "https://_2Do") ]
    public interface IPerson
    {

        [OperationContract()]
        Person SetCustomer(Dictionary<Guid, Person> info);

    }

}

したがって、上記が目標です。Person オブジェクトを転送します。ディクショナリに格納されます。その他の注意事項; 参照によって値を渡す実装は、シリアル化に役立つと思いました。データがメモリに保存されると、私は考えました。処理するための明示的な方法論が含まれます。それは私の側で間違っていますか?

それが私のDataContractServiceContractです。

この時点での実装は次のようになります。

#region Using Reference...

using System.Collections.Generic;
using System.Threading.Tasks;
using _2Do.Contract.Customer;
using System.ServiceModel;
using _2Do.Model.Customer;
using System.Text;
using System.Linq;
using System;

#endregion

namespace _2Do.Service.Customer
{

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class PersonService : IPerson
    {

        #region Constructor:

        PersonService()
        {

            // Empty Constructor.

        }

        #endregion

        #region Implement Interface:

        Person SetCustomer(Dictionary<Guid, Person> info)
        {

            // Receive an error that indicates; best overload method.
            // Contains invalid arguments.

        }

        #endregion

    }

}

次に、アプリケーションをホストする別のプロジェクトを作成しました。空のテキスト ファイルを作成し、名前をPersonService.svc.

次に、次のようにします<%@ ServiceHost Service = "_2Do.Service.Customer.PersonService" %>

適切な名前空間を指す必要があります。これPersonServiceにはweb.config、Internet Information System でホストするための最低限の構成を含むファイルがあります。これにより、アドレス、バインディング、および契約の定義を回避できると思いました。IISがすべてをやってくれるので。

ClientProxy次に、クラスを作成しました。ほとんどのミラーが含まれていますDataContract。次に、実行する実際のクライアント アプリケーションを作成しました。

PersonProxy p = new PersonProxy();
p.First = txtFirst.Text;
p.Last = txtLast.Text;
p.Email = txtEmail.Text;
p.Phone = txtPhone.Text;
p.Site = txtSite.Text;
Dictionary<Guid, Person> i = new Dictionary<Guid, Person>();
i.Add(Guid.NewGuid(), p);

私はこれらのプロジェクトを持っています:

  • モデル --> DataContract
  • 契約 --> ServiceContract
  • サービス --> インターフェイスの実装
  • ホスト --> ストア サービス / サービス
  • ClientProxy --> インターフェイスの実装
  • クライアント --> ClientProxy が継承する実際の値にリンクされています。

これは、クライアントでそれを消費する方法です。どこでこれを台無しにしたのかわかりません。仕事のプロジェクトで WCF を学ぶ必要があるので、WCF を理解したいと思っています。しかし、この問題を解決できないように見えるので、私はとてもイライラし、とても愚かだと感じています.

チュートリアルに従えばうまくいきます。しかし、元の実装に戻ると失敗します。何がどこで間違っているのかわかりません。手を握っていただければ幸いです。しかし、順を追って説明していただければ幸いです。だから私は自分の過ちから学び、実際に改善することができます。

サーバーに変数を保存して送信することはできません。この時点では理由がわかりません。

4

2 に答える 2

2

コードが機能しない理由はまだわかりません。おそらく、IIS でのホスティングについて十分に理解していないのでしょう。ただし、以下は、私が思いつく最も単純な Web サービス + クライアントの完全に機能するサンプルです。問題を見つけて対処するのに役立つことを願っています。

まず、プロジェクト構造: 1 つのクラス ライブラリ プロジェクトのコントラクト、コンソール アプリのサービスとホスト、別のコンソール アプリのクライアント。

データ契約:

[DataContract]
public class Person
{
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string Email { get; set; }
}

サービス契約:

[ServiceContract]
public interface IPerson
{
    [OperationContract]
    Person SetCustomer(Dictionary<Guid, Person> info);
}

サービス:

public class PersonService : IPerson
{
    public Person SetCustomer(Dictionary<Guid, Person> info)
    {
        foreach (var person in info.Values)
        {
            Console.WriteLine("Name: {0} | Email: {1}", person.Name, person.Email);
        }

        var p = new Person { Name = "John Doe", Email = "John@Doe.com" };
        return p;
    }
}

サービス ホスト (ホスト プロジェクトの Program.cs 内):

static void Main(string[] args)
{
    using (ServiceHost host = new ServiceHost(typeof(PersonService), new Uri("http://localhost:8080")))
    {
        host.Open();

        Console.WriteLine("Ready!");
        Console.ReadKey(true);

        host.Close();
    }
}

最後に、クライアント (独自のプロジェクトの Program.cs 内):

static void Main(string[] args)
{
    var binding = new BasicHttpBinding();
    var endpoint = new EndpointAddress("http://localhost:8080/");
    using (var factory = new ChannelFactory<IPerson>(binding, endpoint))
    {
        var request = new Dictionary<Guid, Person>();
        request[Guid.NewGuid()] = new Person { Name = "Bob", Email = "Bob@abc.com" };

        var client = factory.CreateChannel();
        var result = client.SetCustomer(request);

        Console.WriteLine("Name: {0} | Email: {1}", result.Name, result.Email);
        factory.Close();
    }
    Console.ReadKey(true);
}

お役に立てれば!

于 2012-12-28T03:20:44.847 に答える
1

サービス コントラクトのパラメーターとして Dictionary が本当に必要ですか? シンプルにしてください - 代わりにリストを使用してください。私の提案は次のとおりです。

1) Guid プロパティを Person データ コントラクトに追加します。

[DataContract(IsReference = true)]
public class Person
{
    #region Constructor:

    public Person()
    {
        // Empty Constructor.
    }

    #endregion

    #region Data Member Properties:

    [DataMember]
    public Guid Guid { get; set; }

    [DataMember]
    public string First { get; set; }

    [DataMember]
    public string Last { get; set; }

    [DataMember]
    public string Email { get; set; }

    [DataMember]
    public string Phone { get; set; }

    [DataMember]
    public string Site { get; set; }

    #endregion
}

2) リストを使用するようにサービス コントラクトを変更します。

[ServiceContract (Namespace = "https://_2Do") ]
public interface IPerson
{
    [OperationContract()]
    Person SetCustomer(List<Person> info);
}

3) クライアント コードは次のようになります。

PersonProxy p = new PersonProxy();
p.Guid = Guid.NewGuid();
p.First = txtFirst.Text;
p.Last = txtLast.Text;
p.Email = txtEmail.Text;
p.Phone = txtPhone.Text;
p.Site = txtSite.Text;

var list = new List<Person>();
list.Add(p);

最後に、サービス コードで Dictionary が本当に必要な場合は、メソッドToDictionaryを使用して List を簡単に変換できます。

于 2012-12-28T00:16:42.363 に答える